/**
 * Billing History API
 *
 * GET /api/billing/history
 *
 * Fetches billing history for the authenticated user.
 * Convex-first with Stripe invoice enrichment.
 */

import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/lib/auth";
import { stripe } from "@/lib/stripe";
import { logger } from "@/lib/logger";
import { getAuthenticatedEmail } from "@/lib/utils/auth-helpers.util";
import { convexQuery } from "@/lib/convex-client";

const MAX_INVOICE_ENRICHMENT = 20;

export async function GET(request: NextRequest) {
  try {
    const userEmail = await getAuthenticatedEmail(request, auth);
    if (!userEmail) {
      logger.warn("Unauthorized billing history request - no valid auth");
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    // Look up user via Convex
    const convexUser = await convexQuery<Record<string, unknown>>(
      "auth/queries:getUserByEmail",
      { email: userEmail.toLowerCase() },
    );
    const user = convexUser
      ? {
          id: (convexUser.prismaId as string) || (convexUser._id as string),
          stripeCustomerId: (convexUser.stripeCustomerId as string) || null,
        }
      : null;

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

    const limit = Math.min(
      parseInt(request.nextUrl.searchParams.get("limit") || "50", 10),
      100,
    );
    const includeInvoices =
      request.nextUrl.searchParams.get("includeInvoices") !== "false";

    // Convex-first: try fetching billing history
    const customerIds = [user.stripeCustomerId, `user_${user.id}`].filter(
      Boolean,
    ) as string[];

    const historyBuckets = await Promise.all(
      customerIds.map(async (customerId) => {
        const result = await convexQuery<Array<Record<string, unknown>>>(
          "billing/queries:getBillingHistory",
          { customerId, limit },
        );
        return result ?? [];
      }),
    );

    const mergedHistory = historyBuckets
      .flat()
      .filter(
        (event, index, all) =>
          index ===
          all.findIndex(
            (c) =>
              String(c.prismaId ?? c._id) ===
              String(event.prismaId ?? event._id),
          ),
      )
      .sort((a, b) => Number(b.createdAt ?? 0) - Number(a.createdAt ?? 0))
      .slice(0, limit);

    // Enrich with Stripe invoice data
    const invoiceIdsToEnrich = includeInvoices
      ? (mergedHistory
          .map((event) =>
            typeof event.invoiceId === "string" ? event.invoiceId : null,
          )
          .filter(Boolean)
          .slice(0, MAX_INVOICE_ENRICHMENT) as string[])
      : [];

    const invoiceMap = new Map<
      string,
      {
        hosted_invoice_url: string | null;
        invoice_pdf: string | null;
        status: string | null;
        number: string | null;
      }
    >();

    await Promise.all(
      invoiceIdsToEnrich.map(async (invoiceId) => {
        try {
          const invoice = await stripe.invoices.retrieve(invoiceId);
          invoiceMap.set(invoiceId, {
            hosted_invoice_url: invoice.hosted_invoice_url ?? null,
            invoice_pdf: invoice.invoice_pdf ?? null,
            status: invoice.status,
            number: invoice.number,
          });
        } catch {
          // Stripe lookup failed — skip enrichment for this invoice
        }
      }),
    );

    const history = mergedHistory.map((event) => {
      const invoice = event.invoiceId
        ? invoiceMap.get(String(event.invoiceId))
        : null;
      return {
        id: event.prismaId ?? event._id,
        event: event.event,
        amount: event.amount,
        currency: event.currency,
        createdAt: event.createdAt
          ? new Date(event.createdAt as number).toISOString()
          : null,
        metadata: event.metadata ?? null,
        invoiceId: event.invoiceId ?? null,
        paymentIntentId: event.paymentIntentId ?? null,
        invoiceUrl: invoice?.hosted_invoice_url ?? null,
        invoicePdf: invoice?.invoice_pdf ?? null,
        invoiceStatus: invoice?.status ?? null,
        invoiceNumber: invoice?.number ?? null,
      };
    });

    return NextResponse.json({ history, success: true });
  } catch (error) {
    logger.error("Billing history route error", {
      error: error instanceof Error ? error.message : "Unknown error",
      stack: error instanceof Error ? error.stack : undefined,
    });
    return NextResponse.json(
      { error: "Failed to retrieve billing history" },
      { status: 500 },
    );
  }
}
