import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { itemsDir, getHomeDir, DATA_PATH } from '@@/data-path';

type HookEntry = { type: string; command: string };
type HookRule = { matcher?: Record<string, unknown>; hooks: HookEntry[] };
type ClaudeSettings = Record<string, unknown> & {
  hooks?: Record<string, HookRule[]>;
};

type FrontmatterEntry = { name: string; description: string };

function parseFrontmatter(content: string): Record<string, string> {
  const match = content.match(/^---\n([\s\S]*?)\n---/);
  if (!match) return {};
  const fields: Record<string, string> = {};
  for (const line of match[1]!.split('\n')) {
    const m = line.match(/^(\w+):\s*(.+)/);
    if (m) fields[m[1]!] = m[2]!.trim();
  }
  return fields;
}

function scanDir(dir: string, metaFile: string): FrontmatterEntry[] {
  if (!existsSync(dir)) return [];
  const entries: FrontmatterEntry[] = [];
  for (const name of readdirSync(dir, { withFileTypes: true })) {
    if (!name.isDirectory()) continue;
    const filePath = join(dir, name.name, metaFile);
    if (!existsSync(filePath)) continue;
    const fm = parseFrontmatter(readFileSync(filePath, 'utf-8'));
    if (fm.name || fm.label) {
      entries.push({ name: fm.name ?? fm.label ?? name.name, description: fm.description ?? '' });
    }
  }
  return entries;
}

function dedup(entries: FrontmatterEntry[]): FrontmatterEntry[] {
  const seen = new Map<string, FrontmatterEntry>();
  for (const e of entries) seen.set(e.name, e);
  return [...seen.values()];
}

function formatList(entries: FrontmatterEntry[]): string {
  if (entries.length === 0) return 'None configured.\n';
  return entries.map((e) => `- **${e.name}**${e.description ? ` — ${e.description}` : ''}`).join('\n') + '\n';
}

export function generateContainerContext(email: string): string {
  const toolsDir = itemsDir('tools');
  const skillsDir = itemsDir('skills');
  const tasksDir = itemsDir('tasks');
  const tools = dedup(scanDir(toolsDir, 'TOOL.md'));
  const skills = dedup(scanDir(skillsDir, 'SKILL.md'));
  const tasks = dedup(scanDir(tasksDir, 'TASK.md'));

  const userDataDir = join(DATA_PATH, email);

  const content = `# Officer — User Environment

This is an isolated Linux user environment managed by the Officer platform.

## Directory Layout

| Path | Contents |
|------|----------|
| \`~\` | User home directory (read-write) |
| \`~/Projects/\` | User projects |
| \`~/Downloads/\` | Downloaded files |
| \`${toolsDir}/\` | Tools |
| \`${skillsDir}/\` | Reference skills |
| \`${userDataDir}/\` | User data (emails.db, attachments, etc.) |

## Available Tools

Tools are callable capabilities used by the Officer AI agent (Pi). Each tool has a \`TOOL.md\` with documentation and an \`index.ts\` that exports an \`execute()\` function. Read individual tool docs at \`${toolsDir}/<name>/TOOL.md\`.

${formatList(tools)}
## Available Skills

Skills are reference documentation that the AI agent uses to understand APIs and CLIs.

${formatList(skills)}
## Available Tasks

Tasks are predefined instruction sets the AI agent can execute.

${formatList(tasks)}
## Creating New Tools

Create a directory in \`${toolsDir}/<tool-name>/\` with two files:

**TOOL.md** — Frontmatter metadata + markdown documentation:
\`\`\`yaml
---
name: my_tool
description: What it does and when the agent should use it.
version: 1
language: typescript
inputs:
  param:
    type: string
    description: What this parameter is for.
---
# My Tool
Usage documentation here.
\`\`\`

**index.ts** — Must export an \`execute\` function:
\`\`\`typescript
type ToolResult = { content: Array<{ type: string; text: string }>; isError?: boolean };

export async function execute(_toolCallId: string, params: Record<string, unknown>): Promise<ToolResult> {
  return { content: [{ type: 'text', text: 'Done' }] };
}
\`\`\`

## Environment Variables

| Variable | Description |
|----------|-------------|
| \`OFFICER_EMAIL_DB\` | Path to email SQLite database |
| \`PI_TOOLS_DIRS\` | Tool discovery paths (colon-separated) |
| \`PI_SEARXNG_URL\` | Search engine URL |
`;

  const contextDir = join(DATA_PATH, email, '.container-context');
  mkdirSync(contextDir, { recursive: true });
  const filePath = join(contextDir, 'CLAUDE.md');
  writeFileSync(filePath, content);
  return filePath;
}

export function generateClaudeSettings(email: string, username?: string): string {
  const hostSettingsPath = join(process.env.HOME ?? '', '.claude', 'settings.json');
  let settings: ClaudeSettings = {};
  try {
    settings = JSON.parse(readFileSync(hostSettingsPath, 'utf-8')) as ClaudeSettings;
  } catch {
    // no host settings
  }

  const hookCommand = `curl -s -X POST http://localhost:5000/api/hooks/claude-done -H 'Content-Type: application/json' -d '{"email":"${email}"}'`;
  const hooks = settings.hooks ?? {};
  const stopRules = hooks.Stop ?? [];
  const hasOurHook = stopRules.some((rule) => rule.hooks?.some((h) => h.command?.includes('/api/hooks/claude-done')));

  if (!hasOurHook) {
    stopRules.push({ hooks: [{ type: 'command', command: hookCommand }] });
  }

  hooks.Stop = stopRules;
  settings.hooks = hooks;
  settings.defaultMode = 'bypassPermissions';
  settings.skipDangerousModePermissionPrompt = true;

  const contextDir = join(DATA_PATH, email, '.container-context');
  mkdirSync(contextDir, { recursive: true });
  const filePath = join(contextDir, 'settings.json');
  writeFileSync(filePath, JSON.stringify(settings, null, 2));

  // Pre-seed trust and skip-permissions in .claude.json so interactive Claude Code skips all prompts
  if (username) {
    const homeDir = getHomeDir(email);
    const claudeJsonPath = join(homeDir, '.claude.json');
    let claudeJson: Record<string, unknown> = {};
    try {
      claudeJson = JSON.parse(readFileSync(claudeJsonPath, 'utf-8')) as Record<string, unknown>;
    } catch {
      // no existing config
    }
    const projects = (claudeJson.projects ?? {}) as Record<string, Record<string, unknown>>;
    const projectKey = homeDir;
    if (!projects[projectKey]) projects[projectKey] = {};
    projects[projectKey]!.hasTrustDialogAccepted = true;
    claudeJson.projects = projects;
    writeFileSync(claudeJsonPath, JSON.stringify(claudeJson, null, 2));
  }

  return filePath;
}
