const fs = require('fs');
const path = require('path');

/**
 * TypeScript / JavaScript LSP adapter.
 *
 * Language server: `typescript-language-server` (Node, npm).
 * Install mode: global npm install — the binary MUST land on `$PATH` because
 * the consumer (Claude Code's LSP tool) spawns it by name from `$PATH`, not
 * via `npx`/node_modules resolution. A project-local devDep (the pre-v3.33.1
 * behaviour) installed into `node_modules/.bin/` which is NOT on `$PATH`, so
 * every LSP spawn failed with `Executable not found in $PATH` while the
 * `npx --no-install` verify falsely reported success — a dead layer masked by
 * the silent Grep fallback.
 *
 * Detection signal: presence of `tsconfig.json`, `jsconfig.json`, or a
 * `package.json` referencing typescript in deps/devDeps.
 */
class TypeScriptAdapter {
  constructor(cwd = process.cwd()) { this.cwd = cwd; }

  get name() { return 'typescript'; }
  get label() { return 'TypeScript / JavaScript'; }
  get binary() { return 'typescript-language-server'; }

  /**
   * 'npm-global' = installed globally via npm so it lands on `$PATH`.
   * 'system'     = printed install instructions (non-npm toolchains).
   * Treated identically to system mode by the installer except that npm-global
   * adapters are safe to auto-execute (no sudo, no toolchain assumptions).
   */
  get installMode() { return 'npm-global'; }

  /** npm package(s) to install when mode='npm-global'. */
  get npmPackage() { return 'typescript-language-server typescript'; }

  /** Shell command the user (or installer) should run. */
  installCommand() {
    return 'npm install -g typescript-language-server typescript';
  }

  /**
   * Functional probe: invokes the binary the SAME way the consumer spawns it —
   * by name from `$PATH`. Reachability on `$PATH` is the actual contract the
   * consumer depends on; `LspInstaller.verifyServers()` checks it explicitly
   * via `command -v` and only runs this probe once the binary resolves.
   */
  verifyCommand() { return 'typescript-language-server --version'; }

  /**
   * Claude Code code-intelligence plugin id, if any. Null = no companion plugin.
   * When non-null, `LspInstaller.installClaudePlugins()` installs this plugin
   * from the `claude-plugins-official` marketplace (anthropics/claude-plugins-official)
   * so the LSP layer is wired into Claude Code natively instead of leaving the
   * user to enable it manually after `baldart configure`.
   */
  claudePluginId() { return 'typescript-lsp@claude-plugins-official'; }

  /** Autodetect whether this language is in scope for the project. */
  static detect(cwd = process.cwd()) {
    const markers = ['tsconfig.json', 'jsconfig.json'];
    for (const m of markers) {
      if (fs.existsSync(path.join(cwd, m))) return true;
    }
    try {
      const pkgPath = path.join(cwd, 'package.json');
      if (!fs.existsSync(pkgPath)) return false;
      const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
      const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
      return Boolean(allDeps.typescript);
    } catch { return false; }
  }
}

module.exports = TypeScriptAdapter;
