/**
 * Page Build Context
 * ──────────────────
 * Gathers full brand context from all platform data for AI page generation.
 * Uses Promise.allSettled so missing data never blocks generation.
 */

import { prisma } from "@/lib/prisma";

export interface PageBuildContext {
  brand: { name: string; domain: string; industry: string; city: string; state: string; phone: string; logoUrl: string | null; services: string[]; targetAudience: string; brandVoice: string; shortDescription: string };
  topKeywords: Array<{ keyword: string; position: number; clicks: number }>;
  topPages: Array<{ url: string; clicks: number; ctr: number }>;
  conversions: { rate: number; topChannel: string; formPercent: number; callPercent: number; total: number };
  competitorGaps: string[];
  reviews: Array<{ rating: number; comment: string; reviewerName: string }>;
  benchmarks: { conversionRate: number; avgCtr: number; avgPosition: number } | null;
  gscQueries: string[];
}

function safe<T>(result: PromiseSettledResult<T>, fallback: T): T {
  return result.status === "fulfilled" ? result.value : fallback;
}

export async function gatherPageBuildContext(brandId: string): Promise<PageBuildContext | null> {
  const brand = await prisma.brand.findUnique({
    where: { id: brandId },
    include: { profile: true },
  });
  if (!brand) return null;

  const d30 = new Date(Date.now() - 30 * 86400000);
  const industry = brand.profile?.industry || brand.industry || "general";

  const [kwRes, pagesRes, convRes, compRes, reviewRes, benchRes, gscRes] = await Promise.allSettled([
    // Top 10 tracked keywords
    prisma.trackedKeyword.findMany({
      where: { brandId, isActive: true },
      include: { rankings: { orderBy: { checkedAt: "desc" }, take: 1 } },
      take: 10,
    }),
    // Top 5 pages by clicks
    prisma.gscPage.groupBy({
      by: ["pageUrl"],
      where: { brandId, date: { gte: d30 } },
      _sum: { clicks: true, impressions: true },
      _avg: { ctr: true },
      orderBy: { _sum: { clicks: "desc" } },
      take: 5,
    }),
    // Conversion data
    // intentionally unfiltered: internal service; uses raw counts intentionally
    prisma.siteConversion.findMany({
      where: { brandId, timestamp: { gte: d30 } },
      select: { conversionType: true, lastTouchChannel: true },
    }),
    // Competitor content gaps
    prisma.competitor.findMany({
      where: { brandId, isActive: true },
      include: { snapshots: { orderBy: { date: "desc" }, take: 1 } },
      take: 5,
    }),
    // GBP reviews
    prisma.gbpReview.findMany({
      where: { location: { brandId } },
      orderBy: { rating: "desc" },
      take: 20,
      select: { rating: true, comment: true, reviewerName: true },
    }),
    // Industry benchmarks
    prisma.industryBenchmark.findMany({
      where: { industry },
      select: { metric: true, value: true },
    }),
    // Top GSC search queries
    prisma.gscQuery.findMany({
      where: { brandId, date: { gte: d30 } },
      orderBy: { clicks: "desc" },
      take: 15,
      select: { query: true, clicks: true, position: true },
    }),
  ]);

  // Get GBP location for phone/address
  const gbpLocation = await prisma.gbpLocation.findFirst({
    where: { brandId, isActive: true },
    select: { phone: true, city: true, state: true, avgRating: true, totalReviews: true },
  }).catch(() => null);

  // Process keywords
  const keywords = safe(kwRes, []).map((k) => ({
    keyword: k.keyword,
    position: k.rankings[0]?.position ?? 0,
    clicks: 0,
  }));

  // Process top pages
  const pages = safe(pagesRes, []).map((p) => ({
    url: p.pageUrl,
    clicks: p._sum.clicks ?? 0,
    ctr: (p._avg.ctr ?? 0) * 100,
  }));

  // Process conversions. Every SiteConversion.conversionType value
  // that resolves to the form_submitted / phone_call canonical —
  // collapsing the legacy / alias names written by different detection
  // paths. Previously only matched the raw "form_submit" / "phone_call"
  // strings so brands using the tel-link + text-pattern detectors
  // (form-phone.js) had their phone counts undercounted ~3×.
  const convs = safe(convRes, []);
  const total = convs.length || 1;
  const FORM_TYPES = new Set(["form_submit", "form_submitted", "form_submission"]);
  const PHONE_TYPES = new Set(["phone_call", "phone_number_click", "click_to_call"]);
  const forms = convs.filter((c) => FORM_TYPES.has(c.conversionType)).length;
  const calls = convs.filter((c) => PHONE_TYPES.has(c.conversionType)).length;
  const channels: Record<string, number> = {};
  convs.forEach((c) => { if (c.lastTouchChannel) channels[c.lastTouchChannel] = (channels[c.lastTouchChannel] || 0) + 1; });
  const topChannel = Object.entries(channels).sort((a, b) => b[1] - a[1])[0]?.[0] || "organic";

  // Process competitor gaps
  const comps = safe(compRes, [] as Array<{ snapshots: Array<{ newPages: unknown }> }>);
  const gaps: string[] = [];
  for (const c of comps) {
    const snap = c.snapshots?.[0];
    if (snap?.newPages && Array.isArray(snap.newPages)) {
      (snap.newPages as string[]).slice(0, 3).forEach((p) => gaps.push(p));
    }
  }

  // Process benchmarks
  const benchmarks = safe(benchRes, []);
  const benchMap: Record<string, number> = {};
  benchmarks.forEach((b) => { benchMap[b.metric] = b.value; });

  // Process GSC queries
  const gscQueries = safe(gscRes, []);

  const profile = brand.profile;
  const locations = profile?.locations ?? [];

  return {
    brand: {
      name: brand.name,
      domain: brand.domain,
      industry,
      city: gbpLocation?.city || (locations[0] as string) || "",
      state: gbpLocation?.state || "",
      phone: gbpLocation?.phone || "",
      logoUrl: profile?.logoUrl ?? null,
      services: profile?.services ?? [],
      targetAudience: profile?.targetAudience || "",
      brandVoice: profile?.brandVoice || "",
      shortDescription: profile?.shortDescription || "",
    },
    topKeywords: keywords,
    topPages: pages,
    conversions: {
      rate: benchMap["monthly_conversions_per_brand"] ? (benchMap["monthly_conversions_per_brand"] / Math.max(total, 1)) * 100 : 0,
      topChannel,
      formPercent: Math.round((forms / total) * 100),
      callPercent: Math.round((calls / total) * 100),
      total: convs.length,
    },
    competitorGaps: gaps.slice(0, 10),
    reviews: safe(reviewRes, []).filter((r) => r.comment).map((r) => ({
      rating: r.rating,
      comment: r.comment || "",
      reviewerName: r.reviewerName || "Customer",
    })),
    benchmarks: Object.keys(benchMap).length > 0 ? {
      conversionRate: benchMap["monthly_conversions_per_brand"] ?? 0,
      avgCtr: benchMap["avg_ctr"] ?? 0,
      avgPosition: benchMap["avg_position"] ?? 0,
    } : null,
    gscQueries: gscQueries.map((q) => q.query),
  };
}
