/**
 * POST /api/ai-indicators
 *
 * Batch endpoint that returns AI indicator data for a set of keywords
 * and/or pages. Powers the AiBadge components across the app.
 * Results cached in-memory for 10 minutes per brand.
 */

import { NextResponse } from "next/server";
import { getCurrentUser } from "@/lib/auth";
import { prisma } from "@/lib/prisma";

export const dynamic = "force-dynamic";

const memCache = new Map<string, { data: unknown; ts: number }>();
const CACHE_TTL = 10 * 60 * 1000;

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);
  if (!body?.brandId) return NextResponse.json({ error: "brandId required" }, { status: 400 });

  const { brandId, keywords = [], pages = [] } = body as {
    brandId: string;
    keywords: string[];
    pages: string[];
  };

  const cacheKey = `${brandId}:${keywords.length}:${pages.length}`;
  const cached = memCache.get(cacheKey);
  if (cached && Date.now() - cached.ts < CACHE_TTL) {
    return NextResponse.json(cached.data);
  }

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

  const d30 = new Date(Date.now() - 30 * 86_400_000);

  const keywordResults: Record<string, {
    cited: boolean; citations: number; aiVisits: number;
    aiConversions: number; opportunity: boolean; aiDiscovered?: boolean;
  }> = {};

  const pageResults: Record<string, {
    cited: boolean; citations: number; aiVisits: number;
    aiConversions: number; opportunity: boolean; resonanceScore?: number;
  }> = {};

  if (keywords.length > 0) {
    // Only show "opportunity" badges if the brand has SOME citation data
    // (i.e., the ai-citation-check cron has run at least once). When
    // count === 0, every keyword would falsely show "AI Opportunity".
    const totalCitations = await prisma.aiCitation.count({
      where: { brandId },
    }).catch(() => 0);
    const hasCitationData = totalCitations > 0;

    const [citations, attributions, convAttributions] = await Promise.all([
      prisma.aiCitation.findMany({
        where: { brandId, keyword: { in: keywords }, checkedAt: { gte: d30 } },
        select: { keyword: true, brandCited: true },
      }).catch(() => []),

      prisma.aiAttribution.groupBy({
        by: ["queryContext"],
        where: { brandId, timestamp: { gte: d30 }, queryContext: { not: null } },
        _count: true,
      }).catch(() => []),

      prisma.aiAttribution.groupBy({
        by: ["queryContext"],
        where: { brandId, timestamp: { gte: d30 }, converted: true, queryContext: { not: null } },
        _count: true,
      }).catch(() => []),
    ]);

    const citationMap = new Map<string, { cited: boolean; count: number }>();
    for (const c of citations) {
      const entry = citationMap.get(c.keyword) ?? { cited: false, count: 0 };
      if (c.brandCited) entry.cited = true;
      entry.count++;
      citationMap.set(c.keyword, entry);
    }

    const attrMap = new Map<string, number>();
    for (const a of attributions) {
      if (!a.queryContext) continue;
      const key = a.queryContext.replace(/^\[inferred\]\s*/i, "").toLowerCase().trim();
      attrMap.set(key, (attrMap.get(key) ?? 0) + (typeof a._count === "number" ? a._count : 0));
    }

    const convMap = new Map<string, number>();
    for (const a of convAttributions) {
      if (!a.queryContext) continue;
      const key = a.queryContext.replace(/^\[inferred\]\s*/i, "").toLowerCase().trim();
      convMap.set(key, (convMap.get(key) ?? 0) + (typeof a._count === "number" ? a._count : 0));
    }

    for (const kw of keywords) {
      const kwLower = kw.toLowerCase();
      const citation = citationMap.get(kw);
      const aiVisits = attrMap.get(kwLower) ?? 0;
      const aiConversions = convMap.get(kwLower) ?? 0;

      keywordResults[kw] = {
        cited: citation?.cited ?? false,
        citations: citation?.count ?? 0,
        aiVisits,
        aiConversions,
        opportunity: hasCitationData && !citation?.cited && aiVisits === 0,
      };
    }
  }

  if (pages.length > 0) {
    const [pageAttr, pageConv, pageCitations] = await Promise.all([
      prisma.aiAttribution.groupBy({
        by: ["landingPage"],
        where: { brandId, timestamp: { gte: d30 }, landingPage: { in: pages } },
        _count: true,
      }).catch(() => []),

      prisma.aiAttribution.groupBy({
        by: ["landingPage"],
        where: { brandId, timestamp: { gte: d30 }, converted: true, landingPage: { in: pages } },
        _count: true,
      }).catch(() => []),

      prisma.aiCitation.findMany({
        where: { brandId, citedUrl: { in: pages }, checkedAt: { gte: d30 } },
        select: { citedUrl: true, brandCited: true },
      }).catch(() => []),
    ]);

    const attrMap = new Map(pageAttr.map((p) => [p.landingPage, typeof p._count === "number" ? p._count : 0]));
    const convMap = new Map(pageConv.map((p) => [p.landingPage, typeof p._count === "number" ? p._count : 0]));
    const citedPages = new Set(pageCitations.filter((c) => c.brandCited).map((c) => c.citedUrl));

    for (const page of pages) {
      pageResults[page] = {
        cited: citedPages.has(page),
        citations: pageCitations.filter((c) => c.citedUrl === page).length,
        aiVisits: attrMap.get(page) ?? 0,
        aiConversions: convMap.get(page) ?? 0,
        opportunity: false,
      };
    }
  }

  const result = { keywords: keywordResults, pages: pageResults };
  memCache.set(cacheKey, { data: result, ts: Date.now() });

  return NextResponse.json(result);
}
