/**
 * POST /api/admin/debug/backfill-gsc-history[?brandId=xxx&startMonth=2024-12&endMonth=2025-03]
 *
 * Fetches historical GSC data via apiCallAuthed and stores in
 * GscPage + GscQuery. Supports month-range params to avoid 504
 * timeouts — call in 3-month chunks instead of all 16 months at
 * once.
 *
 * Defaults: last 3 months before the earliest existing GscPage row
 * (fills the most recent gap). Pass ?startMonth=&endMonth= to
 * control the range explicitly.
 *
 * Also includes a diagnostic route that logs GscPage row counts
 * per brand so misattributed data can be identified.
 *
 * Superadmin-only. maxDuration=300.
 */
import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireSuperadmin } from "@/lib/admin-auth";
import { getCredentials } from "@/lib/services/integration-credentials";
import { apiCallAuthed } from "@/lib/integrations/types";

export const dynamic = "force-dynamic";
export const maxDuration = 300;

const GSC_API = "https://www.googleapis.com/webmasters/v3";
const ROW_LIMIT = 5000; // smaller batches for reliability
const TIME_LIMIT_MS = 240_000; // 4 min, leave 60s for DB writes

type GscRow = { keys: string[]; clicks: number; impressions: number; ctr: number; position: number };

export async function POST(req: Request) {
  const denied = await requireSuperadmin();
  if (denied) return denied;
  const t0 = Date.now();

  const { searchParams } = new URL(req.url);
  const targetBrandId = searchParams.get("brandId");
  const startMonthParam = searchParams.get("startMonth");
  const endMonthParam = searchParams.get("endMonth");
  const purge = searchParams.get("purge") === "true";

  // ── Purge path — delete wrong data FIRST, before any API logic ──
  if (purge && targetBrandId) {
    const deletedPages = await prisma.gscPage.deleteMany({ where: { brandId: targetBrandId } });
    const deletedQueries = await prisma.gscQuery.deleteMany({ where: { brandId: targetBrandId } });
    const deletedSnapshots = await prisma.metricSnapshot.deleteMany({ where: { brandId: targetBrandId } });
    console.info(`[gsc-backfill] PURGED: ${deletedPages.count} pages, ${deletedQueries.count} queries, ${deletedSnapshots.count} snapshots for ${targetBrandId}`);

    const hasGsc = await prisma.brandIntegration.findFirst({
      where: { brandId: targetBrandId, integrationId: "gsc", connected: true },
      select: { id: true },
    });
    if (!hasGsc) {
      return NextResponse.json({
        purged: { pages: deletedPages.count, queries: deletedQueries.count, snapshots: deletedSnapshots.count },
        message: "Purged wrong data. Brand has no GSC connected — no re-fetch needed.",
      });
    }
    // GSC IS connected — fall through to re-fetch fresh data
  }

  // Diagnostic: dump ALL integrations so we can see what exists
  const allIntegrations = await prisma.brandIntegration.findMany({
    select: { brandId: true, integrationId: true, connected: true, status: true },
  }).catch(() => []);
  console.info("[gsc-backfill] All integrations:", JSON.stringify(allIntegrations));

  const integrations = await prisma.brandIntegration.findMany({
    where: {
      integrationId: "gsc", connected: true,
      ...(targetBrandId ? { brandId: targetBrandId } : {}),
    },
    select: { brandId: true, brand: { select: { name: true, domain: true } } },
  });
  console.info(`[gsc-backfill] GSC connected brands: ${integrations.length}`);

  // If no connected GSC integrations found, also try without the
  // connected filter — the field might be null (never explicitly
  // set to true) even though the integration IS working (has
  // credentials + syncs daily). This catches integrations wired
  // through the legacy OAuth flow that didn't set connected=true.
  let effectiveIntegrations = integrations;
  if (integrations.length === 0) {
    const fallback = await prisma.brandIntegration.findMany({
      where: {
        integrationId: "gsc",
        ...(targetBrandId ? { brandId: targetBrandId } : {}),
      },
      select: { brandId: true, connected: true, status: true, brand: { select: { name: true, domain: true } } },
    });
    console.info(`[gsc-backfill] Fallback (any GSC integration): ${fallback.length}`, JSON.stringify(fallback.map((f) => ({ brand: f.brand.name, connected: f.connected, status: f.status }))));
    effectiveIntegrations = fallback;
  }

  // Diagnostic: log per-brand GscPage row counts
  for (const integ of effectiveIntegrations) {
    const count = await prisma.gscPage.count({ where: { brandId: integ.brandId } }).catch(() => -1);
    const sum = await prisma.gscPage.aggregate({ where: { brandId: integ.brandId }, _sum: { clicks: true } }).catch(() => ({ _sum: { clicks: null } }));
    console.info(`[gsc-history:diagnostic] ${integ.brand.name}: ${count} GscPage rows, ${sum._sum.clicks ?? 0} total clicks`);
  }

  const results: Record<string, { pageRows: number; queryRows: number; range: string; elapsed: number; error?: string }> = {};

  for (const integ of effectiveIntegrations) {
    if (Date.now() - t0 > TIME_LIMIT_MS) { results[integ.brand.name] = { pageRows: 0, queryRows: 0, range: "", elapsed: 0, error: "Time limit — run again for remaining brands" }; continue; }

    const { brandId } = integ;
    const name = integ.brand.name;
    const brandStart = Date.now();
    try {
      const creds = await getCredentials(brandId, "gsc");
      const siteUrl = (creds?.siteUrl as string) || (creds?.accountId as string) || `sc-domain:${integ.brand.domain}`;
      const encoded = encodeURIComponent(siteUrl);

      // Determine date range
      let start: string;
      let end: string;
      if (startMonthParam && endMonthParam) {
        start = `${startMonthParam}-01`;
        end = `${endMonthParam}-28`;
      } else {
        // Default: last 3 months before earliest existing data
        const earliest = await prisma.gscPage.findFirst({ where: { brandId }, orderBy: { date: "asc" }, select: { date: true } });
        const endDate = earliest?.date ?? new Date();
        const startDate = new Date(endDate);
        startDate.setMonth(startDate.getMonth() - 3);
        start = startDate.toISOString().split("T")[0];
        end = endDate.toISOString().split("T")[0];
      }

      console.info(`[gsc-history] ${name}: ${start} → ${end}, siteUrl=${siteUrl}`);

      // Fetch page data with time guard
      let allPages: GscRow[] = [];
      let startRow = 0;
      while (startRow <= 100_000 && Date.now() - t0 < TIME_LIMIT_MS) {
        const res = await apiCallAuthed(
          `${GSC_API}/sites/${encoded}/searchAnalytics/query`,
          { method: "POST", body: { startDate: start, endDate: end, dimensions: ["date", "page"], rowLimit: ROW_LIMIT, startRow } },
          { brandId, integrationId: "gsc" },
        );
        if (!res.ok) { console.error(`[gsc-history] ${name}: pages failed: ${res.status}`, res.error); break; }
        const rows = ((res.data as { rows?: GscRow[] })?.rows) ?? [];
        allPages = allPages.concat(rows);
        console.info(`[gsc-history] ${name}: pages ${rows.length} (total: ${allPages.length})`);
        if (rows.length < ROW_LIMIT) break;
        startRow += ROW_LIMIT;
      }

      if (allPages.length > 0) {
        await prisma.gscPage.deleteMany({ where: { brandId, date: { gte: new Date(start), lte: new Date(end) } } });
        const batch = allPages.map((r) => ({
          brandId, pageUrl: r.keys[1] ?? "", clicks: r.clicks, impressions: r.impressions,
          ctr: r.ctr, position: r.position, date: new Date(r.keys[0]),
        })).filter((r) => r.pageUrl);
        for (let i = 0; i < batch.length; i += 1000) {
          await prisma.gscPage.createMany({ data: batch.slice(i, i + 1000) });
        }
      }

      // Fetch query data
      let allQueries: GscRow[] = [];
      startRow = 0;
      while (startRow <= 100_000 && Date.now() - t0 < TIME_LIMIT_MS) {
        const res = await apiCallAuthed(
          `${GSC_API}/sites/${encoded}/searchAnalytics/query`,
          { method: "POST", body: { startDate: start, endDate: end, dimensions: ["date", "query"], rowLimit: ROW_LIMIT, startRow } },
          { brandId, integrationId: "gsc" },
        );
        if (!res.ok) { console.error(`[gsc-history] ${name}: queries failed: ${res.status}`, res.error); break; }
        const rows = ((res.data as { rows?: GscRow[] })?.rows) ?? [];
        allQueries = allQueries.concat(rows);
        if (rows.length < ROW_LIMIT) break;
        startRow += ROW_LIMIT;
      }

      if (allQueries.length > 0) {
        await prisma.gscQuery.deleteMany({ where: { brandId, date: { gte: new Date(start), lte: new Date(end) } } });
        const batch = allQueries.map((r) => ({
          brandId, query: r.keys[1] ?? "", clicks: r.clicks, impressions: r.impressions,
          ctr: r.ctr, position: r.position, date: new Date(r.keys[0]),
        })).filter((r) => r.query);
        for (let i = 0; i < batch.length; i += 1000) {
          await prisma.gscQuery.createMany({ data: batch.slice(i, i + 1000) });
        }
      }

      const elapsed = Date.now() - brandStart;
      results[name] = {
        pageRows: allPages.length, queryRows: allQueries.length,
        range: `${start} → ${end}`, elapsed,
        ...(allPages.length === 0 && allQueries.length === 0 ? { error: `0 rows — check Vercel logs for API errors. siteUrl=${siteUrl}` } : {}),
      };
    } catch (err) {
      results[name] = { pageRows: 0, queryRows: 0, range: "", elapsed: Date.now() - brandStart, error: err instanceof Error ? err.message : String(err) };
    }
  }

  return NextResponse.json({ brands: effectiveIntegrations.length, elapsed: Date.now() - t0, results });
}
