/**
 * Claude Code adapter — handles Claude CLI specifics.
 */

import { execSync } from 'node:child_process';
import { realpathSync } from 'node:fs';
import type { AgentAdapter, AgentConfig, AgentSpawnOptions, AgentSpawnResult } from './types';

const CAPABILITIES = {
  supportsResume: true,
  supportsStreamJson: true,
  supportsModel: true,
  supportsSkipPermissions: true,
  hasSessionFiles: true,
  requiresTTY: false,
};

/** Resolve claude binary path (symlink → real .js → node) */
function resolveClaudePath(claudePath: string): { cmd: string; prefix: string[] } {
  try {
    let resolved = claudePath;
    try {
      const which = execSync(`which ${claudePath}`, { encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
      resolved = realpathSync(which);
    } catch {
      resolved = realpathSync(claudePath);
    }
    if (resolved.endsWith('.js') || resolved.endsWith('.mjs')) {
      return { cmd: process.execPath, prefix: [resolved] };
    }
    return { cmd: resolved, prefix: [] };
  } catch {
    return { cmd: process.execPath, prefix: [claudePath] };
  }
}

export function createClaudeAdapter(config: AgentConfig): AgentAdapter {
  return {
    id: 'claude',
    config: { ...config, capabilities: CAPABILITIES },

    buildTaskSpawn(opts: AgentSpawnOptions): AgentSpawnResult {
      const resolved = resolveClaudePath(config.path);
      const args = [...resolved.prefix, '-p', '--verbose'];

      if (opts.outputFormat === 'stream-json' || opts.outputFormat === undefined) {
        args.push('--output-format', 'stream-json');
      } else if (opts.outputFormat === 'json') {
        args.push('--output-format', 'json');
      }

      if (opts.skipPermissions !== false) {
        const flag = config.skipPermissionsFlag || '--dangerously-skip-permissions';
        if (flag) args.push(...flag.split(/\s+/));
      }

      if (opts.model && opts.model !== 'default') {
        args.push('--model', opts.model);
      }

      if (opts.conversationId) {
        args.push('--resume', opts.conversationId);
      }

      if (opts.appendSystemPrompt && opts.appendSystemPrompt.trim()) {
        args.push('--append-system-prompt', opts.appendSystemPrompt);
      }

      if (opts.extraFlags) {
        args.push(...opts.extraFlags);
      }

      args.push(opts.prompt);

      // Forward agent-level env (e.g. ANTHROPIC_AUTH_TOKEN/BASE_URL on a
      // user-named CLI agent that wraps claude). task-manager merges this
      // into the child env, letting one agent point claude at a custom
      // endpoint without touching the user's global ~/.claude config.
      const env = (config as any).env as Record<string, string> | undefined;
      return { cmd: resolved.cmd, args, ...(env && Object.keys(env).length ? { env } : {}) };
    },

    buildTerminalCommand(opts) {
      const flag = config.skipPermissionsFlag || '--dangerously-skip-permissions';
      const skipFlag = opts.skipPermissions && flag ? ` ${flag}` : '';
      // MUST use the agent-configured path, not the literal "claude" on
      // $PATH — Forge ships its own pinned binary at <dataDir>/local-bin/claude,
      // and tmux PATH on a first-install machine often still points at a
      // stale global @anthropic-ai/claude-code (e.g. /opt/homebrew/...).
      // Bare "claude" would silently fall through to that older version
      // and throw on resume. Quote in case the path has spaces.
      const claudeCmd = `"${config.path}"`;
      if (opts.sessionId) {
        return `cd "${opts.projectPath}" && ${claudeCmd} --resume ${opts.sessionId}${skipFlag}\n`;
      }
      const resumeFlag = opts.resume ? ' -c' : '';
      return `cd "${opts.projectPath}" && ${claudeCmd}${resumeFlag}${skipFlag}\n`;
    },
  };
}

/** Detect if claude is installed and return config */
export function detectClaude(customPath?: string): AgentConfig | null {
  const paths = customPath ? [customPath] : ['claude'];
  for (const p of paths) {
    try {
      // Resolve to absolute path — storing the literal `'claude'` is
      // useless: every terminal launch then becomes a bare `claude` on
      // tmux pane PATH, which on first-install machines silently
      // resolves to a stale global @anthropic-ai/claude-code (e.g.
      // /opt/homebrew/lib/node_modules/...) and crashes on resume.
      // If the user passed an absolute path already, keep it as-is.
      const which = execSync(`which ${p}`, { encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
      const resolved = (p.startsWith('/') || !which) ? p : which;
      return {
        id: 'claude',
        name: 'Claude Code',
        path: resolved,
        enabled: true,
        type: 'claude-code',
        capabilities: CAPABILITIES,
        skipPermissionsFlag: '--dangerously-skip-permissions',
      };
    } catch {}
  }
  return null;
}
