import { NextRequest, NextResponse } from 'next/server';
import fs from 'fs/promises';
import path from 'path';
import { getPersonajes } from '@/lib/file-service';
import { generateCharacterAssetPrompts } from '@/lib/llm-service';
import { generateImage, generateVariation, saveImage, loadImage } from '@/lib/image-service';
import type { CharacterAsset, CharacterAssetsData } from '@/types/project';

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

function getAssetsPath(slug: string, personajeId: string): string {
  return path.join(PROJECTS_DIR, slug, 'personajes', personajeId, 'assets.json');
}

function ensureBaseFlag(data: CharacterAssetsData): boolean {
  if (data.assets.some(a => a.isBase)) return false;
  const base = data.assets.find(a => a.type === 'tpose' && a.variant === 'front');
  if (base) {
    base.isBase = true;
    return true;
  }
  return false;
}

async function getData(slug: string, personajeId: string): Promise<CharacterAssetsData> {
  try {
    const content = await fs.readFile(getAssetsPath(slug, personajeId), 'utf-8');
    const parsed = JSON.parse(content);
    // Migrate old format (plain array) to new format
    let data: CharacterAssetsData;
    if (Array.isArray(parsed)) {
      data = { assets: parsed, baseLocked: false };
    } else {
      data = parsed;
    }
    // Ensure isBase flag is set; persist fix if data was modified
    const modified = ensureBaseFlag(data);
    if (modified) {
      await saveData(slug, personajeId, data);
    }
    return data;
  } catch {
    return { assets: [], baseLocked: false };
  }
}

async function saveData(slug: string, personajeId: string, data: CharacterAssetsData): Promise<void> {
  const assetsDir = path.join(PROJECTS_DIR, slug, 'personajes', personajeId);
  await fs.mkdir(assetsDir, { recursive: true });
  await fs.writeFile(getAssetsPath(slug, personajeId), JSON.stringify(data, null, 2));
}

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ slug: string; id: string }> }
) {
  try {
    const { slug, id } = await params;
    const data = await getData(slug, id);
    return NextResponse.json(data);
  } catch (error: any) {
    console.error('Error fetching assets:', error);
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
}

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

    // 1. Generate text prompts via LLM
    if (action === 'generate-prompts') {
      const personajes = await getPersonajes(slug);
      const personaje = personajes.find(p => p.id === id);
      if (!personaje) {
        return NextResponse.json({ error: 'Personaje no encontrado' }, { status: 404 });
      }
      const assets = await generateCharacterAssetPrompts(personaje);
      // Mark first tpose-front as the base
      const base = assets.find(a => a.type === 'tpose' && a.variant === 'front');
      if (base) base.isBase = true;
      const data: CharacterAssetsData = { assets, baseLocked: false };
      await saveData(slug, id, data);
      return NextResponse.json(data);
    }

    // 2. Generate base image (text-to-image)
    if (action === 'generate-base-image') {
      const { prompt: customPrompt } = body;
      const data = await getData(slug, id);
      let baseAsset = data.assets.find(a => a.isBase);
      if (!baseAsset) {
        baseAsset = data.assets.find(a => a.type === 'tpose' && a.variant === 'front');
      }
      if (!baseAsset) {
        return NextResponse.json({ error: 'No hay asset base definido. Genera los prompts primero.' }, { status: 400 });
      }
      const prompt = customPrompt || baseAsset.prompt;
      baseAsset.status = 'generating';
      await saveData(slug, id, data);

      const imageBuffer = await generateImage(prompt);
      const imageUrl = await saveImage(slug, id, baseAsset.id, imageBuffer);
      baseAsset.imageUrl = imageUrl;
      baseAsset.prompt = prompt;
      baseAsset.status = 'generated';
      data.baseLocked = false;
      await saveData(slug, id, data);
      return NextResponse.json(data);
    }

    // 3. Lock the base image as canonical reference
    if (action === 'lock-base') {
      const data = await getData(slug, id);
      const baseAsset = data.assets.find(a => a.isBase);
      if (!baseAsset || baseAsset.status !== 'generated') {
        return NextResponse.json({ error: 'Primero genera la imagen base.' }, { status: 400 });
      }
      data.baseLocked = true;
      await saveData(slug, id, data);
      return NextResponse.json(data);
    }

    // 4. Generate a single variation from base reference
    if (action === 'generate-variation') {
      const { assetId } = body;
      if (!assetId) {
        return NextResponse.json({ error: 'Se necesita assetId' }, { status: 400 });
      }
      const data = await getData(slug, id);
      if (!data.baseLocked) {
        return NextResponse.json({ error: 'Primero fija la imagen base.' }, { status: 400 });
      }
      const baseAsset = data.assets.find(a => a.isBase);
      const targetAsset = data.assets.find(a => a.id === assetId);
      if (!baseAsset || !targetAsset) {
        return NextResponse.json({ error: 'Asset no encontrado' }, { status: 404 });
      }
      const refImage = await loadImage(slug, id, baseAsset.id);
      if (!refImage) {
        return NextResponse.json({ error: 'Imagen base no encontrada en disco' }, { status: 400 });
      }
      targetAsset.status = 'generating';
      await saveData(slug, id, data);

      const imageBuffer = await generateVariation(refImage, targetAsset.prompt);
      const imageUrl = await saveImage(slug, id, targetAsset.id, imageBuffer);
      targetAsset.imageUrl = imageUrl;
      targetAsset.status = 'generated';
      await saveData(slug, id, data);
      return NextResponse.json(data);
    }

    // 5. Generate all remaining variations
    if (action === 'generate-all-variations') {
      const data = await getData(slug, id);
      if (!data.baseLocked) {
        return NextResponse.json({ error: 'Primero fija la imagen base.' }, { status: 400 });
      }
      const baseAsset = data.assets.find(a => a.isBase);
      if (!baseAsset) {
        return NextResponse.json({ error: 'No hay asset base' }, { status: 400 });
      }
      const refImage = await loadImage(slug, id, baseAsset.id);
      if (!refImage) {
        return NextResponse.json({ error: 'Imagen base no encontrada en disco' }, { status: 400 });
      }

      const pending = data.assets.filter(a => !a.isBase && a.status !== 'generated');
      for (const asset of pending) {
        try {
          asset.status = 'generating';
          await saveData(slug, id, data);
          const imageBuffer = await generateVariation(refImage, asset.prompt);
          const imageUrl = await saveImage(slug, id, asset.id, imageBuffer);
          asset.imageUrl = imageUrl;
          asset.status = 'generated';
          await saveData(slug, id, data);
        } catch (err: any) {
          console.error(`Error generando variación ${asset.id}:`, err);
          asset.status = 'prompt_ready';
          await saveData(slug, id, data);
        }
      }
      return NextResponse.json(data);
    }

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