#!/usr/bin/env node
/**
 * Bootstrap ~/.pilotdeck/pilotdeck.yaml when it doesn't exist yet, so the
 * gateway can boot and the Web UI can run the onboarding flow that fills in
 * real provider details. On every startup, also sync repo-provided skills
 * into ~/.pilotdeck/skills without overwriting existing targets.
 *
 * Behaviour:
 *   1. Every run: discover repo skills and copy missing slugs into
 *      $PILOT_HOME/skills, skipping existing targets.
 *   2. If $PILOT_HOME/pilotdeck.yaml already exists -> skip config bootstrap.
 *   3. Otherwise write a minimal V2 yaml that:
 *        - has a valid agent.model that resolves to a catalog provider/model,
 *          so the engine's parseModelConfig won't crash on startup
 *        - uses a sentinel apiKey ("PLACEHOLDER_RUN_ONBOARDING_TO_REPLACE")
 *          that hasUsablePilotDeckConfig() recognises as "not ready" so the
 *          UI redirects to onboarding instead of pretending it's configured.
 *
 * Override the target via $PILOT_HOME (same env var the engine reads).
 * Skip the whole step via $PILOTDECK_SKIP_BOOTSTRAP=1.
 */
import { cpSync, existsSync, mkdirSync, readdirSync, writeFileSync } from 'node:fs';
import { homedir } from 'node:os';
import { basename, dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const SENTINEL_API_KEY = 'PLACEHOLDER_RUN_ONBOARDING_TO_REPLACE';
const __filename = fileURLToPath(import.meta.url);
const REPO_ROOT = resolve(dirname(__filename), '..');

const BOOTSTRAP_YAML = `# Auto-generated by scripts/bootstrap-pilotdeck-config.mjs.
# Open the Web UI to finish onboarding — choose a provider, paste an API key,
# and pick a model. The gateway boots with this placeholder config so the
# server can start, but apiKey="${SENTINEL_API_KEY}" tells the UI
# to redirect to the onboarding screen.
schemaVersion: 1
agent:
  model: _placeholder/_placeholder
model:
  providers:
    _placeholder:
      protocol: openai
      url: https://placeholder.invalid
      apiKey: ${SENTINEL_API_KEY}
      models:
        _placeholder:
          capabilities:
            maxOutputTokens: 16384
router:
  scenarios:
    default: _placeholder/_placeholder
  fallback:
    default:
      - _placeholder/_placeholder
  zeroUsageRetry:
    enabled: false
    maxAttempts: 2
  tokenSaver:
    enabled: false
    judge: _placeholder/_placeholder
    defaultTier: medium
    judgeTimeoutMs: 15000
    tiers:
      simple:
        model: _placeholder/_placeholder
        description: "Simple greetings, confirmations, single-step Q&A, trivial file writes, remembering rules"
      medium:
        model: _placeholder/_placeholder
        description: "Single tool call, short text generation, 1-2 file read/write, code generation"
      complex:
        model: _placeholder/_placeholder
        description: "Needs sub-agent orchestration: parallel workstreams, delegation to specialized agents"
      reasoning:
        model: _placeholder/_placeholder
        description: "Deep single-agent work: multi-file operations, data analysis, multi-step workflows, web research, structured reports from many sources"
    rules:
      - "complex is ONLY for tasks that need sub-agent orchestration or parallel delegation — do NOT use it for single-agent multi-step work"
      - "Multi-file operations, data analysis, and multi-step workflows without orchestration should be reasoning"
      - "Simple file creation (1-2 files) or single code generation is medium"
      - "Trivial greetings, confirmations, remembering rules, or reading one file and answering a short question is simple"
  autoOrchestrate:
    enabled: false
    triggerTiers:
      - complex
    slimSystemPrompt: true
    allowedTools:
      - agent
      - read_file
      - grep
      - glob
      - read_skill
    subagentMaxTokens: 48000
  stats:
    enabled: false
`;

function resolvePilotHome() {
  if (process.env.PILOT_HOME) return process.env.PILOT_HOME;
  return join(homedir(), '.pilotdeck');
}

function discoverRepoSkillDirs(skillsRoot) {
  if (!existsSync(skillsRoot)) {
    return [];
  }

  const discovered = [];
  const pending = [skillsRoot];
  while (pending.length > 0) {
    const current = pending.pop();
    const entries = readdirSync(current, { withFileTypes: true });
    if (entries.some((entry) => entry.isFile() && /^skill\.md$/i.test(entry.name))) {
      discovered.push(current);
      continue;
    }
    for (const entry of entries) {
      if (entry.isDirectory()) {
        pending.push(join(current, entry.name));
      }
    }
  }

  discovered.sort((left, right) => left.localeCompare(right));
  return discovered;
}

function syncRepoSkillsToPilotHome(pilotHome) {
  const repoSkillsRoot = join(REPO_ROOT, 'skills');
  const skillDirs = discoverRepoSkillDirs(repoSkillsRoot);
  if (skillDirs.length === 0) {
    return { created: 0, skippedExisting: 0, skippedDuplicateSlug: 0 };
  }

  const targetRoot = join(pilotHome, 'skills');
  mkdirSync(targetRoot, { recursive: true });

  let created = 0;
  let skippedExisting = 0;
  let skippedDuplicateSlug = 0;
  const seenSlugs = new Map();

  for (const sourceDir of skillDirs) {
    const slug = basename(sourceDir);
    const previous = seenSlugs.get(slug);
    if (previous) {
      skippedDuplicateSlug += 1;
      console.warn(
        `[pilotdeck] Skipping repo skill '${slug}' at ${sourceDir}; slug already claimed by ${previous}.`,
      );
      continue;
    }
    seenSlugs.set(slug, sourceDir);

    const targetPath = join(targetRoot, slug);
    if (existsSync(targetPath)) {
      skippedExisting += 1;
      continue;
    }

    try {
      cpSync(sourceDir, targetPath, { recursive: true });
      created += 1;
    } catch (error) {
      console.warn(
        `[pilotdeck] Could not import repo skill '${slug}' into ${targetPath}: ${
          error instanceof Error ? error.message : String(error)
        }`,
      );
    }
  }

  return { created, skippedExisting, skippedDuplicateSlug };
}

function main() {
  if (process.env.PILOTDECK_SKIP_BOOTSTRAP === '1') {
    return;
  }

  const pilotHome = resolvePilotHome();
  const configPath = join(pilotHome, 'pilotdeck.yaml');
  const skillSync = syncRepoSkillsToPilotHome(pilotHome);
  if (skillSync.created > 0 || skillSync.skippedExisting > 0 || skillSync.skippedDuplicateSlug > 0) {
    console.log(
      `[pilotdeck] Synced repo skills into ${join(pilotHome, 'skills')}: ` +
        `${skillSync.created} copied, ${skillSync.skippedExisting} skipped existing, ` +
        `${skillSync.skippedDuplicateSlug} skipped duplicate slug.`,
    );
  }

  if (existsSync(configPath)) {
    return;
  }

  try {
    mkdirSync(dirname(configPath), { recursive: true });
    writeFileSync(configPath, BOOTSTRAP_YAML, 'utf8');
    console.log(
      `[pilotdeck] No config at ${configPath}; wrote a placeholder so the gateway can boot.`,
    );
    console.log('[pilotdeck] Open the Web UI to finish onboarding (provider + API key).');
  } catch (error) {
    console.warn(
      `[pilotdeck] Could not bootstrap ${configPath}: ${error instanceof Error ? error.message : String(error)}`,
    );
    console.warn('[pilotdeck] You may need to create it manually before running npm run dev.');
  }
}

main();