import fs from 'node:fs';
import path from 'node:path';
import { claudeSettingsPath } from '../config/paths';

const HOOK_EVENTS = ['UserPromptSubmit', 'SessionStart', 'SessionEnd'] as const;
const EVENT_TO_SUBCOMMAND: Record<(typeof HOOK_EVENTS)[number], string> = {
  UserPromptSubmit: 'user-prompt-submit',
  SessionStart: 'session-start',
  SessionEnd: 'session-end',
};

// Matches our generated command regardless of exact executable/quoting,
// e.g. `"...\node.exe" "...\bin\prompt-agent" hook session-start`.
const MANAGED_COMMAND_PATTERN = /\bhook (user-prompt-submit|session-start|session-end)\b/;

export function isManagedCommand(command: string): boolean {
  return MANAGED_COMMAND_PATTERN.test(command);
}

interface HookCommand {
  type: 'command';
  command: string;
}

interface HookEntry {
  hooks: HookCommand[];
}

interface ClaudeSettings {
  hooks?: Record<string, HookEntry[]>;
  [key: string]: unknown;
}

function readSettings(): ClaudeSettings {
  const file = claudeSettingsPath();

  if (!fs.existsSync(file)) {
    return {};
  }

  try {
    return JSON.parse(fs.readFileSync(file, 'utf8')) as ClaudeSettings;
  } catch {
    throw new Error(`Could not parse ${file} as JSON. Fix or remove it before installing hooks.`);
  }
}

function writeSettings(settings: ClaudeSettings): void {
  const file = claudeSettingsPath();
  fs.mkdirSync(path.dirname(file), { recursive: true });
  fs.writeFileSync(file, JSON.stringify(settings, null, 2));
}

function commandFor(cliPath: string, event: (typeof HOOK_EVENTS)[number]): string {
  return `"${process.execPath}" "${cliPath}" hook ${EVENT_TO_SUBCOMMAND[event]}`;
}

export function installHooks(cliPath: string): void {
  const settings = readSettings();
  settings.hooks ??= {};

  for (const event of HOOK_EVENTS) {
    const entries = (settings.hooks[event] ??= []);
    const alreadyInstalled = entries.some((entry) => entry.hooks.some((h) => isManagedCommand(h.command)));

    if (!alreadyInstalled) {
      entries.push({ hooks: [{ type: 'command', command: commandFor(cliPath, event) }] });
    }
  }

  writeSettings(settings);
}

export function uninstallHooks(): void {
  const settings = readSettings();

  if (!settings.hooks) {
    return;
  }

  for (const event of HOOK_EVENTS) {
    if (!settings.hooks[event]) {
      continue;
    }

    settings.hooks[event] = settings.hooks[event]
      .map((entry) => ({ hooks: entry.hooks.filter((h) => !isManagedCommand(h.command)) }))
      .filter((entry) => entry.hooks.length > 0);

    if (settings.hooks[event].length === 0) {
      delete settings.hooks[event];
    }
  }

  writeSettings(settings);
}
