import { execSync } from 'child_process';
import type { SkillInstallerSpec } from './types.js';

export interface InstallerPlanStep {
  installerType: SkillInstallerSpec['type'];
  command: string;
}

export interface InstallerPlanSkip {
  installerType: SkillInstallerSpec['type'];
  reason: string;
}

export interface InstallerPlan {
  mode: 'dry-run';
  steps: InstallerPlanStep[];
  skipped: InstallerPlanSkip[];
}

export interface InstallerPlanningOptions {
  hasBinary?: (name: string) => boolean;
}

function hasBinaryOnPath(name: string): boolean {
  const cmd = process.platform === 'win32' ? 'where' : 'which';
  try {
    execSync(`${cmd} ${name}`, { stdio: 'ignore' });
    return true;
  } catch {
    return false;
  }
}

export function buildInstallerPlan(
  installers: SkillInstallerSpec[] | undefined,
  opts: InstallerPlanningOptions = {},
): InstallerPlan {
  const hasBinary = opts.hasBinary ?? hasBinaryOnPath;
  const steps: InstallerPlanStep[] = [];
  const skipped: InstallerPlanSkip[] = [];

  for (const installer of installers ?? []) {
    if (installer.type === 'brew') {
      if (!hasBinary('brew')) {
        skipped.push({ installerType: 'brew', reason: 'brew not available in PATH' });
        continue;
      }
      steps.push({ installerType: 'brew', command: `brew install ${installer.packages.join(' ')}` });
      continue;
    }

    if (installer.type === 'node') {
      if (hasBinary('pnpm')) {
        steps.push({ installerType: 'node', command: `pnpm add -g ${installer.packages.join(' ')}` });
        continue;
      }
      if (hasBinary('npm')) {
        steps.push({ installerType: 'node', command: `npm install -g ${installer.packages.join(' ')}` });
        continue;
      }
      skipped.push({ installerType: 'node', reason: 'neither pnpm nor npm available in PATH' });
      continue;
    }

    if (installer.type === 'go') {
      if (!hasBinary('go')) {
        skipped.push({ installerType: 'go', reason: 'go not available in PATH' });
        continue;
      }
      for (const pkg of installer.packages) {
        steps.push({ installerType: 'go', command: `go install ${pkg}@latest` });
      }
      continue;
    }

    const destination = installer.destination ?? '<default destination>';
    steps.push({
      installerType: 'download',
      command: `download ${installer.url} -> ${destination}`,
    });
  }

  return {
    mode: 'dry-run',
    steps,
    skipped,
  };
}
