/**
 * POST /api/ga4/backfill — Backfill GA4 daily metrics into MetricSnapshot.
 * Fetches organic-only data from the GA4 Data API with daily granularity.
 */
import { NextResponse } from "next/server";
import { getCurrentUser } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { getValidAccessToken, getCredentials } from "@/lib/services/integration-credentials";
import { apiCall } from "@/lib/integrations/types";

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

const GA4_API = "https://analyticsdata.googleapis.com/v1beta";

export async function POST(req: Request) {
  try {
    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;
    const monthsBack = Math.min(body?.monthsBack ?? 6, 16);

    if (!brandId && domain) {
      const found = await prisma.brand.findFirst({ where: { domain: { contains: domain.replace(/^https?:\/\//, "").replace(/^www\./, "").replace(/\/+$/, "") } }, 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 || !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, "ga4"); }
    catch (err) { return NextResponse.json({ error: "GA4 not connected", detail: err instanceof Error ? err.message : "unknown" }, { status: 400 }); }

    const creds = await getCredentials(brandId, "ga4");
    const propertyId = (creds?.propertyId as string) || (creds?.accountId as string);
    if (!propertyId) return NextResponse.json({ error: "No GA4 property ID stored", credsKeys: creds ? Object.keys(creds) : [] }, { status: 400 });

    const endDate = new Date();
    endDate.setDate(endDate.getDate() - 1);
    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(`[ga4-backfill] Starting: property=${propertyId}, ${start} to ${end}, token=${token.slice(0, 10)}...`);

    // Use apiCall helper (same as Dashboard) for consistent auth handling
    const res = await apiCall(
      `${GA4_API}/properties/${propertyId}:runReport`,
      {
        method: "POST",
        bearerToken: token,
        body: {
          dateRanges: [{ startDate: start, endDate: end }],
          dimensions: [{ name: "date" }],
          metrics: [
            { name: "sessions" },
            { name: "totalUsers" },
            { name: "screenPageViews" },
            { name: "conversions" },
            { name: "averageSessionDuration" },
            { name: "bounceRate" },
          ],
          dimensionFilter: {
            filter: {
              fieldName: "sessionDefaultChannelGroup",
              stringFilter: { matchType: "EXACT", value: "Organic Search" },
            },
          },
          orderBys: [{ dimension: { dimensionName: "date" } }],
          limit: 500,
        },
      },
    );

    if (!res.ok) {
      // Token might have expired between getValidAccessToken and apiCall — retry once
      console.log(`[ga4-backfill] First attempt failed (${res.status}), refreshing token and retrying...`);
      const freshToken = await getValidAccessToken(brandId, "ga4");
      const retry = await apiCall(`${GA4_API}/properties/${propertyId}:runReport`, {
        method: "POST",
        bearerToken: freshToken,
        body: {
          dateRanges: [{ startDate: start, endDate: end }],
          dimensions: [{ name: "date" }],
          metrics: [
            { name: "sessions" }, { name: "totalUsers" }, { name: "screenPageViews" },
            { name: "conversions" }, { name: "averageSessionDuration" }, { name: "bounceRate" },
          ],
          dimensionFilter: { filter: { fieldName: "sessionDefaultChannelGroup", stringFilter: { matchType: "EXACT", value: "Organic Search" } } },
          orderBys: [{ dimension: { dimensionName: "date" } }],
          limit: 500,
        },
      });
      if (!retry.ok) {
        return NextResponse.json({ error: `GA4 API error after retry: ${retry.status}`, propertyId, detail: retry.error?.slice(0, 500) }, { status: 502 });
      }
      // Use retry result
      const data = retry.data as { rows?: Array<{ dimensionValues: Array<{ value: string }>; metricValues: Array<{ value: string }> }> };
      return processAndStore(brandId!, data.rows ?? [], start, end, propertyId);
    }

    const data = res.data as { rows?: Array<{ dimensionValues: Array<{ value: string }>; metricValues: Array<{ value: string }> }> };
    return processAndStore(brandId!, data.rows ?? [], start, end, propertyId);
  } catch (err) {
    return NextResponse.json({ error: err instanceof Error ? err.message : "Unknown error", stack: err instanceof Error ? err.stack?.split("\n").slice(0, 5) : undefined }, { status: 500 });
  }
}

type Ga4Row = { dimensionValues: Array<{ value: string }>; metricValues: Array<{ value: string }> };

async function processAndStore(brandId: string, rows: Ga4Row[], start: string, end: string, propertyId: string) {
  if (rows.length === 0) {
    return NextResponse.json({ error: "No data returned from GA4 API", propertyId, dateRange: { start, end } });
  }

  await prisma.metricSnapshot.deleteMany({ where: { brandId, source: "ga4", date: { gte: new Date(start), lte: new Date(end) } } });

  const snapshots = rows.map((row) => {
    const dateStr = row.dimensionValues[0]?.value ?? "";
    const d = `${dateStr.slice(0, 4)}-${dateStr.slice(4, 6)}-${dateStr.slice(6, 8)}`;
    const m = row.metricValues.map((v) => parseFloat(v.value) || 0);
    return {
      brandId, date: new Date(d), source: "ga4",
      sessions: Math.round(m[0]), users: Math.round(m[1]), pageviews: Math.round(m[2]),
      conversions: Math.round(m[3]), avgSessionSec: Math.round(m[4]),
      bounceRate: Math.round((m[5] ?? 0) * 100) / 100,
      organicClicks: 0, impressions: 0, avgPosition: 0, ctr: 0, revenue: 0, seoScore: 0, crawlHealth: 0, aiMentions: 0,
    };
  }).filter((s) => !isNaN(s.date.getTime()));

  for (let i = 0; i < snapshots.length; i += 100) {
    await prisma.metricSnapshot.createMany({ data: snapshots.slice(i, i + 100) });
  }

  const totalSessions = snapshots.reduce((s, r) => s + r.sessions, 0);
  const totalConversions = snapshots.reduce((s, r) => s + r.conversions, 0);
  return NextResponse.json({ stored: snapshots.length, propertyId, dateRange: { start, end }, totalSessions, totalConversions, filter: "Organic Search only", message: `Backfilled ${snapshots.length} days: ${totalSessions.toLocaleString()} organic sessions, ${totalConversions} conversions` });
}
