import { NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { getBuffer, uploadBuffer } from "@/lib/storage";
import { pdfToImages, imageToBase64 } from "@/lib/pdf";
import { ocrImage } from "@/lib/ai-ocr";
import { requireApiAuthWithOrg, handleApiError } from "@/lib/api-auth";

const DELAY_BETWEEN_OCR_MS = 3_000;

export async function GET() {
  try {
    const session = await requireApiAuthWithOrg();
    const missing = await prisma.responseCard.count({
      where: { frontImagePath: null, backImagePath: { not: null }, organizationId: session.user.orgId },
    });
    return NextResponse.json({ missingCount: missing });
  } catch (error) {
    return handleApiError(error);
  }
}

export async function POST() {
  try {
    const session = await requireApiAuthWithOrg();
    const cards = await prisma.responseCard.findMany({
      where: { frontImagePath: null, backImagePath: { not: null }, organizationId: session.user.orgId },
      select: { id: true, sourceFile: true, name: true },
    });

    if (cards.length === 0) {
      return NextResponse.json({ ok: true, recovered: 0, message: "No cards with missing survey sides" });
    }

    const sourceFiles = [...new Set(cards.map((c) => c.sourceFile).filter(Boolean))] as string[];
    console.log(`[recover-survey] ${cards.length} card(s) missing survey, from ${sourceFiles.length} source file(s)`);

    (async () => {
      let recovered = 0;
      let failed = 0;

      for (const sourceFile of sourceFiles) {
        try {
          const jobIdMatch = sourceFile.match(/^sources\/([^/]+)\//);
          if (!jobIdMatch) {
            console.warn(`[recover-survey] Cannot parse job ID from sourceFile: ${sourceFile}`);
            continue;
          }
          const jobId = jobIdMatch[1];

          const job = await prisma.processingJob.findUnique({ where: { id: jobId } });
          if (!job) {
            console.warn(`[recover-survey] Job ${jobId} not found`);
            continue;
          }

          const orderedCardIds = (job.cardIds as string[] | null) ?? [];
          const affectedCards = cards.filter((c) => c.sourceFile === sourceFile);
          const isPdf = job.fileName.toLowerCase().endsWith(".pdf");

          if (!isPdf) {
            console.log(`[recover-survey] Skipping non-PDF source: ${sourceFile}`);
            continue;
          }

          let pdfBuffer: Buffer;
          try {
            pdfBuffer = await getBuffer(sourceFile);
          } catch {
            console.warn(`[recover-survey] Source PDF not found in storage: ${sourceFile}`);
            continue;
          }

          console.log(`[recover-survey] Re-extracting pages from ${sourceFile}`);
          const pageImages = await pdfToImages(pdfBuffer);
          console.log(`[recover-survey] Got ${pageImages.length} pages from ${job.fileName}`);

          for (const card of affectedCards) {
            const cardIndex = orderedCardIds.indexOf(card.id);
            if (cardIndex === -1) {
              console.warn(`[recover-survey] Card ${card.id} not found in job ${jobId} cardIds`);
              continue;
            }

            const surveyPageIndex = cardIndex * 2 + 1;
            if (surveyPageIndex >= pageImages.length) {
              console.log(`[recover-survey] Card "${card.name}" (${card.id}): no survey page at index ${surveyPageIndex} (only ${pageImages.length} pages)`);
              continue;
            }

            const surveyImage = pageImages[surveyPageIndex];
            const imgKey = `images/${card.id}/survey.jpg`;

            try {
              await uploadBuffer(imgKey, surveyImage.buffer, "image/jpeg");
              await prisma.responseCard.update({
                where: { id: card.id },
                data: { frontImagePath: imgKey },
              });

              const base64 = await imageToBase64(surveyImage.buffer);
              const result = await ocrImage(base64, "survey");

              await prisma.responseCard.update({
                where: { id: card.id },
                data: {
                  messageTopics: result.data.messageTopics ?? [],
                  messageTopicsOther: asString(result.data.messageTopicsOther),
                  nextStep: result.data.nextStep ?? [],
                  attendanceDuration: asString(result.data.attendanceDuration),
                  campusPreference: result.data.campusPreference ?? [],
                  campusPreferenceOther: asString(result.data.campusPreferenceOther),
                  howHeard: result.data.howHeard ?? [],
                  howHeardOther: asString(result.data.howHeardOther),
                  serviceAttended: asString(result.data.serviceAttended),
                },
              });

              recovered++;
              console.log(`[recover-survey] Recovered survey for "${card.name}" (${card.id})`);
            } catch (err) {
              failed++;
              console.error(`[recover-survey] Failed OCR for card ${card.id}:`, err);
            }

            await new Promise((r) => setTimeout(r, DELAY_BETWEEN_OCR_MS));
          }
        } catch (err) {
          console.error(`[recover-survey] Error processing source ${sourceFile}:`, err);
        }
      }

      console.log(`[recover-survey] Done: ${recovered} recovered, ${failed} failed`);
    })().catch((err) => {
      console.error("[recover-survey] Background task failed:", err);
    });

    return NextResponse.json({
      ok: true,
      queued: cards.length,
      sourceFiles: sourceFiles.length,
      message: `Recovery started for ${cards.length} card(s) from ${sourceFiles.length} PDF(s)`,
    });
  } catch (error) {
    return handleApiError(error);
  }
}

function asString(v: unknown): string | null {
  if (v === null || v === undefined) return null;
  return String(v);
}
