import { NextRequest, NextResponse } from "next/server";
import { requireStaffAuth } from "@/lib/staff-auth";
import { prisma } from "@/lib/db";
import { stripe } from "@/lib/stripe";
import { getDataSource } from "@/lib/data-source";

/**
 * GET /api/staff/users/[id]/billing/invoices
 * Get all invoice history for a user (from Stripe + local billing_history)
 */
export async function GET(
  request: NextRequest,
  { params }: { params: { id: string } },
) {
  try {
    const staffUser = await requireStaffAuth();
    if (!staffUser) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    const userId = params.id;

    // Get user with Stripe customer ID
    const user = await prisma.users.findUnique({
      where: { id: userId },
      select: {
        id: true,
        email: true,
        name: true,
        stripeCustomerId: true,
        subscriptions: {
          select: {
            id: true,
            stripeCustomerId: true,
            stripeSubscriptionId: true,
            tierId: true,
            status: true,
            billingPeriod: true,
          },
          orderBy: { createdAt: "desc" },
          take: 1,
        },
      },
    });

    if (!user) {
      return NextResponse.json({ error: "User not found" }, { status: 404 });
    }

    // Get Stripe customer ID from subscription or user
    const stripeCustomerId =
      user.subscriptions[0]?.stripeCustomerId || user.stripeCustomerId;

    // Fetch invoices from Stripe if customer exists (Stripe calls stay as-is)
    let stripeInvoices: any[] = [];
    if (stripeCustomerId) {
      try {
        const invoicesResponse = await stripe.invoices.list({
          customer: stripeCustomerId,
          limit: 100,
          expand: ["data.subscription", "data.charge"],
        });

        stripeInvoices = invoicesResponse.data.map((invoice) => ({
          id: invoice.id,
          type: "stripe_invoice",
          number: invoice.number,
          status: invoice.status,
          amount: invoice.amount_paid || invoice.amount_due,
          currency: invoice.currency?.toUpperCase() || "GBP",
          description: getInvoiceDescription(invoice),
          createdAt: new Date(invoice.created * 1000).toISOString(),
          paidAt: invoice.status_transitions?.paid_at
            ? new Date(invoice.status_transitions.paid_at * 1000).toISOString()
            : null,
          hostedInvoiceUrl: invoice.hosted_invoice_url,
          invoicePdf: invoice.invoice_pdf,
          billingReason: invoice.billing_reason,
          periodStart: invoice.period_start
            ? new Date(invoice.period_start * 1000).toISOString()
            : null,
          periodEnd: invoice.period_end
            ? new Date(invoice.period_end * 1000).toISOString()
            : null,
        }));
      } catch (stripeError) {
        console.error("Error fetching Stripe invoices:", stripeError);
      }
    }

    // Fetch local billing history and payments -- Convex or Prisma
    let localPayments: any[] = [];
    let localPaymentRecords: any[] = [];

    if (getDataSource("billing") === "convex" && stripeCustomerId) {
      try {
        const { convexQuery } = await import("@/lib/convex-client");

        const [billingHistoryConvex, paymentsConvex] = await Promise.all([
          convexQuery("billing/queries:getBillingHistory", {
            customerId: stripeCustomerId,
            limit: 100,
          }),
          convexQuery("billing/queries:getPayments", {
            customerId: stripeCustomerId,
          }),
        ]);

        localPayments = ((billingHistoryConvex as any[]) || []).map(
          (record: any) => ({
            id: record._id || record.prismaId,
            type: "billing_event",
            event: record.event,
            amount: record.amount,
            currency: record.currency?.toUpperCase() || "GBP",
            description: formatBillingEvent(record.event),
            createdAt: new Date(record.createdAt).toISOString(),
            invoiceId: record.invoiceId,
            paymentIntentId: record.paymentIntentId,
            metadata: record.metadata,
          }),
        );

        const rawPayments = (paymentsConvex as any[]) || [];
        localPaymentRecords = rawPayments.map((payment: any) => ({
          id: payment._id || payment.prismaId,
          type: "payment",
          stripePaymentIntentId: payment.stripePaymentIntentId,
          amount: Math.round(payment.amount * 100),
          currency: payment.currency?.toUpperCase() || "GBP",
          status: payment.status,
          description: `Payment - ${payment.status}`,
          createdAt: new Date(payment.createdAt).toISOString(),
          succeededAt: payment.succeededAt
            ? new Date(payment.succeededAt).toISOString()
            : null,
          failedAt: payment.failedAt
            ? new Date(payment.failedAt).toISOString()
            : null,
          errorMessage: payment.errorMessage,
        }));
      } catch (convexError) {
        console.error(
          "Convex billing history failed, falling back to Prisma:",
          convexError,
        );
        localPayments = [];
        localPaymentRecords = [];
      }
    }

    // Prisma path (default or Convex fallback)
    if (
      getDataSource("billing") !== "convex" ||
      (localPayments.length === 0 && localPaymentRecords.length === 0)
    ) {
      const billingHistory = await prisma.billing_history.findMany({
        where: {
          customerId: stripeCustomerId || undefined,
          subscriptionId: user.subscriptions[0]?.id,
        },
        orderBy: { createdAt: "desc" },
        take: 100,
      });

      localPayments = billingHistory.map((record) => ({
        id: record.id,
        type: "billing_event",
        event: record.event,
        amount: record.amount,
        currency: record.currency?.toUpperCase() || "GBP",
        description: formatBillingEvent(record.event),
        createdAt: record.createdAt.toISOString(),
        invoiceId: record.invoiceId,
        paymentIntentId: record.paymentIntentId,
        metadata: record.metadata,
      }));

      const payments = stripeCustomerId
        ? await prisma.payments.findMany({
            where: { customerId: stripeCustomerId },
            orderBy: { createdAt: "desc" },
            take: 100,
          })
        : [];

      localPaymentRecords = payments.map((payment) => ({
        id: payment.id,
        type: "payment",
        stripePaymentIntentId: payment.stripePaymentIntentId,
        amount: Math.round(payment.amount * 100),
        currency: payment.currency?.toUpperCase() || "GBP",
        status: payment.status,
        description: `Payment - ${payment.status}`,
        createdAt: payment.createdAt.toISOString(),
        succeededAt: payment.succeededAt?.toISOString(),
        failedAt: payment.failedAt?.toISOString(),
        errorMessage: payment.errorMessage,
      }));
    }

    // Combine and sort all records by date (most recent first)
    const allRecords = [
      ...stripeInvoices,
      ...localPayments,
      ...localPaymentRecords,
    ].sort(
      (a, b) =>
        new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
    );

    // Calculate summary stats
    const summary = {
      totalPaid: stripeInvoices
        .filter((i) => i.status === "paid")
        .reduce((sum, i) => sum + (i.amount || 0), 0),
      totalInvoices: stripeInvoices.length,
      paidInvoices: stripeInvoices.filter((i) => i.status === "paid").length,
      openInvoices: stripeInvoices.filter((i) => i.status === "open").length,
      failedPayments: localPaymentRecords.filter((p) => p.status === "failed")
        .length,
    };

    return NextResponse.json({
      invoices: stripeInvoices,
      billingHistory: localPayments,
      payments: localPaymentRecords,
      allRecords,
      summary,
      subscription: user.subscriptions[0] || null,
    });
  } catch (error) {
    console.error("Failed to fetch user invoices:", error);
    return NextResponse.json(
      { error: "Failed to fetch invoice history" },
      { status: 500 },
    );
  }
}

function getInvoiceDescription(invoice: any): string {
  if (invoice.billing_reason === "subscription_create")
    return "Subscription started";
  if (invoice.billing_reason === "subscription_cycle")
    return "Subscription renewal";
  if (invoice.billing_reason === "subscription_update")
    return "Plan change / upgrade";
  if (invoice.billing_reason === "manual") return "Manual invoice";
  return "Invoice";
}

function formatBillingEvent(event: string): string {
  const eventMap: Record<string, string> = {
    subscription_created: "Subscription created",
    subscription_upgraded: "Plan upgraded",
    subscription_downgraded: "Plan downgraded",
    billing_period_changed: "Billing period changed",
    payment_succeeded: "Payment successful",
    payment_failed: "Payment failed",
    invoice_paid: "Invoice paid",
    refund_created: "Refund issued",
    upgrade_invoice_created: "Upgrade invoice",
  };
  return eventMap[event] || event.replace(/_/g, " ");
}
