#!/usr/bin/env npx tsx
/**
 * Presentation Generator
 *
 * Reads YAML slide data and generates:
 * 1. Mermaid sequence diagrams (.mmd) for sequence slides
 * 2. JSON for Reveal.js slides
 *
 * Usage: npx tsx scripts/generate.ts data/agile-agent-team.yaml
 */

import * as fs from 'fs';
import * as path from 'path';
import * as yaml from 'yaml';

interface Actor {
  id: string;
  label: string;
  description: string;
  color: string;
}

interface Step {
  id: string;
  from: string;
  to: string;
  action: string;
  label: string;
  note?: string;
  callout?: string;
  danger?: boolean;
  warning?: boolean;
  success?: boolean;
}

interface TitleSlide {
  type: 'title';
  id: string;
}

interface HookSlide {
  type: 'hook';
  id: string;
  line: string;
}

interface ProblemSlide {
  type: 'problem';
  id: string;
  title: string;
  points: string[];
}

interface SectionTitleSlide {
  type: 'section-title';
  id: string;
  title: string;
  subtitle: string;
  description: string;
}

interface SequenceSlide {
  type: 'sequence';
  id: string;
  title: string;
  actors: string[];
  steps: Step[];
}

interface InsightSlide {
  type: 'insight';
  id: string;
  title: string;
  points: string[];
}

interface VisionSlide {
  type: 'vision';
  id: string;
  title: string;
  points: string[];
  tagline?: string;
}

type Slide = TitleSlide | HookSlide | ProblemSlide | SectionTitleSlide | SequenceSlide | InsightSlide | VisionSlide;

interface PresentationData {
  meta: {
    id: string;
    title: string;
    subtitle: string;
    version: string;
  };
  actors: Record<string, Actor>;
  slides: Slide[];
  annotations: Record<string, {
    color: string;
    label: string;
    icon: string;
  }>;
}

// Generate Mermaid sequence diagram for a sequence slide
function generateMermaid(data: PresentationData, sequence: SequenceSlide): string {
  const lines: string[] = [];

  lines.push('sequenceDiagram');
  lines.push(`    %% ${sequence.title}`);
  lines.push('');

  // Collect unique actors used in this sequence
  const usedActors = new Set<string>();
  for (const step of sequence.steps) {
    usedActors.add(step.from);
    usedActors.add(step.to);
  }

  // Add participant declarations
  for (const actorKey of usedActors) {
    const actor = data.actors[actorKey];
    if (actor) {
      lines.push(`    participant ${actor.id} as ${actor.label}`);
    }
  }
  lines.push('');

  // Add steps
  for (const step of sequence.steps) {
    const fromActor = data.actors[step.from];
    const toActor = data.actors[step.to];

    if (!fromActor || !toActor) continue;

    // Determine arrow style
    let arrow = '->>';
    if (step.action === 'response') {
      arrow = '-->>';
    }

    // Add the message
    const label = step.label.replace(/"/g, "'");
    lines.push(`    ${fromActor.id}${arrow}${toActor.id}: ${label}`);

    // Add note if present
    if (step.note) {
      const noteText = step.note.replace(/"/g, "'");
      const position = step.from === step.to ? 'over' : 'right of';
      const noteActor = step.from === step.to ? fromActor.id : toActor.id;

      if (step.danger) {
        lines.push(`    Note ${position} ${noteActor}: ⚠️ ${noteText}`);
      } else if (step.success) {
        lines.push(`    Note ${position} ${noteActor}: ✓ ${noteText}`);
      } else {
        lines.push(`    Note ${position} ${noteActor}: ${noteText}`);
      }
    }

    lines.push('');
  }

  return lines.join('\n');
}

// Generate JSON for Reveal.js - pass through slides with actor resolution
function generateRevealJson(data: PresentationData): object {
  return {
    meta: data.meta,
    actors: data.actors,
    annotations: data.annotations,
    slides: data.slides,
  };
}

// Main
function main() {
  const args = process.argv.slice(2);
  if (args.length < 1) {
    console.error('Usage: npx tsx scripts/generate.ts <input.yaml>');
    process.exit(1);
  }

  const inputPath = path.resolve(args[0]);
  const inputDir = path.dirname(inputPath);
  const baseName = path.basename(inputPath, '.yaml');

  // Read and parse YAML
  let data: PresentationData;
  try {
    const yamlContent = fs.readFileSync(inputPath, 'utf-8');
    data = yaml.parse(yamlContent) as PresentationData;
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    console.error(`Failed to read/parse ${inputPath}: ${message}`);
    process.exit(1);
  }

  // Validate required fields
  if (!data.meta || !data.actors || !data.slides) {
    console.error('Invalid presentation data: missing required fields (meta, actors, slides)');
    process.exit(1);
  }

  // Output directory
  const outputDir = path.resolve(inputDir, '..', 'generated');
  fs.mkdirSync(outputDir, { recursive: true });

  // Find all sequence slides
  const sequenceSlides = data.slides.filter((s): s is SequenceSlide => s.type === 'sequence');

  try {
    // Generate Mermaid for each sequence
    for (const sequence of sequenceSlides) {
      const mermaid = generateMermaid(data, sequence);
      const mermaidPath = path.join(outputDir, `${baseName}-${sequence.id}.mmd`);
      fs.writeFileSync(mermaidPath, mermaid);
      console.log(`Generated: ${mermaidPath}`);
    }

    // Generate combined Mermaid
    if (sequenceSlides.length > 0) {
      const allMermaid = sequenceSlides
        .map(seq => generateMermaid(data, seq))
        .join('\n\n---\n\n');
      const combinedMermaidPath = path.join(outputDir, `${baseName}.mmd`);
      fs.writeFileSync(combinedMermaidPath, allMermaid);
      console.log(`Generated: ${combinedMermaidPath}`);
    }

    // Generate JSON for Reveal.js
    const revealJson = generateRevealJson(data);
    const jsonPath = path.join(outputDir, `${baseName}.json`);
    fs.writeFileSync(jsonPath, JSON.stringify(revealJson, null, 2));
    console.log(`Generated: ${jsonPath}`);
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    console.error(`Failed to write output files: ${message}`);
    process.exit(1);
  }
}

main();
