/**
 * /api/site-tag/custom-events
 * ----------------------------
 * GET    ?brandId=xxx                  → list custom events for the brand
 * POST   { brandId, event }            → create a new custom event
 * PATCH  { brandId, eventId, patch }   → update an existing custom event
 * DELETE ?brandId=xxx&eventId=yyy      → delete a custom event
 *
 * Custom events are stored as a JSON array on TrackedSite.customEvents.
 * The schema field may not exist yet on every environment — every query
 * is wrapped in try/catch and returns an empty list on failure so the
 * UI never breaks.
 */

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

export const dynamic = "force-dynamic";

// Internal type — not exported so this file stays compatible with
// Next.js's "route files only export HTTP handlers + route config"
// rule. No consumers outside this file; if one shows up later, move
// the type to src/lib/ rather than re-exporting from a route.
interface CustomEventConfig {
  id: string;
  name: string;
  triggerType: "click" | "form_submit" | "page_visit" | "scroll_to" | "time_on_page";
  triggerConfig: Record<string, string | number>;
  properties: Array<{ name: string; source: "fixed" | "element_text" | "element_attr" | "url_param"; value: string }>;
  isActive: boolean;
  createdAt: string;
  lastTriggered?: string | null;
}

async function checkBrandAccess(brandId: string, userId: string) {
  const brand = await prisma.brand.findUnique({
    where: { id: brandId },
    include: { organization: { include: { memberships: true } } },
  });
  if (!brand) return null;
  if (!brand.organization.memberships.some((m) => m.userId === userId)) return null;
  return brand;
}

async function getSite(brandId: string) {
  return prisma.trackedSite.findUnique({
    where: { brandId },
    select: { id: true, customEvents: true },
  });
}

function readEvents(site: { customEvents: unknown } | null): CustomEventConfig[] {
  if (!site) return [];
  const raw = site.customEvents;
  if (Array.isArray(raw)) return raw as CustomEventConfig[];
  return [];
}

// ─── GET ────────────────────────────────────────────────────────────────────

export async function GET(req: Request) {
  try {
    const user = await getCurrentUser();
    if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

    const { searchParams } = new URL(req.url);
    const brandId = searchParams.get("brandId");
    if (!brandId) return NextResponse.json({ error: "brandId required" }, { status: 400 });

    if (!(await checkBrandAccess(brandId, user.id))) {
      return NextResponse.json({ error: "Access denied" }, { status: 403 });
    }

    const site = await getSite(brandId);
    return NextResponse.json({ events: readEvents(site) });
  } catch (err) {
    console.error("[custom-events] GET failed", { error: String(err) });
    return NextResponse.json({ events: [] });
  }
}

// ─── POST (create) ──────────────────────────────────────────────────────────

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();
    const brandId = body?.brandId as string | undefined;
    const event = body?.event as Partial<CustomEventConfig> | undefined;
    if (!brandId || !event) return NextResponse.json({ error: "brandId and event required" }, { status: 400 });
    if (!event.name || !event.triggerType) {
      return NextResponse.json({ error: "name and triggerType required" }, { status: 400 });
    }

    if (!(await checkBrandAccess(brandId, user.id))) {
      return NextResponse.json({ error: "Access denied" }, { status: 403 });
    }

    const site = await getSite(brandId);
    if (!site) return NextResponse.json({ error: "Site not found" }, { status: 404 });

    const existing = readEvents(site);
    const newEvent: CustomEventConfig = {
      id: randomBytes(8).toString("hex"),
      name: event.name,
      triggerType: event.triggerType,
      triggerConfig: event.triggerConfig ?? {},
      properties: event.properties ?? [],
      isActive: event.isActive ?? true,
      createdAt: new Date().toISOString(),
      lastTriggered: null,
    };

    const next = [...existing, newEvent];
    await prisma.trackedSite.update({
      where: { id: site.id },
      data: { customEvents: next as object },
    });

    return NextResponse.json({ event: newEvent, events: next });
  } catch (err) {
    console.error("[custom-events] POST failed", { error: String(err) });
    return NextResponse.json({ error: "Failed to create event" }, { status: 500 });
  }
}

// ─── PATCH (update) ─────────────────────────────────────────────────────────

export async function PATCH(req: Request) {
  try {
    const user = await getCurrentUser();
    if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

    const body = await req.json();
    const brandId = body?.brandId as string | undefined;
    const eventId = body?.eventId as string | undefined;
    const patch = body?.patch as Partial<CustomEventConfig> | undefined;
    if (!brandId || !eventId || !patch) {
      return NextResponse.json({ error: "brandId, eventId, and patch required" }, { status: 400 });
    }

    if (!(await checkBrandAccess(brandId, user.id))) {
      return NextResponse.json({ error: "Access denied" }, { status: 403 });
    }

    const site = await getSite(brandId);
    if (!site) return NextResponse.json({ error: "Site not found" }, { status: 404 });

    const existing = readEvents(site);
    const next = existing.map((e) => (e.id === eventId ? { ...e, ...patch, id: e.id, createdAt: e.createdAt } : e));

    await prisma.trackedSite.update({
      where: { id: site.id },
      data: { customEvents: next as object },
    });

    return NextResponse.json({ events: next });
  } catch (err) {
    console.error("[custom-events] PATCH failed", { error: String(err) });
    return NextResponse.json({ error: "Failed to update event" }, { status: 500 });
  }
}

// ─── DELETE ─────────────────────────────────────────────────────────────────

export async function DELETE(req: Request) {
  try {
    const user = await getCurrentUser();
    if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

    const { searchParams } = new URL(req.url);
    const brandId = searchParams.get("brandId");
    const eventId = searchParams.get("eventId");
    if (!brandId || !eventId) {
      return NextResponse.json({ error: "brandId and eventId required" }, { status: 400 });
    }

    if (!(await checkBrandAccess(brandId, user.id))) {
      return NextResponse.json({ error: "Access denied" }, { status: 403 });
    }

    const site = await getSite(brandId);
    if (!site) return NextResponse.json({ error: "Site not found" }, { status: 404 });

    const next = readEvents(site).filter((e) => e.id !== eventId);
    await prisma.trackedSite.update({
      where: { id: site.id },
      data: { customEvents: next as object },
    });

    return NextResponse.json({ events: next });
  } catch (err) {
    console.error("[custom-events] DELETE failed", { error: String(err) });
    return NextResponse.json({ error: "Failed to delete event" }, { status: 500 });
  }
}
