// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.


import * as vscode from 'vscode';
import * as fs from 'fs';
import * as logger from './logger';
import * as path from 'path';
import { Ffx } from './ffx';

const CONFIG_ROOT_NAME = 'fuchsia';

/**
 * ToolFinder creates and keeps a single Ffx class instance with an up-to-date path to the ffx
 * binary.
 */
export class ToolFinder {
  private ffxPathInternal: string | undefined;
  private ffxInternal: Ffx;
  private readonly onDidUpdateFfxEmitter = new vscode.EventEmitter<{ isInitial: boolean }>();

  /**
   * Occurs when the FFX instance is updated.
   *
   * Mainly useful for testing
   */
  public readonly onDidUpdateFfx = this.onDidUpdateFfxEmitter.event;

  constructor() {
    const cwd = vscode.workspace.workspaceFolders?.map(folder => folder.uri.path)[0];
    this.ffxInternal = new Ffx(cwd, undefined, this);
    this.updateFfxPath(true).catch((err) => logger.error('unable to configure initial ffx location', undefined, err));
    vscode.workspace.onDidChangeConfiguration(event => {
      if (event.affectsConfiguration(`${CONFIG_ROOT_NAME}.ffxPath`)) {
        this.updateFfxPath(false).catch((err) => logger.error('unable to reconfigure ffx location', undefined, err));
      }
    });
  }

  /**
   * Get the single Ffx class instance with an up-to-date path to the ffx binary.
   * @returns Ffx class instance.
   */
  public get ffx(): Ffx {
    return this.ffxInternal;
  }

  /**
   * For testing: get the path of the ffx binary.
   * @returns the path to the ffx binary.
   */
  public get ffxPath(): string | undefined {
    return this.ffxPathInternal;
  }

  /**
   * Returns the full path to the ffx binary from a custom path. The custom path can be relative,
   * and/or start with `~/` (which means `$HOME`).
   * @param inputPath custom path to the ffx binary.
   * @param workspacePath the full path to the workspace.
   * @returns the full path to the ffx binary.
   */
  resolveAbsolutePath(inputPath: string, workspacePath: string | undefined): string {
    // NB(sollyross): this mimics what VSCode itself does:
    // https://github.com/microsoft/vscode/blob/8030b3ac7ace36d062109846b07643a651f4ce51/src/vs/base/common/labels.ts#L200
    // Note, specifically, that we only handle `~` and not `~sollyross` or
    // `~[omg:zsh]` or other shell- and os-specific variants
    // (which is why `.startsWith('~')` is insufficient)
    let toolPath = inputPath;
    if (toolPath.match(/^~($|\/|\\)/) /* are we `~`, `~/` or `~\` */) {
      if (!process.env.HOME) {
        throw new Error(`Unable to locate $HOME to expand ~ in tool path. path = "${toolPath}".`);
      }
      return path.join(process.env.HOME, toolPath.substring(1)) as string;
    } else if (path.isAbsolute(toolPath)) {
      return toolPath;
    } else {
      if (workspacePath === undefined) {
        throw new Error('Could not evaluate the workspace' +
          `relative path for ffx. path = "${toolPath}".`);
      }
      return path.join(workspacePath, toolPath) as string;
    }
  }

  /**
   * Tests if the ffx path exists and if it's an executable.
   *
   * @param ffxPath absolute path to the ffx binary.
   *
   * @throws error if this test fails.
   */
  async validateFfxPath(ffxPath: string) {
    if (!(await fs.promises.stat(ffxPath)).isFile()) {
      throw new Error(`The path for ffx is not a file. path = "${ffxPath}".`);
    }
    // Check if ffx is executable. This has no effect on Windows.
    await fs.promises.access(ffxPath, fs.constants.X_OK);
  }

  // TODO(fxbug.dev/98459): Handle searching multiple workspace folders.
  /**
   * If the user has not set the ffx binary path, this method searches for it in known locations
   * (e.g. tools/ffx), see README.md.
   * @param workspacePath the full path to the workspace folder
   * @returns the full path to the ffx binary.
   * @throws error if the ffx binary path was not found.
   */
  async findFfxPath(workspacePath: string | undefined): Promise<string> {
    if (workspacePath === undefined) {
      throw new Error('ffx path error: Cannot read the workspace folder.');
    }
    const ffxPaths = [path.join('.jiri_root', 'bin', 'ffx'), path.join('tools', 'ffx')];
    for (const ffxPath of ffxPaths) {
      const fullFfxPath = path.join(workspacePath, ffxPath);
      try {
        await this.validateFfxPath(fullFfxPath);
        return ffxPath;
      } catch (err) {
        if (err instanceof Error) {
          logger.debug(err.message, 'tool_finder');
        }
      }
    }
    throw new Error('Ffx could not be found.');
  }

  /**
   * Update the ffx binary path. This method is generally called when initializing, or when the
   * configuration path settings have changed.
   */
  async updateFfxPath(isInitial: boolean) {
    try {
      const workspacePath = vscode.workspace.workspaceFolders?.map(folder => folder.uri.path)[0];
      const configFfxPath = vscode.workspace.getConfiguration(CONFIG_ROOT_NAME).get('ffxPath');

      if (typeof configFfxPath !== 'string') {
        throw new Error('Could not get the ffxPath configuration.');
      }

      let ffxPath = '';

      if (configFfxPath.length === 0) {
        ffxPath = await this.findFfxPath(workspacePath);
        // don't update here -- it's unexpected to change the user's configuration for them, and it
        // makes it hard to adjust for changes in layout automatically in the future.
        //
        // Plus, it'd trigger an extra loop-around of updates, meaning an extra target list,
        // extra messages, etc.
      } else {
        ffxPath = configFfxPath;
      }

      ffxPath = this.resolveAbsolutePath(ffxPath, workspacePath);
      await this.validateFfxPath(ffxPath);

      this.ffxPathInternal = ffxPath;
    } catch (err) {
      logger.error('Error updating ffx path', 'tool_finder', err);
      void vscode.window.showErrorMessage(`Error updating ffx path: ${(err instanceof Error) ? err.message : ''}`);
      this.ffxPathInternal = undefined;
    }

    this.ffxInternal.path = this.ffxPathInternal;
    if (this.ffxPathInternal) {
      logger.debug(`FFX path set to '${this.ffxPathInternal}'`);
    }

    this.onDidUpdateFfxEmitter.fire({ isInitial });
  }
}
