/**
 * POST /api/storyboard/gptimage-prompts
 *
 * Menerima scenes dari storyboard yang sudah di-generate,
 * lalu menghasilkan satu GPT Image prompt per scene dalam satu AI call.
 *
 * Response:
 *   { success: true, data: GptImagePromptsOutput }
 */

import { NextRequest, NextResponse } from "next/server";
import { createClient } from "@/lib/supabase/server";
import { generatePrompt } from "@/lib/ai/provider";
import { checkRateLimit } from "@/lib/rate-limit";
import { resolveUserEnvVarsCached, hasAnyAiKey } from "@/lib/env-vars-resolver";
import { checkAndIncrementUsage } from "@/lib/usage-quota";
import { calcEstimatedCost } from "@/lib/model-costs";
import { isCsrfSafe, csrfForbiddenPayload } from "@/lib/csrf";
import type {
  GptImagePromptsRequest,
  GptImagePromptsOutput,
  GptImageScenePrompt,
  StoryboardScene,
} from "@/types/storyboard";
import { STORYBOARD_STYLES } from "@/types/storyboard";

export const maxDuration = 60;

// Aspect ratio → human label mapping
const ASPECT_LABELS: Record<string, string> = {
  "1:1":  "Square (1:1)",
  "16:9": "Landscape (16:9)",
  "9:16": "Portrait / Reels (9:16)",
  "4:3":  "Standard (4:3)",
  "3:4":  "Portrait (3:4)",
};

export async function POST(request: NextRequest) {
  try {
    // BUG-13 FIX: CSRF check
    if (!isCsrfSafe(request)) {
      return NextResponse.json(csrfForbiddenPayload(), { status: 403 });
    }

    // ── Auth ──────────────────────────────────────────────────────────────────
    const supabase = createClient();
    const { data: { user }, error: authError } = await supabase.auth.getUser();
    if (authError || !user) {
      return NextResponse.json({ success: false, error: "Unauthorized" }, { status: 401 });
    }

    // ── Rate limit ────────────────────────────────────────────────────────────
    const rateLimit = await checkRateLimit(user.id);
    if (!rateLimit.allowed) {
      return NextResponse.json(
        { success: false, error: "Rate limit exceeded. Coba lagi dalam 1 menit." },
        { status: 429 }
      );
    }

    // ── Resolve API keys ──────────────────────────────────────────────────────
    const resolvedVars = await resolveUserEnvVarsCached(supabase, user.id);

    if (!hasAnyAiKey(resolvedVars)) {
      return NextResponse.json(
        {
          success: false,
          error: "Belum ada AI API key. Tambahkan di Settings → API Keys.",
          redirectTo: "/settings",
        },
        { status: 402 }
      );
    }

    // ── Atomic quota check + pre-increment ───────────────────────────────────
    const quotaResult = await checkAndIncrementUsage(supabase, user.id, 1);
    if (quotaResult === "quota_exceeded") {
      return NextResponse.json(
        { success: false, error: "Kuota habis. Upgrade plan untuk lebih banyak generasi." },
        { status: 403 }
      );
    }

    // ── Parse body ────────────────────────────────────────────────────────────
    const body = (await request.json()) as Partial<GptImagePromptsRequest>;

    const {
      scenes       = [],
      style        = "cinematic",
      language     = "id",
      aspectRatio  = "16:9",
      quality      = "hd",
      extraContext = "",
    } = body;

    if (!Array.isArray(scenes) || scenes.length === 0) {
      return NextResponse.json(
        { success: false, error: "Scenes tidak boleh kosong." },
        { status: 400 }
      );
    }

    if (scenes.length > 20) {
      return NextResponse.json(
        { success: false, error: "Maksimal 20 scene per request." },
        { status: 400 }
      );
    }

    // ── Build prompts ─────────────────────────────────────────────────────────
    const styleInfo   = STORYBOARD_STYLES[style as keyof typeof STORYBOARD_STYLES];
    const langLabel   = language === "id" ? "Bahasa Indonesia" : "English";
    const arLabel     = ASPECT_LABELS[aspectRatio] ?? aspectRatio;

    const scenesJson = scenes
      .map((s: StoryboardScene) =>
        JSON.stringify({
          sceneNumber:        s.sceneNumber,
          title:              s.title,
          narration:          s.narration,
          visualDescription:  s.visualDescription,
          cameraAngle:        s.cameraAngle ?? null,
          emotion:            s.emotion ?? null,
          duration:           s.duration,
        })
      )
      .join("\n");

    const systemPrompt = `You are a world-class AI image prompt engineer specializing in GPT Image (DALL-E 3 / gpt-image-2) prompts for cinematic storyboard visualization.

Your task: given a list of storyboard scenes, generate ONE highly detailed image generation prompt per scene that is optimized for GPT Image.

RULES:
1. Each prompt must be self-contained — include subject, composition, lighting, color palette, style, and mood
2. Be specific about visual elements: textures, depth of field, lens type, time of day, atmosphere
3. Do NOT include motion or time-based language ("moving", "transitioning", "pan") — these are STILL images
4. Mirror the storyboard style: ${styleInfo?.label ?? style} — ${styleInfo?.description ?? ""}
5. Aspect ratio context: ${arLabel} — frame composition accordingly
6. Quality target: ${quality === "hd" ? "ultra high detail, photorealistic or high-fidelity illustration" : "clean, balanced composition"}
7. Output MUST be valid JSON — no text outside the JSON block
8. "compositionNote" and "colorMood" should be in ${langLabel}; "prompt" and "negativeHint" in English
${extraContext ? `9. Storyboard context: ${extraContext}` : ""}

OUTPUT FORMAT:
{
  "scenePrompts": [
    {
      "sceneNumber": 1,
      "title": "scene title here",
      "prompt": "Full detailed image prompt in English, optimized for GPT Image...",
      "negativeHint": "Elements to avoid (not an official DALL-E param — note for reference): ...",
      "compositionNote": "Catatan singkat tentang komposisi dan sudut kamera dalam ${langLabel}",
      "colorMood": "Palet warna dan mood dominan dalam ${langLabel}"
    }
  ]
}`;

    const userPrompt = `Generate GPT Image prompts for each of the following ${scenes.length} storyboard scenes.
Style: ${styleInfo?.label ?? style}
Aspect Ratio: ${arLabel}
Quality: ${quality}

SCENES:
${scenesJson}

Important: Return EXACTLY ${scenes.length} prompts, one per scene, in the same order.`;

    // ── Generate with retry ───────────────────────────────────────────────────
    const MAX_RETRIES = 2;
    let rawOutput  = "";
    let model      = "unknown";
    let provider   = "unknown";
    let lastError: Error | null = null;
    let tokenUsage: { promptTokens: number; completionTokens: number; totalTokens: number } | undefined;

    for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
      try {
        const response = await generatePrompt(
          [
            { role: "system", content: systemPrompt },
            { role: "user",   content: userPrompt },
          ],
          { temperature: 0.75, maxTokens: 8000 },
          resolvedVars
        );
        rawOutput  = response.content;
        model      = response.model;
        provider   = response.provider;
        tokenUsage = response.usage; // capture token usage
        lastError  = null;
        break;
      } catch (e) {
        lastError = e as Error;
        if (attempt < MAX_RETRIES) {
          await new Promise((r) => setTimeout(r, 1000 * (attempt + 1)));
        }
      }
    }

    if (lastError) {
      return NextResponse.json(
        { success: false, error: lastError.message },
        { status: 500 }
      );
    }

    // ── Parse output ──────────────────────────────────────────────────────────
    let parsed: { scenePrompts?: GptImageScenePrompt[] };
    try {
      const cleaned = rawOutput
        .replace(/^```(?:json)?\s*/i, "")
        .replace(/\s*```$/i, "")
        .trim();
      parsed = JSON.parse(cleaned);
    } catch {
      const match = rawOutput.match(/\{[\s\S]*\}/);
      if (!match) {
        return NextResponse.json(
          { success: false, error: "AI menghasilkan output tidak valid. Coba lagi." },
          { status: 500 }
        );
      }
      try {
        parsed = JSON.parse(match[0]);
      } catch {
        return NextResponse.json(
          { success: false, error: "Gagal memparse output AI. Coba lagi." },
          { status: 500 }
        );
      }
    }

    if (!Array.isArray(parsed.scenePrompts) || parsed.scenePrompts.length === 0) {
      return NextResponse.json(
        { success: false, error: "AI tidak mengembalikan prompt yang valid. Coba lagi." },
        { status: 500 }
      );
    }

    // Enrich each prompt with aspect ratio & quality fields
    const enriched: GptImageScenePrompt[] = parsed.scenePrompts.map((sp) => ({
      ...sp,
      aspectRatio,
      quality,
    }));

    const output: GptImagePromptsOutput = {
      scenePrompts:    enriched,
      storyboardStyle: style,
      metadata: {
        generatedAt: new Date().toISOString(),
        model:       `${provider}/${model}`,
        aspectRatio,
        quality,
        totalScenes: enriched.length,
      },
    };

    // ── Log token cost — quota sudah di-increment atomic di atas ─────────────
    const estimatedCostUsd = calcEstimatedCost(provider, model, tokenUsage ?? null);

    if (tokenUsage) {
      await supabase.from("usage_logs").insert({
        user_id:  user.id,
        action:   "gptimage_prompts",
        platform: "storyboard",
        metadata: {
          model,
          provider,
          scene_count:  enriched.length,
          aspect_ratio: aspectRatio,
          quality,
        },
        prompt_tokens:      tokenUsage.promptTokens,
        completion_tokens:  tokenUsage.completionTokens,
        total_tokens:       tokenUsage.totalTokens,
        estimated_cost_usd: estimatedCostUsd,
      });
    }

    return NextResponse.json(
      { success: true, data: output },
      { headers: { "X-RateLimit-Remaining": String(rateLimit.remaining) } }
    );
  } catch (error) {
    console.error("[gptimage-prompts]", error);
    return NextResponse.json(
      { success: false, error: "Internal server error" },
      { status: 500 }
    );
  }
}
