import path from 'node:path';

import { cancel, intro, isCancel, outro, select, text } from '@clack/prompts';

import { PrdService } from './service.js';
import type { CreatePrdOptions, PrdDocument, PrdSectionPatch } from './types.js';

interface WizardAnswers {
  goals: string;
  constraints: string;
  milestones: string;
}

/**
 * Translate wizard answers into section patches using the same keyword
 * matching the wizard always used (first section whose id contains the
 * keyword, then first field whose name contains it, else first field).
 */
function buildWizardPatches(doc: PrdDocument, answers: WizardAnswers): PrdSectionPatch[] {
  const bySection = new Map<string, PrdSectionPatch>();

  const add = (keyword: string, value: string): void => {
    const section = doc.sections.find((candidate) => candidate.id.includes(keyword));
    if (section === undefined) {
      return;
    }

    const fieldName =
      Object.keys(section.fields).find((field) => field.toLowerCase().includes(keyword)) ??
      Object.keys(section.fields)[0];

    if (fieldName === undefined || section.fields[fieldName] === value) {
      return;
    }

    const existing = bySection.get(section.id);
    if (existing === undefined) {
      bySection.set(section.id, { id: section.id, fields: { [fieldName]: value } });
    } else {
      existing.fields[fieldName] = value;
    }
  };

  add('goal', answers.goals);
  add('constraint', answers.constraints);
  add('milestone', answers.milestones);

  return [...bySection.values()];
}

async function promptText(message: string, initialValue = ''): Promise<string> {
  const response = await text({
    message,
    initialValue,
  });

  if (isCancel(response)) {
    cancel('PRD wizard cancelled.');
    throw new Error('PRD wizard cancelled');
  }

  return response.trim();
}

async function promptTemplate(template?: string): Promise<string> {
  if (template !== undefined && template.trim().length > 0) {
    return template;
  }

  const choice = await select({
    message: 'PRD type',
    options: [
      { value: 'software', label: 'Software project' },
      { value: 'feature', label: 'Feature' },
      { value: 'spike', label: 'Research spike' },
    ],
  });

  if (isCancel(choice)) {
    cancel('PRD wizard cancelled.');
    throw new Error('PRD wizard cancelled');
  }

  return choice;
}

/**
 * Interactive PRD wizard. All writes go through PrdService — the wizard is a
 * prompt layer, never a second writer path.
 */
export async function runPrdWizard(options: CreatePrdOptions): Promise<PrdDocument> {
  intro('Mosaic PRD wizard');

  const name =
    options.name.trim().length > 0 ? options.name.trim() : await promptText('Project name');
  const template = await promptTemplate(options.template);
  const goals = await promptText('Primary goals');
  const constraints = await promptText('Key constraints');
  const milestones = await promptText('Planned milestones');

  const service = new PrdService({ projectPath: options.projectPath });
  const doc = await service.create({
    name,
    template,
  });

  const patches = buildWizardPatches(doc, { goals, constraints, milestones });
  const updated =
    patches.length > 0 ? await service.update({ id: doc.id, sections: patches }) : doc;

  outro(`PRD created: ${path.join(updated.projectPath, 'docs', 'prdy', `${updated.id}.yaml`)}`);

  return updated;
}
