import { readdir, readFile, writeFile, mkdir } from 'fs/promises';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import { pathToFileURL } from 'url';
import { existsSync } from 'fs';

const __dirname = dirname(fileURLToPath(import.meta.url));
const SKILLS_DIR = __dirname;

export const name = 'self-improve';
export const description = 'Create new skills, CLI tools, or automation scripts based on what the user needs';

export async function execute(ctx) {
  const request = ctx.args?.topic || ctx.args?.task || ctx.args?.target || '';

  // Read existing skills to understand what we already have
  const files = await readdir(SKILLS_DIR);
  const skillFiles = files.filter(f => f.endsWith('.mjs') && f !== 'self-improve.mjs');

  let skillDescriptions = '';
  for (const file of skillFiles) {
    try {
      const content = await readFile(join(SKILLS_DIR, file), 'utf-8');
      const nameMatch = content.match(/export const name = ['"]([^'"]+)['"]/);
      const descMatch = content.match(/export const description = ['"]([^'"]+)['"]/);
      skillDescriptions += `- ${nameMatch?.[1] || file}: ${descMatch?.[1] || 'no description'}\n`;
    } catch {}
  }

  // Check for existing CLI tools in workspace
  const { getWorkspaceRoot } = await import('../workspace.mjs');
  const wsRoot = getWorkspaceRoot();
  const toolsDir = join(wsRoot, 'tools');
  let existingTools = '';
  try {
    if (existsSync(toolsDir)) {
      const toolFiles = await readdir(toolsDir);
      existingTools = toolFiles.map(f => `  - tools/${f}`).join('\n');
    }
  } catch {}

  // Get recent events for context
  const { getEvents } = await import('../db.mjs');
  const recentEvents = getEvents({ limit: 20 });
  const eventLog = recentEvents.reverse().map(e =>
    `[${e.type}] ${e.content.slice(0, 100)}`
  ).join('\n');

  const prompt = `You are an autonomous AI agent that can improve itself by writing new skills and CLI tools.

User request: "${request}"

Current skills:
${skillDescriptions}

${existingTools ? `Existing CLI tools in workspace:\n${existingTools}\n` : ''}
Recent activity:
${eventLog || '(none yet)'}

Your job: Create ONE new skill that fulfills the user's request or fills a capability gap.

## Skill Architecture

A skill is an ESM module in the skills/ directory. It can optionally create a CLI tool (Node.js or Python script) in the workspace tools/ directory that the skill invokes.

### Pattern A: Simple skill (LLM-only)
Use when the task only needs LLM reasoning (analysis, writing, summarization).

### Pattern B: Skill + CLI tool (for real-world actions)
Use when the task needs system interaction (APIs, file processing, data fetching, etc.).
The skill writes a CLI script to workspace/tools/, then calls it via ctx.askLLM with rawCompletion:false to use the agentic tool loop (which has Bash access).

## ctx API:
- ctx.askLLM(prompt, { model, rawCompletion }) — call the LLM. Set rawCompletion:false to enable the agentic tool loop with Bash/Read/Write/Grep access
- ctx.pickModel(taskType) — get model name ('build' for complex, 'chat' for simple)
- ctx.remember(key, content, category) — store a memory
- ctx.recall(key) — retrieve a memory
- ctx.addEvent(type, source, content, metadata?) — log an event
- ctx.writeOutputFile(filename, content) — write file to workspace
- ctx.args — { topic, task, target, ... }

## Example: Skill with CLI tool

\`\`\`javascript
import { writeFile, mkdir } from 'fs/promises';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import { existsSync } from 'fs';

const __dirname = dirname(fileURLToPath(import.meta.url));

export const name = 'example-tool';
export const description = 'Does something useful via a CLI tool';

export async function execute(ctx) {
  // Ensure tools directory exists
  const { getWorkspaceRoot } = await import('../workspace.mjs');
  const toolsDir = join(getWorkspaceRoot(), 'tools');
  if (!existsSync(toolsDir)) await mkdir(toolsDir, { recursive: true });

  const toolPath = join(toolsDir, 'example-tool.mjs');

  // Write the CLI tool if it doesn't exist yet
  if (!existsSync(toolPath)) {
    const toolCode = \`#!/usr/bin/env node
// CLI tool: example-tool
// Usage: node tools/example-tool.mjs [args]
const args = process.argv.slice(2);
// ... tool logic here ...
console.log(JSON.stringify({ success: true, data: result }));
\`;
    await writeFile(toolPath, toolCode, 'utf-8');
    ctx.addEvent('skill', 'agent', 'Created CLI tool: tools/example-tool.mjs');
  }

  // Use the agentic loop to run the tool and process results
  const result = await ctx.askLLM(\`Run the tool at \${toolPath} and process the output.
Use the Bash tool to execute: node \${toolPath}
Then summarize the results for the user.\`, {
    model: ctx.pickModel('build'),
    rawCompletion: false  // enables Bash/Read/Write tools
  });

  return result;
}
\`\`\`

## Rules:
- Write ONLY the JavaScript module code. No explanation, no markdown fences.
- Start with import statements or export const.
- The skill must export: name (string), description (string), execute(ctx) async function.
- If the skill needs external APIs or system interaction, use Pattern B (create a CLI tool).
- The CLI tool should be a standalone Node.js (.mjs) or Python (.py) script.
- CLI tools go in the workspace tools/ directory, NOT in the skills/ directory.
- Use rawCompletion: false when the skill needs to execute bash commands.
- Keep it practical and focused on the user's actual request.`;

  const code = await ctx.askLLM(prompt, { model: ctx.pickModel('self-improve') });

  // Clean markdown fences if present
  const cleanCode = code
    .replace(/^```[\w]*\s*\n?/i, '')
    .replace(/\n?\s*```\s*$/i, '')
    .trim();

  // Validate: must have required exports
  if (!cleanCode.includes('export const name') || !cleanCode.includes('export async function execute')) {
    ctx.addEvent('error', 'system', 'Self-improve: generated code missing required exports');
    return 'Generated skill was invalid (missing exports).';
  }

  // Extract the skill name from the generated code
  const nameMatch = cleanCode.match(/export const name = ['"]([^'"]+)['"]/);
  const skillName = nameMatch ? nameMatch[1] : `skill-${Date.now()}`;
  const filename = `${skillName.replace(/[^a-z0-9-]/g, '-')}.mjs`;

  // Write the new skill
  await writeFile(join(SKILLS_DIR, filename), cleanCode, 'utf-8');

  // Validate by trying to import it
  try {
    const mod = await import(pathToFileURL(join(SKILLS_DIR, filename)).href + `?t=${Date.now()}`);
    const skill = mod.default || mod;
    if (!skill.name || !skill.execute) {
      const { unlink } = await import('fs/promises');
      await unlink(join(SKILLS_DIR, filename));
      ctx.addEvent('error', 'system', 'Self-improve validation failed: skill missing name or execute export. File deleted.');
      return 'Generated skill was invalid (missing exports) and was removed.';
    }
  } catch (importErr) {
    const { unlink } = await import('fs/promises');
    await unlink(join(SKILLS_DIR, filename));
    ctx.addEvent('error', 'system', `Self-improve validation failed: ${importErr.message}. File deleted.`);
    return `Generated skill had errors and was removed: ${importErr.message}`;
  }

  ctx.addEvent('skill', 'agent', `Self-improvement: created new skill "${skillName}" (${filename})`, {
    skill: 'self-improve',
    created_skill: skillName,
    filename
  });

  // Trigger a skill reload
  const { reloadSkills } = await import('../skills.mjs');
  await reloadSkills();

  return `Created new skill: ${skillName}`;
}

export default { name, description, execute };
