/**
 * POST /api/site-tag/seo-monitor
 *
 * Upserts a PageSEOSnapshot per (brand, pageUrl). When the snapshot
 * differs from the previous one, logs a SiteEvent of type "seo_change"
 * with a diff payload so the backend can alert on accidental noindex,
 * canonical flips, schema removals, and mixed-content regressions.
 */

import { NextResponse } from "next/server";
import { getCorsHeaders, resolveSiteFromTag } from "@/lib/services/page-lifecycle";
import { prisma } from "@/lib/prisma";

export const dynamic = "force-dynamic";

export async function OPTIONS(req: Request) {
  return new NextResponse(null, { status: 204, headers: getCorsHeaders(req) });
}

interface SeoBody {
  siteId?: string;
  tagId?: string;
  pageUrl?: string;
  title?: string | null;
  metaDescription?: string | null;
  canonical?: string | null;
  robots?: string | null;
  h1Count?: number;
  h1Texts?: unknown;
  h1s?: unknown;
  ogTags?: Record<string, string>;
  ogTitle?: string;
  ogDescription?: string;
  ogImage?: string;
  hasSchema?: boolean;
  schemaTypes?: unknown;
  hreflang?: unknown;
  mixedContent?: boolean;
  noindexed?: boolean;
}

type Diff = Record<string, { old: unknown; new: unknown }>;

function diffSnapshot(prev: Record<string, unknown>, next: Record<string, unknown>): Diff {
  const changes: Diff = {};
  const keys = ["title", "metaDescription", "canonical", "robots", "h1Count", "hasSchema", "noindexed", "mixedContent"];
  for (const key of keys) {
    const a = prev[key];
    const b = next[key];
    if ((a ?? null) !== (b ?? null)) changes[key] = { old: a ?? null, new: b ?? null };
  }
  // schemaTypes is an array — compare as sorted JSON
  const aTypes = JSON.stringify(Array.isArray(prev.schemaTypes) ? [...(prev.schemaTypes as string[])].sort() : []);
  const bTypes = JSON.stringify(Array.isArray(next.schemaTypes) ? [...(next.schemaTypes as string[])].sort() : []);
  if (aTypes !== bTypes) changes.schemaTypes = { old: prev.schemaTypes ?? [], new: next.schemaTypes ?? [] };
  return changes;
}

export async function POST(req: Request) {
  const cors = getCorsHeaders(req);
  let body: SeoBody;
  try {
    body = (await req.json()) as SeoBody;
  } catch {
    return NextResponse.json({ ok: false, error: "Invalid JSON" }, { status: 400, headers: cors });
  }

  const siteId = body.siteId || body.tagId;
  const resolved = await resolveSiteFromTag(siteId, body.pageUrl || "");
  if (!resolved.ok) {
    return NextResponse.json({ ok: false, error: resolved.error }, { status: resolved.status, headers: cors });
  }
  if (!body.pageUrl) {
    return NextResponse.json({ ok: false, error: "pageUrl required" }, { status: 400, headers: cors });
  }

  const brandId = resolved.site.brandId;
  const pageUrl = String(body.pageUrl).slice(0, 2048);
  const schemaTypes = Array.isArray(body.schemaTypes) ? body.schemaTypes : [];
  const noindexed = !!body.noindexed || /noindex/i.test(body.robots || "");

  const nextData = {
    title: body.title ?? null,
    metaDescription: body.metaDescription ?? null,
    canonical: body.canonical ?? null,
    robots: body.robots ?? null,
    h1Count: typeof body.h1Count === "number" ? body.h1Count : null,
    hasSchema: typeof body.hasSchema === "boolean" ? body.hasSchema : schemaTypes.length > 0,
    schemaTypes: schemaTypes as unknown as object,
    noindexed,
    mixedContent: !!body.mixedContent,
  };

  try {
    const prev = await prisma.pageSEOSnapshot.findUnique({
      where: { brandId_pageUrl: { brandId, pageUrl } },
    });

    await prisma.pageSEOSnapshot.upsert({
      where: { brandId_pageUrl: { brandId, pageUrl } },
      create: { brandId, pageUrl, ...nextData },
      update: { ...nextData, detectedAt: new Date() },
    });

    if (prev) {
      const changes = diffSnapshot(prev as unknown as Record<string, unknown>, nextData as unknown as Record<string, unknown>);
      if (Object.keys(changes).length > 0) {
        await prisma.siteEvent.create({
          data: {
            brandId,
            pageUrl,
            eventType: "seo_change",
            eventData: { changes } as unknown as object,
          },
        });
      }
    }
  } catch (err) {
    console.error("[site-tag/seo-monitor] write failed", err);
    return NextResponse.json({ ok: false, error: "Write failed" }, { status: 500, headers: cors });
  }

  return NextResponse.json({ ok: true }, { headers: cors });
}
