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 { isCsrfSafe, csrfForbiddenPayload } from "@/lib/csrf";
import { extractUrlContent } from "@/lib/url-extractor";
import type { StoryboardRequest, StoryboardOutput, StoryboardScene } from "@/types/storyboard";
import {
  STORYBOARD_STYLES,
  STORYBOARD_LENGTHS,
  SCENE_DURATION_PRESETS,
  TOTAL_DURATION_PRESETS,
} from "@/types/storyboard";

export const maxDuration = 60;

// ── Resolve scene count & duration strings from request ────────────────────────
function resolveSceneParams(req: Partial<StoryboardRequest>): {
  sceneCountInstruction: string;
  sceneDurationInstruction: string;
  totalDurationInstruction: string;
  estimatedDuration: string;
} {
  const { length = "medium", customSceneCount, sceneDurationPreset, customSceneDuration, totalDurationPreset, customTotalDuration } = req;

  // ── Scene count ──
  let sceneCountInstruction: string;
  if (length === "custom" && customSceneCount && customSceneCount >= 1 && customSceneCount <= 30) {
    sceneCountInstruction = `Buat TEPAT ${customSceneCount} scene (tidak kurang, tidak lebih).`;
  } else {
    const preset = STORYBOARD_LENGTHS[length as keyof typeof STORYBOARD_LENGTHS];
    sceneCountInstruction = `Buat ${preset?.scenes ?? "6-9 scene"}.`;
  }

  // ── Scene duration ──
  let sceneDurationInstruction: string;
  let sceneDurationLabel: string;
  if (sceneDurationPreset === "custom" && customSceneDuration?.trim()) {
    sceneDurationLabel = customSceneDuration.trim();
    sceneDurationInstruction = `Setiap scene berdurasi ${customSceneDuration.trim()}.`;
  } else if (sceneDurationPreset && sceneDurationPreset !== "custom") {
    const preset = SCENE_DURATION_PRESETS[sceneDurationPreset];
    sceneDurationLabel = preset.value;
    sceneDurationInstruction = `Setiap scene berdurasi ${preset.value}.`;
  } else {
    sceneDurationLabel = "3-5 detik";
    sceneDurationInstruction = "Setiap scene berdurasi sekitar 3-5 detik (sesuaikan dengan konten).";
  }

  // ── Total duration ──
  let totalDurationInstruction: string;
  let totalDurationLabel: string;
  if (totalDurationPreset === "custom" && customTotalDuration?.trim()) {
    totalDurationLabel = customTotalDuration.trim();
    totalDurationInstruction = `Total durasi video sekitar ${customTotalDuration.trim()}.`;
  } else if (totalDurationPreset && totalDurationPreset !== "custom") {
    const preset = TOTAL_DURATION_PRESETS[totalDurationPreset];
    totalDurationLabel = preset.value;
    totalDurationInstruction = `Total durasi video sekitar ${preset.value}.`;
  } else {
    const preset = STORYBOARD_LENGTHS[length as keyof typeof STORYBOARD_LENGTHS];
    totalDurationLabel = preset?.duration ?? "30-60 detik";
    totalDurationInstruction = `Total estimasi durasi: ${totalDurationLabel}.`;
  }

  return {
    sceneCountInstruction,
    sceneDurationInstruction,
    totalDurationInstruction,
    estimatedDuration: totalDurationLabel,
  };
}

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 & validate request body ─────────────────────────────────────────
    const body = await request.json() as Partial<StoryboardRequest>;
    const {
      url,
      style = "cinematic",
      length = "medium",
      language = "id",
      tone,
      targetAudience,
      customInstructions,
      customSceneCount,
      sceneDurationPreset,
      customSceneDuration,
      totalDurationPreset,
      customTotalDuration,
    } = body;

    if (!url || typeof url !== "string") {
      return NextResponse.json({ success: false, error: "URL tidak boleh kosong" }, { status: 400 });
    }

    // Validate custom scene count range
    if (length === "custom" && customSceneCount !== undefined) {
      if (customSceneCount < 1 || customSceneCount > 30) {
        return NextResponse.json({ success: false, error: "Jumlah scene harus antara 1–30" }, { status: 400 });
      }
    }

    // ── Extract content from URL ──────────────────────────────────────────────
    let extracted;
    try {
      extracted = await extractUrlContent(url);
    } catch (e) {
      return NextResponse.json(
        { success: false, error: `Gagal mengambil konten dari URL: ${(e as Error).message}` },
        { status: 422 }
      );
    }

    if (!extracted.body && !extracted.description) {
      return NextResponse.json(
        { success: false, error: "Konten dari URL kosong atau tidak dapat dibaca. Pastikan URL dapat diakses publik." },
        { status: 422 }
      );
    }

    // ── Resolve scene/duration params ─────────────────────────────────────────
    const { sceneCountInstruction, sceneDurationInstruction, totalDurationInstruction, estimatedDuration } =
      resolveSceneParams(body);

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

    const systemPrompt = `Kamu adalah profesional Storyboard Writer dan Storyteller kelas dunia.
Tugasmu: membaca konten dari sebuah postingan/artikel, lalu mengubahnya menjadi storyboard visual yang menarik.

ATURAN PENTING:
1. JANGAN keluar dari tema/topik utama postingan asli
2. Boleh merangkum, memperluas, atau merestrukturisasi — ASAL masih relevan dengan tema asli
3. Pertahankan fakta dan pesan inti konten asli
4. Output HARUS dalam ${langLabel}
5. Output HARUS berupa JSON valid, tidak ada teks di luar JSON

STYLE: ${styleInfo?.label ?? style} — ${styleInfo?.description ?? ""}

INSTRUKSI SCENE:
- ${sceneCountInstruction}
- ${sceneDurationInstruction}
- ${totalDurationInstruction}
${tone ? `TONE: ${tone}` : ""}
${targetAudience ? `TARGET AUDIENCE: ${targetAudience}` : ""}
${customInstructions ? `INSTRUKSI KHUSUS: ${customInstructions}` : ""}

PENTING TENTANG DURASI:
- Field "duration" pada setiap scene HARUS mengikuti instruksi durasi per scene di atas
- Jangan abaikan instruksi durasi — ini adalah kebutuhan produksi yang wajib dipenuhi

OUTPUT FORMAT (JSON):
{
  "theme": "tema utama yang diidentifikasi dari konten",
  "hook": "kalimat pembuka yang menarik perhatian",
  "summary": "ringkasan cerita keseluruhan (2-3 paragraf)",
  "callToAction": "ajakan bertindak yang relevan",
  "scenes": [
    {
      "sceneNumber": 1,
      "title": "judul singkat scene",
      "narration": "teks narasi/voiceover untuk scene ini",
      "visualDescription": "deskripsi visual yang harus ditampilkan",
      "duration": "durasi scene sesuai instruksi di atas",
      "cameraAngle": "sudut kamera yang disarankan",
      "emotion": "emosi dominan scene ini",
      "transition": "transisi ke scene berikutnya"
    }
  ]
}`;

    const userPrompt = `Berikut konten yang perlu dijadikan storyboard:

SUMBER: ${extracted.platform.toUpperCase()} — ${extracted.url}
JUDUL: ${extracted.title}
${extracted.author ? `PENULIS: ${extracted.author}` : ""}

KONTEN:
${extracted.body}

Buat storyboard style ${styleInfo?.label ?? style} dalam ${langLabel}.
${sceneCountInstruction}
${sceneDurationInstruction}`;

    // ── Generate dengan retry ─────────────────────────────────────────────────
    const MAX_RETRIES = 2;
    let rawOutput = "";
    let model = "unknown";
    let provider = "unknown";
    let lastError: Error | null = null;

    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;
        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 AI output ───────────────────────────────────────────────────────
    let parsed: { theme?: string; hook?: string; summary?: string; callToAction?: string; scenes?: StoryboardScene[] };
    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 });
      }
    }

    const scenes: StoryboardScene[] = Array.isArray(parsed.scenes) ? parsed.scenes : [];

    // Resolve scene duration label for metadata
    let sceneDurationLabel = "3-5 detik";
    if (sceneDurationPreset === "custom" && customSceneDuration) sceneDurationLabel = customSceneDuration;
    else if (sceneDurationPreset && sceneDurationPreset !== "custom") sceneDurationLabel = SCENE_DURATION_PRESETS[sceneDurationPreset]?.value ?? "3-5 detik";

    let totalDurationLabel = estimatedDuration;
    if (totalDurationPreset === "custom" && customTotalDuration) totalDurationLabel = customTotalDuration;
    else if (totalDurationPreset && totalDurationPreset !== "custom") totalDurationLabel = TOTAL_DURATION_PRESETS[totalDurationPreset]?.value ?? estimatedDuration;

    const output: StoryboardOutput = {
      sourceUrl: extracted.url,
      sourcePlatform: extracted.platform,
      sourceTitle: extracted.title,
      theme: parsed.theme ?? "Tidak terdeteksi",
      hook: parsed.hook ?? "",
      summary: parsed.summary ?? "",
      callToAction: parsed.callToAction ?? "",
      scenes,
      metadata: {
        generatedAt: new Date().toISOString(),
        model: `${provider}/${model}`,
        style,
        length,
        totalScenes: scenes.length,
        estimatedDuration: totalDurationLabel,
        sceneCount: scenes.length,
        sceneDuration: sceneDurationLabel,
        totalDuration: totalDurationLabel,
      },
    };

    // ── Save history — quota sudah di-increment atomic di atas ───────────────
    await supabase.from("storyboard_history").insert({
      user_id: user.id,
      source_url: extracted.url,
      source_platform: extracted.platform,
      source_title: extracted.title,
      style,
      length,
      language,
      output,
    });

    return NextResponse.json(
      { success: true, data: output },
      { headers: { "X-RateLimit-Remaining": String(rateLimit.remaining) } }
    );

  } catch (error) {
    console.error("[storyboard]", error);
    return NextResponse.json({ success: false, error: "Internal server error" }, { status: 500 });
  }
}
