import * as fs from 'fs';
import * as path from 'path';
import * as tsickle from 'tsickle';
import * as ts from 'typescript';

import {FileLoader, isNonHermeticInput} from './file_cache';
import * as perfTrace from './perf_trace';
import {BazelOptions} from './tsconfig';

export type ModuleResolver =
    (moduleName: string, containingFile: string,
     compilerOptions: ts.CompilerOptions, host: ts.ModuleResolutionHost) =>
        ts.ResolvedModuleWithFailedLookupLocations;

/**
 * Narrows down the type of some properties from non-optional to required, so
 * that we do not need to check presence before each access.
 */
export interface BazelTsOptions extends ts.CompilerOptions {
  rootDirs: string[];
  rootDir: string;
  outDir: string;
}

export function narrowTsOptions(options: ts.CompilerOptions): BazelTsOptions {
  if (!options.rootDirs)
    throw new Error(`compilerOptions.rootDirs should be set by tsconfig.bzl`);
  if (!options.rootDir)
    throw new Error(`compilerOptions.rootDirs should be set by tsconfig.bzl`);
  if (!options.outDir)
    throw new Error(`compilerOptions.rootDirs should be set by tsconfig.bzl`);
  return options as BazelTsOptions;
}

/**
 * CompilerHost that knows how to cache parsed files to improve compile times.
 */
export class CompilerHost implements ts.CompilerHost, tsickle.TsickleHost {
  /**
   * Lookup table to answer file stat's without looking on disk.
   */
  private knownFiles = new Set<string>();

  /**
   * rootDirs relative to the rootDir, eg "bazel-out/local-fastbuild/bin"
   */
  private relativeRoots: string[];

  getCancelationToken?: () => ts.CancellationToken;

  googmodule: boolean;
  es5Mode: boolean;
  prelude: string;
  untyped: boolean;
  typeBlackListPaths: Set<string>;
  transformDecorators: boolean;
  transformTypesToClosure: boolean;
  addDtsClutzAliases: boolean;
  options: BazelTsOptions;
  host: ts.ModuleResolutionHost = this;

  constructor(
      public inputFiles: string[], options: ts.CompilerOptions,
      readonly bazelOpts: BazelOptions, private delegate: ts.CompilerHost,
      private fileLoader: FileLoader,
      private readonly allowNonHermeticReads: boolean,
      private moduleResolver: ModuleResolver = ts.resolveModuleName) {
    this.options = narrowTsOptions(options);
    this.relativeRoots =
        this.options.rootDirs.map(r => path.relative(this.options.rootDir, r));
    inputFiles.forEach((f) => {
      this.knownFiles.add(f);
    });

    // getCancelationToken is an optional method on the delegate. If we
    // unconditionally implement the method, we will be forced to return null,
    // in the absense of the delegate method. That won't match the return type.
    // Instead, we optionally set a function to a field with the same name.
    if (delegate && delegate.getCancellationToken) {
      this.getCancelationToken = delegate.getCancellationToken.bind(delegate);
    }

    this.googmodule = bazelOpts.googmodule;
    this.es5Mode = bazelOpts.es5Mode;
    this.prelude = bazelOpts.prelude;
    this.untyped = bazelOpts.untyped;
    this.typeBlackListPaths = new Set(bazelOpts.typeBlackListPaths);
    this.transformDecorators = bazelOpts.tsickle;
    this.transformTypesToClosure = bazelOpts.tsickle;
    this.addDtsClutzAliases = bazelOpts.addDtsClutzAliases;
  }

  /**
   * Workaround https://github.com/Microsoft/TypeScript/issues/8245
   * We use the `rootDirs` property both for module resolution,
   * and *also* to flatten the structure of the output directory
   * (as `rootDir` would do for a single root).
   * To do this, look for the pattern outDir/relativeRoots[i]/path/to/file
   * or relativeRoots[i]/path/to/file
   * and replace that with path/to/file
   */
  flattenOutDir(fileName: string): string {
    let result = fileName;

    // outDir/relativeRoots[i]/path/to/file -> relativeRoots[i]/path/to/file
    if (fileName.startsWith(this.options.rootDir)) {
      result = path.relative(this.options.outDir, fileName);
    }

    for (const dir of this.relativeRoots) {
      if (result.startsWith(dir + '/')) {
        // relativeRoots[i]/path/to/file -> path/to/file
        result = path.relative(dir, result);
        // relativeRoots is sorted longest first so we can short-circuit
        // after the first match
        break;
      }
    }
    return result;
  }

  /** Avoid using tsickle on files that aren't in srcs[] */
  shouldSkipTsickleProcessing(fileName: string): boolean {
    return this.bazelOpts.compilationTargetSrc.indexOf(fileName) === -1;
  }

  /** Whether the file is expected to be imported using a named module */
  shouldNameModule(fileName: string): boolean {
    return this.bazelOpts.compilationTargetSrc.indexOf(fileName) !== -1;
  }

  /** Allows suppressing warnings for specific known libraries */
  shouldIgnoreWarningsForPath(filePath: string): boolean {
    return this.bazelOpts.ignoreWarningPaths.some(
        p => !!filePath.match(new RegExp(p)));
  }

  fileNameToModuleId(fileName: string): string {
    return this.flattenOutDir(fileName.substring(0, fileName.lastIndexOf('.')));
  }

  /**
   * TypeScript SourceFile's have a path with the rootDirs[i] still present, eg.
   * /build/work/bazel-out/local-fastbuild/bin/path/to/file
   * @return the path without any rootDirs, eg. path/to/file
   */
  private rootDirsRelative(fileName: string): string {
    for (const root of this.options.rootDirs) {
      if (fileName.startsWith(root)) {
        // rootDirs are sorted longest-first, so short-circuit the iteration
        // see tsconfig.ts.
        return path.relative(root, fileName);
      }
    }
    return fileName;
  }

  /**
   * Massages file names into valid goog.module names:
   * - resolves relative paths to the given context
   * - resolves non-relative paths which takes module_root into account
   * - replaces '/' with '.' in the '<workspace>' namespace
   * - replace first char if non-alpha
   * - replace subsequent non-alpha numeric chars
   */
  pathToModuleName(context: string, importPath: string): string {
    // tsickle hands us an output path, we need to map it back to a source
    // path in order to do module resolution with it.
    // outDir/relativeRoots[i]/path/to/file ->
    // rootDir/relativeRoots[i]/path/to/file
    if (context.startsWith(this.options.outDir)) {
      context = path.join(
          this.options.rootDir, path.relative(this.options.outDir, context));
    }

    // Try to get the resolved path name from TS compiler host which can
    // handle resolution for libraries with module_root like rxjs and @angular.
    let resolvedPath: string|null = null;
    const resolved =
        this.moduleResolver(importPath, context, this.options, this);
    if (resolved && resolved.resolvedModule &&
        resolved.resolvedModule.resolvedFileName) {
      resolvedPath = resolved.resolvedModule.resolvedFileName;
      // /build/work/bazel-out/local-fastbuild/bin/path/to/file ->
      // path/to/file
      resolvedPath = this.rootDirsRelative(resolvedPath);
    } else {
      // importPath can be an absolute file path in google3.
      // Try to trim it as a path relative to bin and genfiles, and if so,
      // handle its file extension in the block below and prepend the workspace
      // name.
      const trimmed = this.rootDirsRelative(importPath);
      if (trimmed !== importPath) {
        resolvedPath = trimmed;
      }
    }
    if (resolvedPath) {
      // Strip file extensions.
      importPath = resolvedPath.replace(/(\.d)?\.tsx?$/, '');
      // Make sure all module names include the workspace name.
      if (importPath.indexOf(this.bazelOpts.workspaceName) !== 0) {
        importPath = path.join(this.bazelOpts.workspaceName, importPath);
      }
    }

    // Remove the __{LOCALE} from the module name.
    if (this.bazelOpts.locale) {
      const suffix = '__' + this.bazelOpts.locale.toLowerCase();
      if (importPath.toLowerCase().endsWith(suffix)) {
        importPath = importPath.substring(0, importPath.length - suffix.length);
      }
    }

    // Replace characters not supported by goog.module and '.' with
    // '$<Hex char code>' so that the original module name can be re-obtained
    // without any loss.
    // See goog.VALID_MODULE_RE_ in Closure's base.js for characters supported
    // by google.module.

    const escape = (c: string) => {
      return '$' + c.charCodeAt(0).toString(16);
    };
    const moduleName = importPath.replace(/^[^a-zA-Z_/]/, escape)
                           .replace(/[^a-zA-Z_0-9_/]/g, escape)
                           .replace(/\//g, '.');
    return moduleName;
  }

  /**
   * Converts file path into a valid AMD module name.
   *
   * An AMD module can have an arbitrary name, so that it is require'd by name
   * rather than by path. See http://requirejs.org/docs/whyamd.html#namedmodules
   *
   * "However, tools that combine multiple modules together for performance need
   *  a way to give names to each module in the optimized file. For that, AMD
   *  allows a string as the first argument to define()"
   */
  amdModuleName(sf: ts.SourceFile): string|undefined {
    if (!this.shouldNameModule(sf.fileName)) return undefined;
    // /build/work/bazel-out/local-fastbuild/bin/path/to/file.ts
    // -> path/to/file.ts
    let fileName = this.rootDirsRelative(sf.fileName);
    let workspace = this.bazelOpts.workspaceName;

    // Workaround https://github.com/bazelbuild/bazel/issues/1262
    //
    // When the file comes from an external bazel repository,
    // and TypeScript resolves runfiles symlinks, then the path will look like
    // output_base/execroot/local_repo/external/another_repo/foo/bar
    // We want to name such a module "another_repo/foo/bar" just as it would be
    // named by code in that repository.
    // As a workaround, check for the /external/ path segment, and fix up the
    // workspace name to be the name of the external repository.
    if (fileName.startsWith('external/')) {
      const parts = fileName.split('/');
      workspace = parts[1];
      fileName = parts.slice(2).join('/');
    }

    // path/to/file.ts ->
    // myWorkspace/path/to/file
    return path.join(workspace, fileName.replace(/(\.d)?\.tsx?$/, ''));
  }

  /** Loads a source file from disk (or the cache). */
  getSourceFile(
      fileName: string, languageVersion: ts.ScriptTarget,
      onError?: (message: string) => void) {
    return perfTrace.wrap(`getSourceFile ${fileName}`, () => {
      const sf = this.fileLoader.loadFile(fileName, fileName, languageVersion);
      if (this.options.module === ts.ModuleKind.AMD ||
          this.options.module === ts.ModuleKind.UMD) {
        const moduleName = this.amdModuleName(sf);
        if (sf.moduleName === moduleName || !moduleName) return sf;
        if (sf.moduleName) {
          throw new Error(
              `ERROR: ${sf.fileName} ` +
              `contains a module name declaration ${sf.moduleName} ` +
              `which would be overwritten with ${moduleName} ` +
              `by Bazel's TypeScript compiler.`);
        }
        // Setting the moduleName is equivalent to the original source having a
        // ///<amd-module name="some/name"/> directive
        sf.moduleName = moduleName;
      }
      return sf;
    });
  }

  writeFile(
      fileName: string, content: string, writeByteOrderMark: boolean,
      onError: ((message: string) => void) | undefined,
      sourceFiles: ReadonlyArray<ts.SourceFile>): void {
    perfTrace.wrap(
        `writeFile ${fileName}`,
        () => this.writeFileImpl(
            fileName, content, writeByteOrderMark, onError, sourceFiles || []));
  }

  writeFileImpl(
      fileName: string, content: string, writeByteOrderMark: boolean,
      onError: ((message: string) => void) | undefined,
      sourceFiles: ReadonlyArray<ts.SourceFile>): void {
    // Workaround https://github.com/Microsoft/TypeScript/issues/18648
    if ((this.options.module === ts.ModuleKind.AMD ||
         this.options.module === ts.ModuleKind.UMD) &&
        fileName.endsWith('.d.ts') && sourceFiles && sourceFiles.length > 0 &&
        sourceFiles[0].moduleName) {
      content =
          `/// <amd-module name="${sourceFiles[0].moduleName}" />\n${content}`;
    }
    fileName = this.flattenOutDir(fileName);
    if (!this.bazelOpts.es5Mode) {
      // Write ES6 transpiled files to *.closure.js.
      if (this.bazelOpts.locale) {
        // i18n paths are required to end with __locale.js so we put
        // the .closure segment before the __locale
        fileName = fileName.replace(/(__[^\.]+)?\.js$/, '.closure$1.js');
      } else {
        fileName = fileName.replace(/\.js$/, '.closure.js');
      }
    }

    // Prepend the output directory.
    fileName = path.join(this.options.outDir, fileName);

    // Our file cache is based on mtime - so avoid writing files if they
    // did not change.
    if (!fs.existsSync(fileName) ||
        fs.readFileSync(fileName, 'utf-8') !== content) {
      this.delegate.writeFile(
          fileName, content, writeByteOrderMark, onError, sourceFiles);
    }
  }

  /**
   * Performance optimization: don't try to stat files we weren't explicitly
   * given as inputs.
   * This also allows us to disable Bazel sandboxing, without accidentally
   * reading .ts inputs when .d.ts inputs are intended.
   * Note that in worker mode, the file cache will also guard against arbitrary
   * file reads.
   */
  fileExists(filePath: string): boolean {
    // Allow moduleResolution=node to behave normally.
    if (this.allowNonHermeticReads && isNonHermeticInput(filePath) &&
        this.delegate.fileExists(filePath)) {
      return true;
    }
    return this.knownFiles.has(filePath);
  }

  getDefaultLibFileName(options: ts.CompilerOptions): string {
    if (this.bazelOpts.nodeModulesPrefix) {
      return path.join(
          this.bazelOpts.nodeModulesPrefix, 'typescript/lib',
          ts.getDefaultLibFileName({target: ts.ScriptTarget.ES5}));
    }
    return this.delegate.getDefaultLibFileName(options);
  }

  // Delegate everything else to the original compiler host.

  getCanonicalFileName(path: string) {
    return this.delegate.getCanonicalFileName(path);
  }

  getCurrentDirectory(): string {
    return this.delegate.getCurrentDirectory();
  }

  useCaseSensitiveFileNames(): boolean {
    return this.delegate.useCaseSensitiveFileNames();
  }

  getNewLine(): string {
    return this.delegate.getNewLine();
  }

  getDirectories(path: string) {
    return this.delegate.getDirectories(path);
  }

  readFile(fileName: string): string|undefined {
    return this.delegate.readFile(fileName);
  }

  trace(s: string): void {
    console.error(s);
  }

  realpath(s: string): string {
    return ts.sys.realpath!(s);
  }
}
