import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/lib/auth";
import { stripe } from "@/lib/stripe";
import { logger } from "@/lib/logger";
import { getAuthenticatedConvexUser } from "@/lib/convex-auth-state";
import { getActiveConvexSubscription } from "@/lib/convex-billing-state";
import { convexQuery } from "@/lib/convex-client";

export const dynamic = "force-dynamic";

async function resolveStripeCustomerId(
  userId: string,
  fallbackCustomerId?: string | null,
) {
  const directSubscription = await getActiveConvexSubscription(userId);
  if (directSubscription?.stripeCustomerId) {
    return directSubscription.stripeCustomerId;
  }

  const orgState = await convexQuery<{
    organization: { ownerId: string };
  }>("organizations/queries:getOrganizationStateByUserId", {
    userId,
  });

  if (
    orgState?.organization?.ownerId &&
    orgState.organization.ownerId !== userId
  ) {
    const ownerSubscription = await getActiveConvexSubscription(
      orgState.organization.ownerId,
    );
    if (ownerSubscription?.stripeCustomerId) {
      return ownerSubscription.stripeCustomerId;
    }
  }

  return fallbackCustomerId ?? null;
}

function getInvoiceDescription(invoice: { billing_reason?: string | null }) {
  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 "Subscription updated";
  }
  if (invoice.billing_reason === "manual") {
    return "Manual invoice";
  }
  return "Invoice";
}

export async function GET(request: NextRequest) {
  try {
    const user = await getAuthenticatedConvexUser(request, auth);
    if (!user) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    const { searchParams } = new URL(request.url);
    const limit = Math.min(
      parseInt(searchParams.get("limit") || "50", 10),
      100,
    );
    const startingAfter = searchParams.get("starting_after") || undefined;

    const stripeCustomerId = await resolveStripeCustomerId(
      user.id,
      user.stripeCustomerId,
    );

    if (!stripeCustomerId) {
      return NextResponse.json({
        invoices: [],
        hasMore: false,
      });
    }

    const invoices = await stripe.invoices.list({
      customer: stripeCustomerId,
      limit,
      starting_after: startingAfter,
      expand: ["data.subscription", "data.charge"],
    });

    const transformedInvoices = invoices.data.map((invoice) => ({
      id: invoice.id,
      number: invoice.number,
      status: invoice.status,
      amount: invoice.amount_paid || invoice.amount_due,
      currency: invoice.currency,
      description: invoice.description || getInvoiceDescription(invoice),
      createdAt: new Date(invoice.created * 1000).toISOString(),
      dueDate: invoice.due_date
        ? new Date(invoice.due_date * 1000).toISOString()
        : null,
      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,
      periodStart: invoice.period_start
        ? new Date(invoice.period_start * 1000).toISOString()
        : null,
      periodEnd: invoice.period_end
        ? new Date(invoice.period_end * 1000).toISOString()
        : null,
      billingReason: invoice.billing_reason,
      subtotal: invoice.subtotal,
      tax:
        (
          invoice as unknown as {
            total_tax_amounts?: Array<{ amount: number }>;
          }
        ).total_tax_amounts?.reduce(
          (sum: number, item: { amount: number }) => sum + item.amount,
          0,
        ) || 0,
      total: invoice.total,
      amountPaid: invoice.amount_paid,
      amountRemaining: invoice.amount_remaining,
      attemptCount: invoice.attempt_count,
      attempted: invoice.attempted,
      lineItems:
        invoice.lines?.data?.map((line) => ({
          id: line.id,
          description: line.description,
          amount: line.amount,
          quantity: line.quantity,
          period: line.period
            ? {
                start: new Date(line.period.start * 1000).toISOString(),
                end: new Date(line.period.end * 1000).toISOString(),
              }
            : null,
        })) || [],
    }));

    logger.info("Invoices fetched", {
      userId: user.id,
      count: transformedInvoices.length,
    });

    return NextResponse.json({
      invoices: transformedInvoices,
      hasMore: invoices.has_more,
    });
  } catch (error) {
    logger.error("Failed to fetch invoices", {
      error: error instanceof Error ? error.message : "Unknown error",
    });

    return NextResponse.json(
      { error: "Failed to fetch invoices" },
      { status: 500 },
    );
  }
}
