import path from 'path';
import debug from 'debug';

// @flow

/*::
type Node = {
  type: string,
  fullpath: string,
  basename: string,
  metadata: Object, // mode, oid
  parent?: Node,
  children: Array<Node>
}
*/

/** @ignore */
function flatFileListToDirectoryStructure(files /*: Array<{path: string}> */
) /*: Node|void */{
  const inodes /*: Map<string, Node> */ = new Map();
  const mkdir = function (name) /*: Node|void */{
    if (!inodes.has(name)) {
      let dir /*: Node */ = {
        type: 'tree',
        fullpath: name,
        basename: path.basename(name),
        metadata: {},
        children: []
      };
      inodes.set(name, dir);
      // This recursively generates any missing parent folders.
      // We do it after we've added the inode to the set so that
      // we don't recurse infinitely trying to create the root '.' dirname.
      dir.parent = mkdir(path.dirname(name));
      if (dir.parent && dir.parent !== dir) dir.parent.children.push(dir);
    }
    return inodes.get(name);
  };

  const mkfile = function (name, metadata) /*: Node|void */{
    if (!inodes.has(name)) {
      let file /*: Node */ = {
        type: 'blob',
        fullpath: name,
        basename: path.basename(name),
        metadata: metadata,
        // This recursively generates any missing parent folders.
        parent: mkdir(path.dirname(name)),
        children: []
      };
      if (file.parent) file.parent.children.push(file);
      inodes.set(name, file);
    }
    return inodes.get(name);
  };

  mkdir('.');
  for (let file of files) {
    mkfile(file.path, file);
  }
  return inodes.get('.');
}

/** @ignore */
async function sleep(ms) {
  return new Promise((resolve, reject) => setTimeout(resolve, ms));
}

var name = "isomorphic-git";
var version = "0.0.0-development";
var description = "A pure JavaScript implementation of git for node and browsers!";
var typings = "./src/index.d.ts";
var main = "dist/for-node/isomorphic-git/";
var browser = { "isomorphic-git": "./dist/bundle.umd.min.js", "isomorphic-git/internal-apis": "./dist/internal.umd.min.js" };
var module$1 = "dist/for-future/";
var unpkg = "dist/bundle.umd.min.js";
var bin = { "isogit": "./cli.js" };
var engines = { "node": ">=7.6.0" };
var scripts = { "start": "nps", "format": "nps format", "build": "nps build", "test": "nps test", "precommit": "ban", "prepush": "nps lint", "semantic-release": "semantic-release", "travis-deploy-once": "travis-deploy-once" };
var repository = { "type": "git", "url": "https://github.com/isomorphic-git/isomorphic-git.git" };
var keywords = ["git", "isomorphic"];
var author = "William Hilton <wmhilton@gmail.com>";
var license = "MIT";
var bugs = { "url": "https://github.com/isomorphic-git/isomorphic-git/issues" };
var homepage = "https://isomorphic-git.github.io/";
var files = ["dist", "cli.js", "src/index.d.ts"];
var dependencies = { "async-lock": "^1.1.0", "babel-runtime": "^6.26.0", "buffer": "^5.0.8", "buffercursor": "0.0.12", "crc": "^3.5.0", "debug": "^3.1.0", "diff-lines": "^1.1.0", "git-apply-delta": "0.0.7", "git-list-pack": "0.0.10", "ignore": "^3.3.7", "lodash.sortby": "^4.7.0", "marky": "^1.2.0", "minimisted": "^2.0.0", "pad": "^2.0.3", "pako": "^1.0.6", "pify": "^3.0.0", "sha.js": "^2.4.9", "shasum": "^1.0.2", "simple-concat": "^1.0.0", "simple-get": "^2.7.0", "split2": "^2.2.0", "stream-source": "^0.3.5", "through2": "^2.0.3" };
var devDependencies = { "@types/node": "^9.4.7", "all-contributors-cli": "^4.11.1", "babel-plugin-external-helpers": "^6.22.0", "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", "babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-plugin-transform-runtime": "^6.23.0", "babel-preset-env": "^1.6.1", "babel-preset-flow": "^6.23.0", "ban-sensitive-files": "^1.9.2", "browserfs": "^2.0.0", "browserify": "^16.0.0", "browserify-shim": "^3.8.14", "buffer-to-stream": "^1.0.0", "bundlesize": "^0.17.0", "cross-env": "^5.1.3", "envify": "^4.1.0", "fetch-mock": "^6.0.1", "husky": "^0.14.3", "jasmine": "^3.0.0", "jasmine-console-reporter": "^2.0.1", "jasmine-core": "^3.0.0", "jest-fixtures": "^0.6.0", "karma": "^2.0.0", "karma-browserify": "^5.1.3", "karma-chrome-launcher": "^2.2.0", "karma-firefox-launcher": "^1.1.0", "karma-git-http-server-middleware": "^1.0.0", "karma-jasmine": "^1.1.1", "karma-sauce-launcher": "^1.2.0", "karma-verbose-reporter": "0.0.6", "nock": "^9.2.3", "nps": "^5.7.1", "nps-utils": "^1.5.0", "openpgp": "^2.6.1", "parse-header-stream": "^1.1.1", "prettier-standard": "^8.0.0", "pretty-format": "^22.1.0", "rollup": "^0.57.1", "rollup-plugin-babel": "^3.0.3", "rollup-plugin-json": "^2.3.0", "standard": "^11.0.0", "typescript": "^2.7.2", "uglify-es": "^3.3.4" };
var optionalDependencies = { "codecov": "^3.0.0", "jest": "^22.0.4", "semantic-release": "^15.0.0", "travis-deploy-once": "^4.3.1" };
var browserify = { "transform": ["browserify-shim"] };
var jest = { "testRegex": "/__tests__/[^\\/]+\\.js", "moduleNameMapper": { "^isomorphic-git$": "<rootDir>/src", "^isomorphic-git/(.+)$": "<rootDir>/src/$1" }, "coveragePathIgnorePatterns": ["<rootDir>/node_modules/", "<rootDir>/__tests__/__helpers__"], "testEnvironment": "node" };
var bundlesize = [{ "path": "./dist/bundle.umd.min.js" }];
var _package = {
	name: name,
	version: version,
	description: description,
	typings: typings,
	main: main,
	browser: browser,
	module: module$1,
	unpkg: unpkg,
	bin: bin,
	engines: engines,
	scripts: scripts,
	repository: repository,
	keywords: keywords,
	author: author,
	license: license,
	bugs: bugs,
	homepage: homepage,
	files: files,
	dependencies: dependencies,
	devDependencies: devDependencies,
	optionalDependencies: optionalDependencies,
	browserify: browserify,
	jest: jest,
	bundlesize: bundlesize,
	"browserify-shim": { "fs": "global:fs" }
};

var _package$1 = /*#__PURE__*/Object.freeze({
  name: name,
  version: version,
  description: description,
  typings: typings,
  main: main,
  browser: browser,
  module: module$1,
  unpkg: unpkg,
  bin: bin,
  engines: engines,
  scripts: scripts,
  repository: repository,
  keywords: keywords,
  author: author,
  license: license,
  bugs: bugs,
  homepage: homepage,
  files: files,
  dependencies: dependencies,
  devDependencies: devDependencies,
  optionalDependencies: optionalDependencies,
  browserify: browserify,
  jest: jest,
  bundlesize: bundlesize,
  default: _package
});

/**
 *
 * Use with {@link push} and {@link fetch} to set Basic Authentication headers.
 * This for is for *actual* OAuth2 tokens (not "personal access tokens").
 * Unfortunately, all the major git hosting companies have chosen different conventions!
 * Lucky for you, I already looked up and codified it for you.
 *
 * - oauth2('github', token) - Github uses `token` as the username, and 'x-oauth-basic' as the password.
 * - oauth2('bitbucket', token) - Bitbucket uses 'x-token-auth' as the username, and `token` as the password.
 * - oauth2('gitlab', token) - Gitlab uses 'oauth2' as the username, and `token` as the password.
 *
 * I will gladly accept pull requests for more companies' conventions.
 *
 * @param {string} company
 * @param {string} token
 * @returns {{username: string, password: string}}
 *
 */
function oauth2(company, token) {
  switch (company) {
    case 'github':
      return {
        username: token,
        password: 'x-oauth-basic'
      };
    case 'bitbucket':
      return {
        username: 'x-token-auth',
        password: token
      };
    case 'gitlab':
      return {
        username: 'oauth2',
        password: token
      };
    default:
      throw new Error(`I don't know how ${company} expects its Basic Auth headers to be formatted for OAuth2 usage. If you do, you can use the regular '.auth(username, password)' to set the basic auth header yourself.`);
  }
}

/**
 *
 * Use with {@link push} and {@link fetch} to set Basic Authentication headers.
 * This works for basic username / password auth, or the newer username / token auth
 * that is often required if 2FA is enabled.
 *
 * Authentication is normally required for pushing to a git repository.
 * It may also be required to clone or fetch from a private repository.
 * Git does all its authentication using HTTPS Basic Authentication.
 * Usually this is straightforward, but there are some things to watch out for.
 *
 * If you have two-factor authentication (2FA) enabled on your account, you
 * probably cannot push or pull using your regular username and password.
 * Instead, you may have to create a Personal Access Token (or an App
 * Password in Bitbucket lingo) and use that to authenticate.
 *
 * @param {string} username
 * @param {string} password
 * @returns {{username: string, password: string}}
 *
 * @example
 * let {username, password} = auth('username', 'password')
 *
 * // a one-argument version is also supported
 * let {username, password} = auth('username:password')
 *
 * // Personal Access Token Authentication
 * // (note Bitbucket calls theirs App Passwords instead for some reason)
 * let {username, password} = auth('username', 'personal access token')
 * let {username, password} = auth('username', 'app password')
 * let {username, password} = auth('personal access token') // Github (only) lets you leave out the username
 */
function auth(username, password) {
  // Allow specifying it as one argument (mostly for CLI inputability)
  if (password === undefined) {
    let i = username.indexOf(':');
    if (i > -1) {
      password = username.slice(i + 1);
      username = username.slice(0, i);
    } else {
      password = ''; // Enables the .auth(GITHUB_TOKEN) no-username shorthand
    }
  }
  return { username, password };
}

const log = debug('isomorphic-git');

log.log = console.log.bind(console);

export { flatFileListToDirectoryStructure, sleep, _package$1 as pkg, oauth2, auth, log };
