import { NextRequest, NextResponse } from 'next/server';
import fs from 'fs/promises';
import path from 'path';
import matter from 'gray-matter';
import { getIdeaMotriz, getPersonajes } from '@/lib/file-service';
import type { Personaje, PersonajeEnPlano, PlanoEscaleta, PreEscaleta, EmotionVariant } from '@/types/project';

const PROJECTS_DIR = path.join(process.cwd(), 'projects');

const VALID_EMOTIONS: EmotionVariant[] = ['alegria', 'tristeza', 'sorpresa', 'miedo', 'enfado', 'neutral'];

async function findCapDir(capitulosDir: string, numero: string) {
  const dirs = await fs.readdir(capitulosDir, { withFileTypes: true });
  return dirs.find(d =>
    d.isDirectory() && d.name.startsWith(numero.padStart(2, '0'))
  );
}

/** Validate and fix personajesDetalle IDs against real personajes list */
function normalizePlanos(planos: any[], personajes: Personaje[]): PlanoEscaleta[] {
  const byId = new Map(personajes.map(p => [p.id, p]));
  const byName = new Map(personajes.map(p => [p.nombre.toLowerCase(), p]));

  return planos.map((plano) => {
    let detalle: PersonajeEnPlano[] = [];

    if (Array.isArray(plano.personajesDetalle)) {
      detalle = plano.personajesDetalle.map((pd: any) => {
        // Try to resolve the personaje by ID first, then by name
        let persona = byId.get(pd.personajeId) || byName.get((pd.nombre || '').toLowerCase());
        if (!persona) return null;
        const emocion = VALID_EMOTIONS.includes(pd.emocion) ? pd.emocion : 'neutral';
        return { personajeId: persona.id, nombre: persona.nombre, emocion } as PersonajeEnPlano;
      }).filter(Boolean) as PersonajeEnPlano[];
    }

    // Backfill personajesEnPlano from personajesDetalle
    const personajesEnPlano = detalle.length > 0
      ? detalle.map(d => d.nombre)
      : plano.personajesEnPlano || [];

    return { ...plano, personajesDetalle: detalle, personajesEnPlano };
  });
}

/** Migrate old planos that only have personajesEnPlano (string[]) but no personajesDetalle */
function migrateLegacyPlanos(planos: any[], personajes: Personaje[]): PlanoEscaleta[] {
  const byName = new Map(personajes.map(p => [p.nombre.toLowerCase(), p]));

  return planos.map((plano) => {
    if (Array.isArray(plano.personajesDetalle) && plano.personajesDetalle.length > 0) {
      return plano; // already has structured data
    }
    if (!Array.isArray(plano.personajesEnPlano) || plano.personajesEnPlano.length === 0) {
      return { ...plano, personajesDetalle: [] };
    }
    const detalle: PersonajeEnPlano[] = plano.personajesEnPlano
      .map((name: string) => {
        const persona = byName.get(name.toLowerCase());
        if (!persona) return null;
        return { personajeId: persona.id, nombre: persona.nombre, emocion: 'neutral' as EmotionVariant };
      })
      .filter(Boolean) as PersonajeEnPlano[];
    return { ...plano, personajesDetalle: detalle };
  });
}

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ slug: string; numero: string }> }
) {
  try {
    const { slug, numero } = await params;
    const capitulosDir = path.join(PROJECTS_DIR, slug, 'capitulos');
    const capDir = await findCapDir(capitulosDir, numero);
    
    if (!capDir) {
      return NextResponse.json(null);
    }
    
    const capPath = path.join(capitulosDir, capDir.name);
    const escaletaPath = path.join(capPath, 'escaleta.md');
    const planosPath = path.join(capPath, 'escaleta-planos.json');
    
    try {
      const fileContent = await fs.readFile(escaletaPath, 'utf-8');
      const { data, content } = matter(fileContent);
      let planos: any[] = [];
      try {
        const planosJson = await fs.readFile(planosPath, 'utf-8');
        planos = JSON.parse(planosJson);
      } catch { /* no planos file yet */ }

      // Migrate legacy planos: add personajesDetalle from personajesEnPlano if missing
      if (planos.length > 0 && planos.some((p: any) => !p.personajesDetalle || p.personajesDetalle.length === 0)) {
        const personajes = await getPersonajes(slug);
        planos = migrateLegacyPlanos(planos, personajes);
        // Persist migration so it only runs once
        await fs.writeFile(planosPath, JSON.stringify(planos, null, 2));
      }

      return NextResponse.json({ ...data, contenidoMarkdown: content, planos });
    } catch {
      return NextResponse.json(null);
    }
  } catch (error: any) {
    console.error('Error fetching escaleta:', error);
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
}

export async function POST(
  request: NextRequest,
  { params }: { params: Promise<{ slug: string; numero: string }> }
) {
  try {
    const { slug, numero } = await params;
    const { action, guion, contenidoMarkdown } = await request.json();

    const capitulosDir = path.join(PROJECTS_DIR, slug, 'capitulos');
    const capDir = await findCapDir(capitulosDir, numero);

    if (!capDir) {
      return NextResponse.json({ error: 'Capítulo no encontrado' }, { status: 404 });
    }

    const capPath = path.join(capitulosDir, capDir.name);
    const escaletaPath = path.join(capPath, 'escaleta.md');
    const planosPath = path.join(capPath, 'escaleta-planos.json');

    if (action === 'generate') {
      if (!guion) {
        return NextResponse.json({ error: 'Se necesita el guión conductor para generar la escaleta' }, { status: 400 });
      }
      const ideaMotriz = await getIdeaMotriz(slug);
      if (!ideaMotriz) {
        return NextResponse.json({ error: 'Primero debes crear la Idea Motriz' }, { status: 400 });
      }
      const personajes = await getPersonajes(slug);

      // Load pre-escaleta (required — defines exact plano counts per segment)
      let preEscaleta: PreEscaleta | null = null;
      try {
        const preEscaletaJson = await fs.readFile(path.join(capPath, 'pre-escaleta.json'), 'utf-8');
        preEscaleta = JSON.parse(preEscaletaJson);
      } catch { /* no pre-escaleta */ }

      if (!preEscaleta) {
        return NextResponse.json({ error: 'Primero genera la pre-escaleta para definir la estructura de planos.' }, { status: 400 });
      }

      const { generateEscaleta } = await import('@/lib/llm-service');
      const escaleta = await generateEscaleta(guion, ideaMotriz, personajes, preEscaleta);

      const { contenidoMarkdown: _ignore, planos: rawPlanos, ...frontmatterData } = escaleta as any;
      // Normalize personajesDetalle: validate IDs and backfill personajesEnPlano
      const planos = normalizePlanos(rawPlanos || [], personajes);
      const mdContent = generateEscaletaMarkdown({ ...frontmatterData, planos });
      const fileContent = matter.stringify(mdContent, frontmatterData);
      await fs.writeFile(escaletaPath, fileContent);
      // Save planos as structured JSON for downstream use (prompts generation)
      await fs.writeFile(planosPath, JSON.stringify(planos, null, 2));

      return NextResponse.json({ ...frontmatterData, contenidoMarkdown: mdContent, planos });
    }

    if (action === 'generate-stream') {
      if (!guion) {
        return NextResponse.json({ error: 'Se necesita el guión conductor para generar la escaleta' }, { status: 400 });
      }
      const ideaMotriz = await getIdeaMotriz(slug);
      if (!ideaMotriz) {
        return NextResponse.json({ error: 'Primero debes crear la Idea Motriz' }, { status: 400 });
      }
      const personajes = await getPersonajes(slug);

      let preEscaletaData: import('@/types/project').PreEscaleta | null = null;
      try {
        const preEscaletaJson = await fs.readFile(path.join(capPath, 'pre-escaleta.json'), 'utf-8');
        preEscaletaData = JSON.parse(preEscaletaJson);
      } catch { /* no pre-escaleta */ }

      if (!preEscaletaData) {
        return NextResponse.json({ error: 'Primero genera la pre-escaleta para definir la estructura de planos.' }, { status: 400 });
      }

      const preEscaletaFinal = preEscaletaData;
      const encoder = new TextEncoder();
      const stream = new ReadableStream({
        async start(controller) {
          const send = (data: any) => {
            try {
              controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`));
            } catch { /* client disconnected */ }
          };

          try {
            const { generateEscaleta } = await import('@/lib/llm-service');
            const escaletaResult = await generateEscaleta(guion, ideaMotriz, personajes, preEscaletaFinal,
              (current, total, label) => {
                send({ type: 'progress', current, total, label });
              }
            );

            const { contenidoMarkdown: _ignore, planos: rawPlanos, ...frontmatterData } = escaletaResult as any;
            const planosSaved = normalizePlanos(rawPlanos || [], personajes);
            const mdContent = generateEscaletaMarkdown({ ...frontmatterData, planos: planosSaved });
            const fileContent = matter.stringify(mdContent, frontmatterData);
            await fs.writeFile(escaletaPath, fileContent);
            await fs.writeFile(planosPath, JSON.stringify(planosSaved, null, 2));

            send({ type: 'done', result: { ...frontmatterData, contenidoMarkdown: mdContent, planos: planosSaved } });
          } catch (error: any) {
            send({ type: 'error', message: error.message });
          }

          controller.close();
        }
      });

      return new Response(stream, {
        headers: {
          'Content-Type': 'text/event-stream',
          'Cache-Control': 'no-cache',
          'X-Accel-Buffering': 'no',
        },
      });
    }

    if (action === 'save' && contenidoMarkdown !== undefined) {
      let frontmatterData: Record<string, any> = {};
      try {
        const existing = await fs.readFile(escaletaPath, 'utf-8');
        const { data } = matter(existing);
        frontmatterData = data;
      } catch { /* no existing file */ }

      const fileContent = matter.stringify(contenidoMarkdown, frontmatterData);
      await fs.writeFile(escaletaPath, fileContent);
      return NextResponse.json({ success: true });
    }

    return NextResponse.json({ error: 'Acción inválida' }, { status: 400 });
  } catch (error: any) {
    console.error('Error en escaleta:', error);
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
}

function generateEscaletaMarkdown(escaleta: any): string {
  let md = `# Escaleta: ${escaleta.capitulo}\n\n`;
  md += `**Virtud: ${escaleta.virtudGanada}** | Duración total: ${escaleta.duracionTotalSegundos}s\n\n`;
  md += `| # | Plano | Segmento | Tiempo | Personajes | Acción | Sonido |\n`;
  md += `|---|-------|----------|--------|------------|--------|--------|\n`;

  if (escaleta.planos) {
    for (let i = 0; i < escaleta.planos.length; i++) {
      const p = escaleta.planos[i];
      const personajesStr = Array.isArray(p.personajesDetalle) && p.personajesDetalle.length > 0
        ? p.personajesDetalle.map((pd: PersonajeEnPlano) => `${pd.nombre}(${pd.emocion})`).join(', ')
        : '-';
      md += `| ${i + 1} | ${p.numeroPlano} | ${p.segmentoGuion} | ${p.tiempoSegundos}s | ${personajesStr} | ${p.accionDescripcion} | ${p.indicacionesSonido} |\n`;
    }
  }

  return md;
}
