/**
 * POST /api/gsc/backfill — Backfill GSC daily page data for a brand.
 * Fetches up to 6 months of historical data with dimensions: ["date", "page"].
 * Paginates to handle large sites. Stores per-day GscPage rows.
 */
import { NextResponse } from "next/server";
import { getCurrentUser } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { getValidAccessToken, getCredentials } from "@/lib/services/integration-credentials";

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

const API_BASE = "https://www.googleapis.com/webmasters/v3";
const ROW_LIMIT = 25000;

export async function POST(req: Request) {
  const user = await getCurrentUser();
  if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

  const body = await req.json().catch(() => null);
  let brandId = body?.brandId as string | undefined;
  const domain = body?.domain as string | undefined;
  // Default to 16 months (the full GSC API retention window) so the
  // Historical Tracking page captures the complete archive on first
  // sync. Previously defaulted to 6 which left 10 months of available
  // data on the table.
  const monthsBack = Math.min(body?.monthsBack ?? 16, 16);

  // Look up by domain if brandId not provided
  if (!brandId && domain) {
    const cleanDomain = domain.replace(/^https?:\/\//, "").replace(/^www\./, "").replace(/\/+$/, "");
    const found = await prisma.brand.findFirst({ where: { domain: { contains: cleanDomain } }, select: { id: true } });
    if (found) brandId = found.id;
  }
  if (!brandId) return NextResponse.json({ error: "brandId or domain required" }, { status: 400 });

  const brand = await prisma.brand.findUnique({
    where: { id: brandId },
    include: { organization: { include: { memberships: true } } },
  });
  if (!brand) return NextResponse.json({ error: "Brand not found" }, { status: 404 });
  if (!brand.organization.memberships.some((m) => m.userId === user.id)) return NextResponse.json({ error: "Access denied" }, { status: 403 });

  let token: string;
  try { token = await getValidAccessToken(brandId, "gsc"); }
  catch { return NextResponse.json({ error: "GSC not connected" }, { status: 400 }); }

  // Use the SAME siteUrl the Dashboard uses (stored during OAuth property selection)
  const creds = await getCredentials(brandId, "gsc");
  const siteUrl = (creds?.siteUrl as string) || (creds?.accountId as string) || `sc-domain:${brand.domain}`;
  const encodedSite = encodeURIComponent(siteUrl);
  console.log(`[gsc-backfill] Using siteUrl: "${siteUrl}" (encoded: ${encodedSite})`);
  const endDate = new Date();
  endDate.setDate(endDate.getDate() - 2); // GSC data is ~2 days delayed
  const startDate = new Date(endDate);
  startDate.setMonth(startDate.getMonth() - monthsBack);

  const start = startDate.toISOString().split("T")[0];
  const end = endDate.toISOString().split("T")[0];

  console.log(`[gsc-backfill] Starting backfill for ${brand.domain}: ${start} to ${end}, siteUrl=${siteUrl}`);

  // First: verify connection with a no-dimensions totals call (same as Dashboard)
  const verifyRes = await fetch(`${API_BASE}/sites/${encodedSite}/searchAnalytics/query`, {
    method: "POST",
    headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
    body: JSON.stringify({ startDate: start, endDate: end }),
  });
  if (!verifyRes.ok) {
    const errText = await verifyRes.text().catch(() => "");
    return NextResponse.json({ error: `GSC API verification failed: ${verifyRes.status}`, siteUrl, detail: errText.slice(0, 500) }, { status: 502 });
  }
  const verifyData = await verifyRes.json() as { rows?: Array<{ clicks: number; impressions: number }> };
  const totalClicks = verifyData.rows?.[0]?.clicks ?? 0;
  const totalImpressions = verifyData.rows?.[0]?.impressions ?? 0;
  console.log(`[gsc-backfill] Verified: ${totalClicks.toLocaleString()} clicks, ${totalImpressions.toLocaleString()} impressions for ${start} to ${end}`);

  // Now fetch with date+page dimensions and pagination
  type GscRow = { keys: string[]; clicks: number; impressions: number; ctr: number; position: number };
  let allRows: GscRow[] = [];
  let startRow = 0;
  let calls = 0;

  while (startRow <= 500000) {
    const res = await fetch(`${API_BASE}/sites/${encodedSite}/searchAnalytics/query`, {
      method: "POST",
      headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
      body: JSON.stringify({ startDate: start, endDate: end, dimensions: ["date", "page"], rowLimit: ROW_LIMIT, startRow }),
    });
    calls++;
    if (!res.ok) {
      const errText = await res.text().catch(() => "");
      console.log(`[gsc-backfill] API error on call ${calls}: ${res.status} ${errText.slice(0, 500)}`);
      if (calls === 1) return NextResponse.json({ error: `GSC daily data call failed: ${res.status}`, siteUrl, detail: errText.slice(0, 500), verifiedTotals: { totalClicks, totalImpressions } }, { status: 502 });
      break;
    }
    const data = await res.json() as { rows?: GscRow[] };
    const rows = data.rows ?? [];
    allRows = allRows.concat(rows);
    console.log(`[gsc-backfill] Call ${calls}: ${rows.length} rows (total: ${allRows.length})`);
    if (rows.length < ROW_LIMIT) break;
    startRow += ROW_LIMIT;
  }

  if (allRows.length === 0) {
    return NextResponse.json({ error: "No daily data returned from GSC API (but totals verified)", calls, siteUrl, verifiedTotals: { totalClicks, totalImpressions } });
  }

  // Delete existing GscPage data for this range to prevent duplicates
  await prisma.gscPage.deleteMany({
    where: { brandId, date: { gte: new Date(start), lte: new Date(end) } },
  });

  // Store per-day per-page rows
  const batch = allRows.map((row) => ({
    brandId,
    pageUrl: row.keys[1] ?? "",
    clicks: row.clicks,
    impressions: row.impressions,
    ctr: row.ctr,
    position: row.position,
    date: new Date(row.keys[0]),
  })).filter((r) => r.pageUrl);

  // Insert in batches of 1000
  let stored = 0;
  for (let i = 0; i < batch.length; i += 1000) {
    await prisma.gscPage.createMany({ data: batch.slice(i, i + 1000) });
    stored += Math.min(1000, batch.length - i);
  }

  const uniqueDates = new Set(allRows.map((r) => r.keys[0])).size;
  const storedClicks = allRows.reduce((s, r) => s + r.clicks, 0);

  console.log(`[gsc-backfill] Pages done: ${stored} rows across ${uniqueDates} dates, ${storedClicks.toLocaleString()} clicks, ${calls} API calls`);

  // ── Pass 2: Query data (dimensions: ["date", "query"]) ──
  let allQueryRows: GscRow[] = [];
  let queryStartRow = 0;
  let queryCalls = 0;

  // Refresh token in case it expired during the page pass
  let queryToken = token;
  try { queryToken = await getValidAccessToken(brandId, "gsc"); } catch { /* use existing */ }

  while (queryStartRow <= 500000) {
    const res = await fetch(`${API_BASE}/sites/${encodedSite}/searchAnalytics/query`, {
      method: "POST",
      headers: { Authorization: `Bearer ${queryToken}`, "Content-Type": "application/json" },
      body: JSON.stringify({ startDate: start, endDate: end, dimensions: ["date", "query"], rowLimit: ROW_LIMIT, startRow: queryStartRow }),
    });
    queryCalls++;
    if (!res.ok) {
      console.log(`[gsc-backfill] Query API error on call ${queryCalls}: ${res.status}`);
      break;
    }
    const data = await res.json() as { rows?: GscRow[] };
    const rows = data.rows ?? [];
    allQueryRows = allQueryRows.concat(rows);
    console.log(`[gsc-backfill] Query call ${queryCalls}: ${rows.length} rows (total: ${allQueryRows.length})`);
    if (rows.length < ROW_LIMIT) break;
    queryStartRow += ROW_LIMIT;
  }

  let storedQueries = 0;
  if (allQueryRows.length > 0) {
    await prisma.gscQuery.deleteMany({ where: { brandId, date: { gte: new Date(start), lte: new Date(end) } } });

    const queryBatch = allQueryRows.map((row) => ({
      brandId,
      query: row.keys[1] ?? "",
      clicks: row.clicks,
      impressions: row.impressions,
      ctr: row.ctr,
      position: row.position,
      date: new Date(row.keys[0]),
    })).filter((r) => r.query);

    for (let i = 0; i < queryBatch.length; i += 1000) {
      await prisma.gscQuery.createMany({ data: queryBatch.slice(i, i + 1000) });
      storedQueries += Math.min(1000, queryBatch.length - i);
    }
  }

  console.log(`[gsc-backfill] Queries done: ${storedQueries} rows, ${queryCalls} API calls`);

  return NextResponse.json({
    stored,
    storedQueries,
    uniqueDates,
    storedClicks,
    verifiedTotalClicks: totalClicks,
    apiCalls: calls + queryCalls,
    dateRange: { start, end },
    message: `Backfilled ${stored} page rows and ${storedQueries} query rows across ${uniqueDates} dates from ${start} to ${end}`,
  });
}
