import { GoogleGenAI } from '@google/genai';
import fs from 'fs/promises';
import path from 'path';

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

let genaiClient: GoogleGenAI | null = null;

function getGenAI(): GoogleGenAI {
  if (!genaiClient) {
    if (!process.env.GEMINI_API_KEY) {
      throw new Error('GEMINI_API_KEY no está configurada. Añádela a .env.local');
    }
    genaiClient = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
  }
  return genaiClient;
}

// ---------------------
// IMAGE STORAGE
// ---------------------

function getImagesDir(slug: string, personajeId: string): string {
  return path.join(PROJECTS_DIR, slug, 'personajes', personajeId, 'images');
}

export function getImagePath(slug: string, personajeId: string, assetId: string): string {
  return path.join(getImagesDir(slug, personajeId), `${assetId}.png`);
}

export async function saveImage(slug: string, personajeId: string, assetId: string, imageBuffer: Buffer): Promise<string> {
  const dir = getImagesDir(slug, personajeId);
  await fs.mkdir(dir, { recursive: true });
  const filePath = getImagePath(slug, personajeId, assetId);
  await fs.writeFile(filePath, imageBuffer);
  return `/api/projects/${slug}/personajes/${personajeId}/images/${assetId}`;
}

export async function loadImage(slug: string, personajeId: string, assetId: string): Promise<Buffer | null> {
  try {
    const filePath = getImagePath(slug, personajeId, assetId);
    return await fs.readFile(filePath);
  } catch {
    return null;
  }
}

// ---------------------
// TEXT-TO-IMAGE (base character)
// ---------------------

export async function generateImage(
  prompt: string,
  options?: { aspectRatio?: string }
): Promise<Buffer> {
  const ai = getGenAI();

  const response = await ai.models.generateContent({
    model: 'gemini-3-pro-image-preview',
    contents: prompt,
    config: {
      responseModalities: ['TEXT', 'IMAGE'],
      imageConfig: {
        aspectRatio: options?.aspectRatio || '1:1',
      },
    },
  });

  const candidates = response.candidates;
  if (!candidates || candidates.length === 0) {
    throw new Error('No se generó imagen: sin candidatos');
  }

  for (const part of candidates[0].content?.parts || []) {
    if (part.inlineData) {
      const buffer = Buffer.from(part.inlineData.data!, 'base64');
      return buffer;
    }
  }

  throw new Error('No se encontró imagen en la respuesta');
}

// ---------------------
// IMAGE-TO-IMAGE (variations from reference)
// ---------------------

export async function generateVariation(
  referenceImageBuffer: Buffer,
  prompt: string,
  options?: { aspectRatio?: string }
): Promise<Buffer> {
  const ai = getGenAI();
  const base64Ref = referenceImageBuffer.toString('base64');

  const referenceInstruction = `Using the character shown in the reference image as the exact visual reference (same colors, proportions, features, accessories, and art style), generate the following:\n\n${prompt}`;

  const contents = [
    {
      inlineData: {
        mimeType: 'image/png',
        data: base64Ref,
      },
    },
    { text: referenceInstruction },
  ];

  const response = await ai.models.generateContent({
    model: 'gemini-3-pro-image-preview',
    contents,
    config: {
      responseModalities: ['TEXT', 'IMAGE'],
      imageConfig: {
        aspectRatio: options?.aspectRatio || '1:1',
      },
    },
  });

  const candidates = response.candidates;
  if (!candidates || candidates.length === 0) {
    throw new Error('No se generó variación: sin candidatos');
  }

  for (const part of candidates[0].content?.parts || []) {
    if (part.inlineData) {
      return Buffer.from(part.inlineData.data!, 'base64');
    }
  }

  throw new Error('No se encontró imagen en la respuesta de variación');
}

// ---------------------
// SCENE IMAGE (multi-reference)
// ---------------------

export async function generateSceneImage(
  referenceImages: { buffer: Buffer; label: string }[],
  prompt: string,
  options?: { aspectRatio?: string }
): Promise<Buffer> {
  const ai = getGenAI();

  const contents: any[] = [];

  // Add each reference image with its label
  for (const ref of referenceImages) {
    contents.push({
      inlineData: {
        mimeType: 'image/png',
        data: ref.buffer.toString('base64'),
      },
    });
    contents.push({ text: `[Reference: ${ref.label}]` });
  }

  // Add the scene prompt
  const instruction = referenceImages.length > 0
    ? `Using the character reference images above as exact visual references (maintain their colors, proportions, features, accessories, and art style), generate the following scene:\n\n${prompt}`
    : prompt;
  contents.push({ text: instruction });

  const response = await ai.models.generateContent({
    model: 'gemini-3-pro-image-preview',
    contents,
    config: {
      responseModalities: ['TEXT', 'IMAGE'],
      imageConfig: {
        aspectRatio: options?.aspectRatio || '16:9',
      },
    },
  });

  const candidates = response.candidates;
  if (!candidates || candidates.length === 0) {
    throw new Error('No se generó imagen de escena: sin candidatos');
  }

  for (const part of candidates[0].content?.parts || []) {
    if (part.inlineData) {
      return Buffer.from(part.inlineData.data!, 'base64');
    }
  }

  throw new Error('No se encontró imagen en la respuesta de escena');
}

// ---------------------
// PLANO IMAGE STORAGE
// ---------------------

function getPlanoImagesDir(slug: string, capDir: string): string {
  return path.join(PROJECTS_DIR, slug, 'capitulos', capDir, 'imagenes');
}

export function getPlanoImagePath(slug: string, capDir: string, planoId: string): string {
  return path.join(getPlanoImagesDir(slug, capDir), `${planoId}.png`);
}

export async function savePlanoImage(slug: string, capDir: string, planoId: string, imageBuffer: Buffer): Promise<string> {
  const dir = getPlanoImagesDir(slug, capDir);
  await fs.mkdir(dir, { recursive: true });
  const filePath = getPlanoImagePath(slug, capDir, planoId);
  await fs.writeFile(filePath, imageBuffer);
  // capDir is e.g. "01" — use it directly as numero in the URL (findCapDir handles padding)
  return `/api/projects/${slug}/capitulos/${capDir}/imagenes/${planoId}`;
}

export async function loadPlanoImage(slug: string, capDir: string, planoId: string): Promise<Buffer | null> {
  try {
    const filePath = getPlanoImagePath(slug, capDir, planoId);
    return await fs.readFile(filePath);
  } catch {
    return null;
  }
}
