/**
 * Hooks preview stage — shows users what hooks will be installed into ~/.claude/
 * and asks for consent before the finalize stage copies them.
 *
 * Skipped automatically when Claude was not detected in runtimeSetupStage.
 */

import { existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import type { WizardPrompter } from '../prompter/interface.js';
import type { WizardState } from '../types.js';

// ── Types for the hooks-config.json schema ────────────────────────────────────

interface HookEntry {
  type?: string;
  command?: string;
  args?: string[];
  /** Allow any additional keys */
  [key: string]: unknown;
}

interface HookTrigger {
  matcher?: string;
  hooks?: HookEntry[];
}

interface HooksConfig {
  name?: string;
  description?: string;
  version?: string;
  hooks?: Record<string, HookTrigger[]>;
  [key: string]: unknown;
}

// ── Constants ─────────────────────────────────────────────────────────────────

const COMMAND_PREVIEW_MAX = 80;

// ── Helpers ───────────────────────────────────────────────────────────────────

function truncate(s: string, max: number): string {
  return s.length <= max ? s : `${s.slice(0, max - 3)}...`;
}

function loadHooksConfig(state: WizardState): HooksConfig | null {
  // Prefer package source during fresh install
  const candidates = [
    join(state.sourceDir, 'framework', 'runtime', 'claude', 'hooks-config.json'),
    join(state.mosaicHome, 'runtime', 'claude', 'hooks-config.json'),
  ];

  for (const p of candidates) {
    if (existsSync(p)) {
      try {
        return JSON.parse(readFileSync(p, 'utf-8')) as HooksConfig;
      } catch {
        return null;
      }
    }
  }

  return null;
}

function buildHookLines(config: HooksConfig): string[] {
  const lines: string[] = [];

  if (config.name) {
    lines.push(`  ${config.name}`);
    if (config.description) lines.push(`  ${config.description}`);
    lines.push('');
  }

  const hookEvents = config.hooks ?? {};
  const eventNames = Object.keys(hookEvents);

  if (eventNames.length === 0) {
    lines.push('  (no hook events defined)');
    return lines;
  }

  for (const event of eventNames) {
    const triggers = hookEvents[event] ?? [];
    for (const trigger of triggers) {
      const matcher = trigger.matcher ?? '(any)';
      lines.push(`  Event:   ${event}`);
      lines.push(`  Matcher: ${matcher}`);

      const hookList = trigger.hooks ?? [];
      for (const h of hookList) {
        const parts: string[] = [];
        if (h.command) parts.push(h.command);
        if (Array.isArray(h.args)) {
          // Show first arg (usually '-c') then a preview of the script
          const firstArg = h.args[0] as string | undefined;
          const scriptArg = h.args[1] as string | undefined;
          if (firstArg) parts.push(firstArg);
          if (scriptArg) parts.push(truncate(scriptArg, COMMAND_PREVIEW_MAX));
        }
        lines.push(`  Command: ${parts.join(' ')}`);
      }

      lines.push('');
    }
  }

  return lines;
}

// ── Stage ─────────────────────────────────────────────────────────────────────

export async function hooksPreviewStage(p: WizardPrompter, state: WizardState): Promise<void> {
  // Skip entirely when Claude wasn't detected
  if (!state.runtimes.detected.includes('claude')) {
    return;
  }

  p.separator();

  const config = loadHooksConfig(state);

  if (!config) {
    p.warn(
      'Could not locate hooks-config.json — skipping hooks preview. ' +
        'You can manage hooks later with `mosaic config hooks list`.',
    );
    return;
  }

  const hookLines = buildHookLines(config);

  p.note(hookLines.join('\n'), 'Hooks to be installed in ~/.claude/');

  const accept = await p.confirm({
    message: 'Install these hooks to ~/.claude/?',
    initialValue: true,
  });

  if (accept) {
    state.hooks = { accepted: true, acceptedAt: new Date().toISOString() };
  } else {
    state.hooks = { accepted: false };
    p.note(
      'Hooks skipped. Runtime assets (settings.json, CLAUDE.md) will still be copied.\n' +
        'To install hooks later: re-run `mosaic wizard` or copy the file manually.',
      'Hooks skipped',
    );
  }
}
