import { headers } from "next/headers";
import { NextResponse } from "next/server";
import Stripe from "stripe";
import { initDb } from "@/lib/db";
import { getStripe } from "@/lib/stripe/stripe-client";
import { applyPlanToWorkspace } from "@/lib/queries/billing-queries";
import type { PlanTier } from "@/types";
import type { SubscriptionStatus } from "@/types";

export const runtime = "nodejs";

function mapSubscriptionStatus(
  stripeStatus: Stripe.Subscription.Status
): SubscriptionStatus {
  if (stripeStatus === "active" || stripeStatus === "trialing") {
    return "active";
  }
  if (stripeStatus === "past_due" || stripeStatus === "unpaid") {
    return "past_due";
  }
  if (
    stripeStatus === "canceled" ||
    stripeStatus === "incomplete_expired"
  ) {
    return "canceled";
  }
  return "past_due";
}

async function recordInvoiceFromStripe(
  workspaceId: string,
  stripeInvoice: Stripe.Invoice
) {
  if (!stripeInvoice.id || stripeInvoice.amount_paid == null) return;

  const { Invoice } = initDb();
  const existing = await Invoice.findOne({
    where: { stripeInvoiceId: stripeInvoice.id },
  });
  if (existing) return;

  await Invoice.create({
    workspaceId,
    amount: stripeInvoice.amount_paid,
    currency: (stripeInvoice.currency ?? "usd").toUpperCase(),
    status: stripeInvoice.status === "paid" ? "paid" : "open",
    stripeInvoiceId: stripeInvoice.id,
    issuedAt: new Date(
      (stripeInvoice.status_transitions?.paid_at ??
        stripeInvoice.created) * 1000
    ),
  });
}

export async function POST(request: Request) {
  const stripe = getStripe();
  const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;

  if (!stripe || !webhookSecret) {
    return NextResponse.json(
      { error: "Stripe webhook not configured" },
      { status: 503 }
    );
  }

  const body = await request.text();
  const signature = headers().get("stripe-signature");

  if (!signature) {
    return NextResponse.json({ error: "Missing signature" }, { status: 400 });
  }

  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(body, signature, webhookSecret);
  } catch {
    return NextResponse.json({ error: "Invalid signature" }, { status: 400 });
  }

  const { Workspace, AuditLog } = initDb();

  try {
    switch (event.type) {
      case "checkout.session.completed": {
        const session = event.data.object as Stripe.Checkout.Session;
        const workspaceId = session.metadata?.workspaceId;
        const planTier = (session.metadata?.planTier ?? "pro") as PlanTier;
        const billingCycle =
          (session.metadata?.billingCycle as "monthly" | "annual") ??
          "monthly";

        if (workspaceId) {
          const paid =
            session.payment_status === "paid" ||
            session.payment_status === "no_payment_required";

          await Workspace.update(
            {
              stripeCustomerId:
                typeof session.customer === "string"
                  ? session.customer
                  : session.customer?.id ?? undefined,
              stripeSubscriptionId:
                typeof session.subscription === "string"
                  ? session.subscription
                  : session.subscription?.id ?? undefined,
            },
            { where: { id: workspaceId } }
          );

          if (paid) {
            await applyPlanToWorkspace(workspaceId, planTier, billingCycle);
            await Workspace.update(
              { subscriptionStatus: "active" },
              { where: { id: workspaceId } }
            );
          }

          await AuditLog.create({
            workspaceId,
            action: "billing.checkout_completed",
            metadata: {
              message: paid
                ? `Payment received — upgraded to ${planTier}`
                : `Checkout completed — awaiting payment (${session.payment_status})`,
              planTier,
              paymentStatus: session.payment_status,
              event: event.type,
            },
          });
        }
        break;
      }

      case "checkout.session.async_payment_succeeded": {
        const session = event.data.object as Stripe.Checkout.Session;
        const workspaceId = session.metadata?.workspaceId;
        const planTier = (session.metadata?.planTier ?? "pro") as PlanTier;
        const billingCycle =
          (session.metadata?.billingCycle as "monthly" | "annual") ??
          "monthly";

        if (workspaceId) {
          await applyPlanToWorkspace(workspaceId, planTier, billingCycle);
          await Workspace.update(
            { subscriptionStatus: "active" },
            { where: { id: workspaceId } }
          );
        }
        break;
      }

      case "customer.subscription.updated": {
        const sub = event.data.object as Stripe.Subscription;
        const workspaceId = sub.metadata?.workspaceId;
        if (!workspaceId) break;

        const status = mapSubscriptionStatus(sub.status);

        await Workspace.update(
          {
            stripeSubscriptionId: sub.id,
            subscriptionStatus: status,
          },
          { where: { id: workspaceId } }
        );

        await AuditLog.create({
          workspaceId,
          action: "stripe.webhook",
          metadata: {
            message: `Subscription ${sub.status}`,
            event: event.type,
          },
        });
        break;
      }

      case "customer.subscription.deleted": {
        const sub = event.data.object as Stripe.Subscription;
        const workspaceId = sub.metadata?.workspaceId;
        if (!workspaceId) break;

        await applyPlanToWorkspace(workspaceId, "free");
        await Workspace.update(
          {
            stripeSubscriptionId: null,
            subscriptionStatus: "canceled",
          },
          { where: { id: workspaceId } }
        );

        await AuditLog.create({
          workspaceId,
          action: "billing.subscription_canceled",
          metadata: { event: event.type },
        });
        break;
      }

      case "invoice.paid": {
        const inv = event.data.object as Stripe.Invoice;
        const workspaceId =
          inv.metadata?.workspaceId ??
          (typeof inv.customer === "string"
            ? (
                await Workspace.findOne({
                  where: { stripeCustomerId: inv.customer },
                })
              )?.id
            : undefined);

        if (workspaceId) {
          await recordInvoiceFromStripe(workspaceId, inv);
          await AuditLog.create({
            workspaceId,
            action: "stripe.webhook",
            metadata: {
              message: "Payment webhook received — Stripe",
              event: event.type,
            },
          });
        }
        break;
      }

      case "invoice.payment_failed": {
        const inv = event.data.object as Stripe.Invoice;
        const customerId =
          typeof inv.customer === "string" ? inv.customer : inv.customer?.id;

        if (customerId) {
          await Workspace.update(
            { subscriptionStatus: "past_due" },
            { where: { stripeCustomerId: customerId } }
          );
        }

        await AuditLog.create({
          action: "billing.payment_failed",
          metadata: { message: "Invoice payment failed", event: event.type },
        });
        break;
      }

      default:
        break;
    }
  } catch (err) {
    console.error("Stripe webhook error:", err);
    return NextResponse.json({ error: "Webhook handler failed" }, { status: 500 });
  }

  return NextResponse.json({ received: true });
}
