import { NextRequest, NextResponse } from 'next/server';
import fs from 'fs/promises';
import path from 'path';
import { loadImage, generateSceneImage, savePlanoImage, getPlanoImagePath } from '@/lib/image-service';
import type { PlanoConPrompt, ReferenceAsset, PromptComposition, FondoReferencia } from '@/types/project';

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

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'))
  );
}

/** Migrate old referenceAsset format: tposeUrl → tposeFrontUrl */
function migrateReferenceAssets(refs: any[]): ReferenceAsset[] {
  return refs.map(ref => {
    if (ref.tposeFrontUrl || !ref.tposeUrl) return ref;
    const { tposeUrl, ...rest } = ref;
    return { ...rest, tposeFrontUrl: tposeUrl };
  });
}

/** Load planos: prefer prompts-planos.json, fall back to escaleta-planos.json */
async function loadPlanos(capPath: string): Promise<{ planos: PlanoConPrompt[]; source: 'prompts' | 'escaleta' }> {
  try {
    const content = await fs.readFile(path.join(capPath, 'prompts-planos.json'), 'utf-8');
    const promptPlanos: PlanoConPrompt[] = JSON.parse(content);
    let escaletaPlanos: any[] = [];
    try {
      const esc = await fs.readFile(path.join(capPath, 'escaleta-planos.json'), 'utf-8');
      escaletaPlanos = JSON.parse(esc);
    } catch { /* ok */ }

    const promptMap = new Map(promptPlanos.map(p => [p.id, p]));
    const merged = escaletaPlanos.map((ep: any) => {
      const withPrompt = promptMap.get(ep.id);
      if (!withPrompt) return { ...ep, promptImagen: '', referenceAssets: [] };
      // Migrate old referenceAssets format
      return {
        ...withPrompt,
        referenceAssets: migrateReferenceAssets(withPrompt.referenceAssets || []),
      };
    });
    return { planos: merged.length > 0 ? merged : promptPlanos.map(p => ({
      ...p,
      referenceAssets: migrateReferenceAssets(p.referenceAssets || []),
    })), source: 'prompts' };
  } catch { /* no prompts-planos.json */ }

  try {
    const content = await fs.readFile(path.join(capPath, 'escaleta-planos.json'), 'utf-8');
    const escaletaPlanos = JSON.parse(content);
    const planos: PlanoConPrompt[] = escaletaPlanos.map((p: any) => ({
      ...p,
      promptImagen: '',
      referenceAssets: [],
    }));
    return { planos, source: 'escaleta' };
  } catch { /* no escaleta either */ }

  throw new Error('NO_PLANOS');
}

async function savePromptPlanos(capPath: string, planos: PlanoConPrompt[]): Promise<void> {
  await fs.writeFile(path.join(capPath, 'prompts-planos.json'), JSON.stringify(planos, null, 2));
}

/** Check which planos already have generated images on disk */
async function enrichWithImageStatus(
  planos: PlanoConPrompt[],
  slug: string,
  capDirName: string
): Promise<PlanoConPrompt[]> {
  return Promise.all(planos.map(async (plano) => {
    try {
      await fs.access(getPlanoImagePath(slug, capDirName, plano.id));
      return {
        ...plano,
        imagenUrl: `/api/projects/${slug}/capitulos/${capDirName}/imagenes/${plano.id}`,
      };
    } catch {
      return { ...plano, imagenUrl: undefined };
    }
  }));
}

/** Load reference images from disk for a plano: 3 T-poses + emotion per character + fondo */
async function loadReferenceImages(
  slug: string,
  capDirName: string,
  refs: ReferenceAsset[],
  fondoId?: string
): Promise<{ buffer: Buffer; label: string }[]> {
  const images: { buffer: Buffer; label: string }[] = [];

  // Load fondo reference image first (if available)
  if (fondoId) {
    const fondoPath = path.join(PROJECTS_DIR, slug, 'capitulos', capDirName, 'fondos', `${fondoId}.png`);
    try {
      const buffer = await fs.readFile(fondoPath);
      // Load fondos.json to get the fondo name
      let fondoNombre = fondoId;
      try {
        const fondosJson: FondoReferencia[] = JSON.parse(
          await fs.readFile(path.join(PROJECTS_DIR, slug, 'capitulos', capDirName, 'fondos.json'), 'utf-8')
        );
        const fondo = fondosJson.find(f => f.id === fondoId);
        if (fondo) fondoNombre = fondo.nombre;
      } catch { /* ok */ }
      images.push({ buffer, label: `Background reference for "${fondoNombre}". Use this image as inspiration for the background/environment where the action takes place. Match the atmosphere, lighting, and setting shown.` });
    } catch { /* no fondo image */ }
  }

  // Load character reference images
  for (const ref of refs) {
    // Front T-pose (also check legacy tposeUrl field)
    const frontUrl = ref.tposeFrontUrl || (ref as any).tposeUrl;
    if (frontUrl) {
      const assetId = frontUrl.split('/').pop()!;
      const buffer = await loadImage(slug, ref.personajeId, assetId);
      if (buffer) {
        images.push({ buffer, label: `${ref.nombre} - T-pose front` });
      }
    }
    // Side T-pose
    if (ref.tposeSideUrl) {
      const assetId = ref.tposeSideUrl.split('/').pop()!;
      const buffer = await loadImage(slug, ref.personajeId, assetId);
      if (buffer) {
        images.push({ buffer, label: `${ref.nombre} - T-pose side` });
      }
    }
    // Back T-pose
    if (ref.tposeBackUrl) {
      const assetId = ref.tposeBackUrl.split('/').pop()!;
      const buffer = await loadImage(slug, ref.personajeId, assetId);
      if (buffer) {
        images.push({ buffer, label: `${ref.nombre} - T-pose back` });
      }
    }
    // Emotion
    if (ref.emotionUrl) {
      const assetId = ref.emotionUrl.split('/').pop()!;
      const buffer = await loadImage(slug, ref.personajeId, assetId);
      if (buffer) {
        images.push({ buffer, label: `${ref.nombre} - ${ref.emocion}` });
      }
    }
  }

  return images;
}

/** Compose a final prompt string from sub-fields */
function composePrompt(comp: PromptComposition): string {
  const parts = [
    comp.tipoPlano,
    comp.camara,
    comp.optica,
    comp.personajes,
    comp.accion,
    comp.luz,
    comp.estilo,
    comp.custom,
  ].filter(Boolean);
  return parts.join('. ') + '.';
}

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);

    try {
      const { planos } = await loadPlanos(capPath);
      const enriched = await enrichWithImageStatus(planos, slug, capDir.name);
      const generated = enriched.filter(p => p.imagenUrl).length;
      const withPrompt = enriched.filter(p => p.promptImagen).length;
      return NextResponse.json({ planos: enriched, total: enriched.length, generated, withPrompt });
    } catch {
      return NextResponse.json(null);
    }
  } catch (error: any) {
    console.error('Error fetching imagenes:', 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, planoId, composition } = 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);

    let planos: PlanoConPrompt[];
    try {
      const result = await loadPlanos(capPath);
      planos = result.planos;
    } catch {
      return NextResponse.json(
        { error: 'No se encontraron planos. Genera la escaleta primero.' },
        { status: 400 }
      );
    }

    if (action === 'generate') {
      if (!planoId) {
        return NextResponse.json({ error: 'Se necesita planoId' }, { status: 400 });
      }

      const planoIdx = planos.findIndex(p => p.id === planoId);
      if (planoIdx === -1) {
        return NextResponse.json({ error: 'Plano no encontrado' }, { status: 404 });
      }

      const plano = planos[planoIdx];
      if (!plano.promptImagen) {
        return NextResponse.json({ error: 'Este plano no tiene prompt. Genera el prompt primero.' }, { status: 400 });
      }

      const refs = await loadReferenceImages(slug, capDir.name, plano.referenceAssets || [], plano.fondoId);

      const imageBuffer = await generateSceneImage(
        refs,
        plano.promptImagen,
        { aspectRatio: '16:9' }
      );

      const imagenUrl = await savePlanoImage(slug, capDir.name, plano.id, imageBuffer);
      planos[planoIdx] = { ...plano, imagenUrl };
      await savePromptPlanos(capPath, planos);

      return NextResponse.json({ plano: planos[planoIdx] });
    }

    if (action === 'generate-all') {
      const results: { id: string; success: boolean; error?: string }[] = [];

      for (let i = 0; i < planos.length; i++) {
        const plano = planos[i];
        if (!plano.promptImagen) {
          results.push({ id: plano.id, success: false, error: 'Sin prompt' });
          continue;
        }

        try {
          const refs = await loadReferenceImages(slug, capDir.name, plano.referenceAssets || [], plano.fondoId);
          const imageBuffer = await generateSceneImage(
            refs,
            plano.promptImagen,
            { aspectRatio: '16:9' }
          );
          const imagenUrl = await savePlanoImage(slug, capDir.name, plano.id, imageBuffer);
          planos[i] = { ...plano, imagenUrl };
          await savePromptPlanos(capPath, planos);
          results.push({ id: plano.id, success: true });
        } catch (err: any) {
          console.error(`Error generando imagen para ${plano.id}:`, err);
          results.push({ id: plano.id, success: false, error: err.message });
        }
      }

      const enriched = await enrichWithImageStatus(planos, slug, capDir.name);
      const generated = enriched.filter(p => p.imagenUrl).length;
      const withPrompt = enriched.filter(p => p.promptImagen).length;
      return NextResponse.json({ planos: enriched, total: enriched.length, generated, withPrompt, results });
    }

    if (action === 'save-composition') {
      if (!planoId || !composition) {
        return NextResponse.json({ error: 'Se necesita planoId y composition' }, { status: 400 });
      }

      const planoIdx = planos.findIndex(p => p.id === planoId);
      if (planoIdx === -1) {
        return NextResponse.json({ error: 'Plano no encontrado' }, { status: 404 });
      }

      const promptComposition: PromptComposition = composition;
      const promptImagen = composePrompt(promptComposition);

      planos[planoIdx] = { ...planos[planoIdx], promptComposition, promptImagen };
      await savePromptPlanos(capPath, planos);

      return NextResponse.json({ plano: planos[planoIdx] });
    }

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