import fs from 'node:fs';
import path from 'node:path';

import type { BoardPersona, BoardSynthesis, ForgeTask, PersonaReview } from './types.js';

/**
 * Build the brief content for a persona's board evaluation.
 */
export function buildPersonaBrief(brief: string, persona: BoardPersona): string {
  return [
    `# Board Evaluation: ${persona.name}`,
    '',
    '## Your Role',
    persona.description,
    '',
    '## Brief Under Review',
    brief.trim(),
    '',
    '## Instructions',
    'Evaluate this brief from your perspective. Output a JSON object:',
    '{',
    `  "persona": "${persona.name}",`,
    '  "verdict": "approve|reject|conditional",',
    '  "confidence": 0.0-1.0,',
    '  "concerns": ["..."],',
    '  "recommendations": ["..."],',
    '  "key_risks": ["..."]',
    '}',
    '',
  ].join('\n');
}

/**
 * Write a persona brief to the run directory and return the path.
 */
export function writePersonaBrief(
  runDir: string,
  baseTaskId: string,
  persona: BoardPersona,
  brief: string,
): string {
  const briefDir = path.join(runDir, '01-board', 'briefs');
  fs.mkdirSync(briefDir, { recursive: true });

  const briefPath = path.join(briefDir, `${baseTaskId}-${persona.slug}.md`);
  fs.writeFileSync(briefPath, buildPersonaBrief(brief, persona), 'utf-8');
  return briefPath;
}

/**
 * Get the result path for a persona's board review.
 */
export function personaResultPath(runDir: string, taskId: string): string {
  return path.join(runDir, '01-board', 'results', `${taskId}.board.json`);
}

/**
 * Get the result path for the board synthesis.
 */
export function synthesisResultPath(runDir: string, taskId: string): string {
  return path.join(runDir, '01-board', 'results', `${taskId}.board.json`);
}

/**
 * Generate one ForgeTask per board persona plus one synthesis task.
 *
 * Persona tasks run independently (no depends_on).
 * The synthesis task depends on all persona tasks with 'all_terminal' policy.
 */
export function generateBoardTasks(
  brief: string,
  personas: BoardPersona[],
  runDir: string,
  baseTaskId = 'BOARD',
): ForgeTask[] {
  const tasks: ForgeTask[] = [];
  const personaTaskIds: string[] = [];
  const personaResultPaths: string[] = [];

  for (const persona of personas) {
    const taskId = `${baseTaskId}-${persona.slug}`;
    personaTaskIds.push(taskId);

    const briefPath = writePersonaBrief(runDir, baseTaskId, persona, brief);
    const resultRelPath = personaResultPath(runDir, taskId);
    personaResultPaths.push(resultRelPath);

    tasks.push({
      id: taskId,
      title: `Board review: ${persona.name}`,
      description: `Independent board evaluation for ${persona.name}.`,
      type: 'review',
      dispatch: 'exec',
      status: 'pending',
      briefPath,
      resultPath: resultRelPath,
      timeoutSeconds: 120,
      qualityGates: ['true'],
      metadata: {
        personaName: persona.name,
        personaSlug: persona.slug,
        personaPath: persona.path,
        resultOutputPath: resultRelPath,
      },
    });
  }

  // Synthesis task — merges all persona reviews
  const synthesisId = `${baseTaskId}-SYNTHESIS`;
  const synthesisResult = synthesisResultPath(runDir, synthesisId);

  tasks.push({
    id: synthesisId,
    title: 'Board synthesis',
    description: 'Merge independent board reviews into a single recommendation.',
    type: 'review',
    dispatch: 'exec',
    status: 'pending',
    briefPath: '',
    resultPath: synthesisResult,
    timeoutSeconds: 120,
    dependsOn: personaTaskIds,
    dependsOnPolicy: 'all_terminal',
    qualityGates: ['true'],
    metadata: {
      resultOutputPath: synthesisResult,
      inputResultPaths: personaResultPaths,
    },
  });

  return tasks;
}

/**
 * Merge multiple persona reviews into a board synthesis.
 */
export function synthesizeReviews(reviews: PersonaReview[]): BoardSynthesis {
  const verdicts = reviews.map((r) => r.verdict);

  let mergedVerdict: PersonaReview['verdict'];
  if (verdicts.includes('reject')) {
    mergedVerdict = 'reject';
  } else if (verdicts.includes('conditional')) {
    mergedVerdict = 'conditional';
  } else {
    mergedVerdict = 'approve';
  }

  const confidenceValues = reviews.map((r) => r.confidence);
  const avgConfidence =
    confidenceValues.length > 0
      ? Math.round((confidenceValues.reduce((a, b) => a + b, 0) / confidenceValues.length) * 1000) /
        1000
      : 0;

  const concerns = unique(reviews.flatMap((r) => r.concerns));
  const recommendations = unique(reviews.flatMap((r) => r.recommendations));
  const keyRisks = unique(reviews.flatMap((r) => r.keyRisks));

  return {
    persona: 'Board Synthesis',
    verdict: mergedVerdict,
    confidence: avgConfidence,
    concerns,
    recommendations,
    keyRisks,
    reviews,
  };
}

/** Deduplicate while preserving order. */
function unique(items: string[]): string[] {
  const seen = new Set<string>();
  const result: string[] = [];
  for (const item of items) {
    if (!seen.has(item)) {
      seen.add(item);
      result.push(item);
    }
  }
  return result;
}
