import { eq } from "drizzle-orm";
import { getDb } from "@/db";
import { orders, stripeEvents } from "@/db/schema";
import { catalogEntryForPrice, isCheckoutConfigurationComplete } from "@/lib/commerce";

function parseSignature(header: string) {
  const parts = Object.fromEntries(header.split(",").map((part) => part.trim().split("=", 2)));
  return { timestamp: parts.t, signature: parts.v1 };
}

function toHex(bytes: ArrayBuffer) {
  return [...new Uint8Array(bytes)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
}

function constantTimeEqual(left: string, right: string) {
  if (left.length !== right.length) return false;
  let difference = 0;
  for (let index = 0; index < left.length; index += 1) difference |= left.charCodeAt(index) ^ right.charCodeAt(index);
  return difference === 0;
}

async function validSignature(body: string, header: string, secret: string) {
  const { timestamp, signature } = parseSignature(header);
  if (!timestamp || !signature || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
  const digest = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(`${timestamp}.${body}`));
  return constantTimeEqual(toHex(digest), signature);
}

type StripeEvent = {
  id: string;
  type: string;
  data: { object: { id: string; mode?: string; client_reference_id?: string; payment_status?: string; amount_total?: number; currency?: string; customer_details?: { email?: string }; metadata?: Record<string, string> } };
};

type StripeLineItems = {
  data?: Array<{
    amount_total?: number;
    quantity?: number;
    price?: { id?: string; currency?: string; unit_amount?: number };
  }>;
  error?: { message?: string };
};

async function reconcileSession(session: StripeEvent["data"]["object"], stripeSecret: string) {
  if (!isCheckoutConfigurationComplete()) throw new Error("stripe_catalog_incomplete");
  const response = await fetch(`https://api.stripe.com/v1/checkout/sessions/${encodeURIComponent(session.id)}/line_items?limit=10`, {
    headers: { authorization: `Bearer ${stripeSecret}` },
  });
  const payload = (await response.json()) as StripeLineItems;
  if (!response.ok || !payload.data) throw new Error(`stripe_line_items_failed:${payload.error?.message || response.status}`);
  if (payload.data.length !== 1 || payload.data[0].quantity !== 1) throw new Error("stripe_line_items_unexpected");
  const line = payload.data[0];
  const priceId = line.price?.id || "";
  const catalogEntry = catalogEntryForPrice(priceId);
  if (!catalogEntry) throw new Error("stripe_price_not_in_catalog");
  const currency = (session.currency || line.price?.currency || "").toLowerCase();
  const amountTotal = session.amount_total ?? line.amount_total;
  if (currency !== catalogEntry.currency || amountTotal !== catalogEntry.amountCents || line.price?.unit_amount !== catalogEntry.amountCents) {
    throw new Error("stripe_amount_or_currency_mismatch");
  }
  if (session.metadata?.ticket_tier !== catalogEntry.tier) throw new Error("stripe_tier_metadata_mismatch");
  const publicId = session.metadata?.order_public_id || session.client_reference_id || "";
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(publicId) || (session.client_reference_id && session.client_reference_id !== publicId)) {
    throw new Error("stripe_order_reference_mismatch");
  }
  return { catalogEntry, publicId, amountTotal, currency };
}

export async function POST(request: Request) {
  const secret = process.env.STRIPE_WEBHOOK_SECRET;
  const stripeSecret = process.env.STRIPE_SECRET_KEY;
  const signature = request.headers.get("stripe-signature") || "";
  const body = await request.text();
  if (!secret || !stripeSecret || !(await validSignature(body, signature, secret))) return Response.json({ error: "Assinatura inválida." }, { status: 400 });
  try {
    const event = JSON.parse(body) as StripeEvent;
    if (!event.id || !event.type || !event.data?.object?.id) return Response.json({ error: "Evento inválido." }, { status: 400 });
    const db = getDb();
    const duplicate = await db.select({ id: stripeEvents.id }).from(stripeEvents).where(eq(stripeEvents.eventId, event.id)).limit(1);
    if (duplicate.length) return Response.json({ received: true, duplicate: true });

    if (["checkout.session.completed", "checkout.session.async_payment_succeeded", "checkout.session.async_payment_failed"].includes(event.type)) {
      const session = event.data.object;
      if (session.mode !== "payment") throw new Error("stripe_session_mode_invalid");
      const reconciled = await reconcileSession(session, stripeSecret);
      const paid = session.payment_status === "paid" && event.type !== "checkout.session.async_payment_failed";
      const paymentStatus = event.type === "checkout.session.async_payment_failed" ? "failed" : paid ? "paid" : "pending";
      await db.insert(orders).values({
        publicId: reconciled.publicId, stripeSessionId: session.id, ticketTier: reconciled.catalogEntry.tier, paymentStatus,
        amountTotal: reconciled.amountTotal, currency: reconciled.currency,
        customerEmail: session.customer_details?.email ?? null, updatedAt: new Date().toISOString(),
      }).onConflictDoUpdate({
        target: orders.stripeSessionId,
        set: { paymentStatus, amountTotal: reconciled.amountTotal, currency: reconciled.currency, customerEmail: session.customer_details?.email ?? null, updatedAt: new Date().toISOString() },
      });
    }
    await db.insert(stripeEvents).values({ eventId: event.id, eventType: event.type }).onConflictDoNothing();
    return Response.json({ received: true });
  } catch (error) {
    console.error("stripe_webhook_failed", error);
    return Response.json({ error: "Falha no processamento do evento." }, { status: 500 });
  }
}
