/**
 * POST /api/signals/dismiss
 *
 * Persists a user's dismissal of a Signals Center row. The Signals
 * Center aggregates two families of rows:
 *
 *   1. "Detection" signals — id prefix `detection-` — each backed by
 *      a real SiteEvent row written by the signal-detection cron.
 *      Dismissing updates that row's eventData.status to "resolved",
 *      which generateSignals already filters out (see
 *      src/lib/services/signals.ts → generateDetectedSignals, the
 *      `if (data.status === "resolved") continue` guard).
 *
 *   2. "Derived" signals — synthetic ids computed from underlying
 *      data (e.g. `tech_critical_${auditId}`, `dead_count_${brandId}`,
 *      `conv_rev_up_${brandId}`). No row to mutate; we instead write
 *      a new SiteEvent with eventType="signal_dismissed" + the
 *      signal id in eventData. generateSignals consults these on
 *      read to suppress recently-dismissed synthetic signals for
 *      DISMISSAL_TTL_DAYS (default 14 — synthetic signals should
 *      re-surface if the underlying condition persists long enough
 *      for the user to care again).
 *
 * The response is identical regardless of path so the client can
 * treat dismissal as a single operation.
 */

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

export const dynamic = "force-dynamic";

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) as { brandId?: string; signalId?: string } | null;
  const brandId = body?.brandId;
  const signalId = body?.signalId;
  if (!brandId || !signalId) {
    return NextResponse.json({ error: "brandId and signalId 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 });
  }

  if (signalId.startsWith("detection-")) {
    const siteEventId = signalId.slice("detection-".length);
    // Only update SiteEvent rows that BELONG to this brand — a
    // malicious client passing another brand's event id would
    // otherwise hit the one they don't have membership in. Using a
    // compound where clause (id + brandId) on updateMany handles
    // the "not found" case naturally — 0 affected rows.
    const updated = await prisma.siteEvent.updateMany({
      where: { id: siteEventId, brandId },
      // Merge-preserve existing eventData fields. Prisma's Json
      // update doesn't offer partial-merge natively, so we read +
      // rewrite.
      data: {},
    }).catch(() => ({ count: 0 }));
    if (updated.count > 0) {
      const row = await prisma.siteEvent.findUnique({ where: { id: siteEventId }, select: { eventData: true } });
      const existing = (row?.eventData && typeof row.eventData === "object" ? row.eventData : {}) as Record<string, unknown>;
      await prisma.siteEvent.update({
        where: { id: siteEventId },
        data: {
          eventData: { ...existing, status: "resolved", dismissedAt: new Date().toISOString(), dismissedBy: user.id },
        },
      }).catch(() => { /* swallow — next call will retry */ });
    }
    return NextResponse.json({ ok: true, kind: "detection", persisted: updated.count > 0 });
  }

  // Synthetic / derived signal — write a dismissal marker. No unique
  // constraint on (brandId, eventType, eventData); repeated dismisses
  // of the same id just write another row, which is harmless given
  // generateSignals only checks presence of any matching row.
  // pageUrl is non-nullable on SiteEvent — use an internal sentinel
  // value since this is a meta-event, not a page interaction.
  await prisma.siteEvent.create({
    data: {
      brandId,
      eventType: "signal_dismissed",
      pageUrl: `internal:signal-dismissal`,
      eventData: {
        dismissedSignalId: signalId,
        dismissedAt: new Date().toISOString(),
        dismissedBy: user.id,
      },
    },
  }).catch((err) => {
    console.warn("[signals:dismiss] derived-signal marker write failed", { brandId, signalId, err: err instanceof Error ? err.message : "unknown" });
  });

  return NextResponse.json({ ok: true, kind: "derived", persisted: true });
}
