import { getEvolutionContext, recordCreation, getQualityPolicy } from '../evolution.mjs';
import { parseLLMJson } from '../json-utils.mjs';
import { listWorkspaceFiles } from '../workspace.mjs';
import { generateRefinedInstructions, refineInstructions } from '../refined-instructions.mjs';

export const name = 'build-page';
export const description = 'Build a self-contained interactive HTML page (game, tool, art)';

const META_PAGE_PATTERN = /\b(capabilities?\s+blueprint|delivery\s+protocol|loop\s*#?|operating model)\b/i;

export async function execute(ctx) {
  const topic = ctx.args?.topic;
  const growthMode = ctx.args?.growthMode;
  const domain = ctx.args?.domain;
  const connections = ctx.args?.connections || [];
  const goal = ctx.args?.goal || null;
  const userValue = ctx.args?.userValue || '';
  const evidence = Array.isArray(ctx.args?.evidence) ? ctx.args.evidence.map(e => String(e)).filter(Boolean) : [];
  const autonomyMode = ctx.args?._taskSource === 'autonomy';
  const qualityPolicy = getQualityPolicy();
  const minAlignment = Number(qualityPolicy.min_alignment_score) || 70;
  const minUsefulness = Number(qualityPolicy.min_usefulness_score) || 70;

  const evolutionContext = await getEvolutionContext();

  // Gather existing workspace files so the LLM knows what's already built
  let workspaceContext = '';
  try {
    const wsId = ctx.getActiveWorkspaceId ? ctx.getActiveWorkspaceId() : undefined;
    const files = await listWorkspaceFiles(wsId);
    if (files.length > 0) {
      const fileList = files
        .slice(0, 20)
        .map(f => `- ${f.name} (${f.size ? Math.round(f.size / 1024) + ' KB' : 'unknown size'}, modified ${String(f.modified || '').slice(0, 19)})`)
        .join('\n');
      workspaceContext = `\n## Existing Workspace Files
The user already has these files in the workspace:
${fileList}
${files.length > 20 ? `... and ${files.length - 20} more files` : ''}

IMPORTANT: Review these existing files before creating something new.
- Do NOT duplicate content that already exists.
- If the user asks for something similar to an existing file, make it distinct and complementary.
- Build on what's already there — don't start from scratch when existing work can be extended.
`;
    }
  } catch {}

  // Run the user request through the Communicator → Refiner pipeline to produce
  // high-quality, unambiguous build instructions before generating the page.
  const userRequest = topic || 'Build an interactive page that solves a concrete user problem.';
  let refinedBlock;
  try {
    const deps = { askLLM: ctx.askLLM, pickModel: ctx.pickModel };
    const communicated = await generateRefinedInstructions(userRequest, deps);
    refinedBlock = await refineInstructions(communicated, deps);
  } catch (err) {
    // If the pipeline fails, fall back to the raw topic
    refinedBlock = userRequest;
  }

  const prompt = `You are an autonomous AI agent who builds useful web experiences.
Prioritize user outcomes over novelty for novelty's sake.

${evolutionContext}
${workspaceContext}
${goal ? `Current goal: ${goal}` : ''}
${autonomyMode ? `Autonomy context:
- User value target: ${userValue || '(not provided)'}
- Evidence:
${evidence.length ? evidence.map(e => `  - ${e}`).join('\n') : '  - (none provided)'}
` : ''}

${refinedBlock}

Requirements:
- Single self-contained HTML file
- Embedded CSS and JavaScript (no external dependencies)
- Interactive and immediately usable
- Clear UX with visible controls and readable output
- Keep it concise and practical (avoid demo fluff)
- Do not create meta/process pages unless explicitly requested

- If similar files already exist in the workspace, make this one clearly different
${autonomyMode ? '- This is autonomous mode: only create a page if it delivers clear user value now.' : ''}

Respond with ONLY the HTML. Start with <!DOCTYPE html>.`;

  let html = await ctx.askLLM(prompt, { model: ctx.pickModel('build') });

  // Strip markdown code fences if the model wrapped the response.
  html = html.replace(/^```(?:html)?\s*\n?/i, '').replace(/\n?\s*```\s*$/, '').trim();

  // Defensive: extract only the HTML if the response contains tool-use reasoning
  // or other non-HTML text before the actual content (e.g. from Claude CLI agentic
  // traces leaking into the response).
  if (html && !html.startsWith('<!')) {
    const htmlMatch = html.match(/(<!DOCTYPE html[\s\S]*<\/html>)/i);
    if (htmlMatch) {
      html = htmlMatch[1];
    }
  }

  if (!html) return 'Skipped build: empty output.';

  if (autonomyMode) {
    const reviewPrompt = `You are scoring a proposed autonomous HTML deliverable.
Goal: ${goal || '(none)'}
Topic: ${topic || '(none)'}
User value target: ${userValue || '(none)'}
Evidence:
${evidence.length ? evidence.map(e => `- ${e}`).join('\n') : '- (none)'}

HTML:
${html.slice(0, 7000)}

Return JSON only:
{"alignment":0-100,"usefulness":0-100,"generic_meta":true|false,"reason":"short reason"}`;

    const reviewRaw = await ctx.askLLM(reviewPrompt, { model: ctx.pickModel('classify') });
    const reviewParsed = parseLLMJson(reviewRaw);
    const review = reviewParsed.ok ? reviewParsed.data : null;
    const alignment = Number(review?.alignment || 0);
    const usefulness = Number(review?.usefulness || 0);
    const genericMeta = !!review?.generic_meta;

    if (!review || alignment < minAlignment || usefulness < minUsefulness || genericMeta) {
      const reason = review?.reason || 'low alignment/usefulness or generic meta output';
      ctx.addEvent('system', 'agent', `Skipped autonomous build-page: ${reason}`, {
        skill: name,
        alignment,
        usefulness
      });
      return `Skipped build: ${reason}`;
    }
  }

  // Generate a filename
  const titleMatch = html.match(/<title>([^<]+)<\/title>/i);
  const rawTitle = titleMatch ? titleMatch[1] : `page-${Date.now()}`;
  if (autonomyMode && META_PAGE_PATTERN.test(rawTitle)) {
    return 'Skipped build: generated meta/process page title.';
  }
  const title = rawTitle.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 40) || `page-${Date.now()}`;
  const filename = `${title}.html`;

  const written = await ctx.writeOutputFile(filename, html);
  const actualName = written?.name || filename;

  // Record this creation in the evolution graph
  if (domain) {
    try {
      await recordCreation({
        filename: actualName,
        mode: growthMode || 'branch',
        domain,
        connections
      });
      console.log(`[evolution] Recorded: ${actualName} in domain "${domain}" (${growthMode || 'branch'} mode)`);
    } catch (err) {
      console.log(`[evolution] Failed to record creation: ${err.message}`);
    }
  }

  return `Built: ${actualName}`;
}

export default { name, description, execute };

