import { NextResponse } from 'next/server';
import { withErrorHandler } from '@server/middleware/withErrorHandler';
import { withAuth, AuthedRequest } from '@server/middleware/withAuth';
import { getStripeClientFromDb, getStripeSecretKey } from '@server/lib/stripe';
import { db, subscriptions } from '@server/db/drizzle';
import { eq, desc } from 'drizzle-orm';
import { sql } from 'drizzle-orm';
import { initDatabase } from '@server/db/init';
import { getGatewayConfig } from '@server/services/gateway.service';
import { childLogger } from '@server/logger';

const log = childLogger('route.billing.invoices');

interface NormalizedInvoice {
  id: string;
  number: string | null;
  status: string | null;
  amount: number;
  currency: string;
  periodStart: string;
  periodEnd: string;
  createdAt: string;
  pdfUrl: string | null;
  hostedUrl: string | null;
  gateway: 'stripe' | 'razorpay';
}

export const GET = withErrorHandler(
  withAuth(async (req: AuthedRequest) => {
    await initDatabase();
    const restaurantId = req.session.restaurantId!;

    const rows = await db.select({
      stripeCustomerId: subscriptions.stripeCustomerId,
    })
      .from(subscriptions)
      .where(eq(subscriptions.restaurantId, restaurantId))
      .orderBy(desc(subscriptions.createdAt))
      .limit(1);
    const sub = rows[0];

    const cfg = await getGatewayConfig();
    const allInvoices: NormalizedInvoice[] = [];

    const [stripeResult, razorpayResult] = await Promise.allSettled([
      (async () => {
        if (!cfg.stripeActive || !sub?.stripeCustomerId) return [];
        const stripeKey = await getStripeSecretKey();
        if (!stripeKey) return [];
        const stripe = await getStripeClientFromDb();
        const invoices = await stripe.invoices.list({
          customer: sub.stripeCustomerId,
          limit: 24,
        });
        return invoices.data.map(inv => ({
          id: inv.id ?? `stripe-${Date.now()}`,
          number: inv.number ?? null,
          status: inv.status ?? null,
          amount: (inv.status === 'paid' ? inv.amount_paid : inv.amount_due) / 100,
          currency: inv.currency.toUpperCase(),
          periodStart: new Date(inv.period_start * 1000).toISOString(),
          periodEnd: new Date(inv.period_end * 1000).toISOString(),
          createdAt: new Date(inv.created * 1000).toISOString(),
          pdfUrl: inv.invoice_pdf ?? null,
          hostedUrl: inv.hosted_invoice_url ?? null,
          gateway: 'stripe' as const,
        }));
      })(),
      (async () => {
        if (!cfg.razorpayActive) return [];
        const { rows: payRows } = await db.execute(sql`
          SELECT rp.id, rp.razorpay_order_id, rp.razorpay_payment_id,
                 rp.amount, rp.currency, rp.status, rp.created_at,
                 p.name as plan_name
          FROM public.razorpay_payments rp
          LEFT JOIN public.plans p ON p.id = rp.plan_id
          WHERE rp.restaurant_id = ${restaurantId}
          ORDER BY rp.created_at DESC
          LIMIT 24
        `);
        return payRows.map((row) => {
          const r = row as {
            id: string; razorpay_order_id: string; razorpay_payment_id: string;
            amount: string; currency: string; status: string; created_at: string; plan_name: string | null;
          };
          const created = new Date(r.created_at).toISOString();
          return {
            id: r.razorpay_payment_id,
            number: r.razorpay_order_id,
            status: r.status,
            amount: parseFloat(r.amount),
            currency: r.currency.toUpperCase(),
            periodStart: created,
            periodEnd: created,
            createdAt: created,
            pdfUrl: null,
            hostedUrl: null,
            gateway: 'razorpay' as const,
          };
        });
      })(),
    ]);

    if (stripeResult.status === 'fulfilled') {
      allInvoices.push(...stripeResult.value);
    } else {
      log.warn({ err: stripeResult.reason }, 'Failed to fetch Stripe invoices');
    }

    if (razorpayResult.status === 'fulfilled') {
      allInvoices.push(...razorpayResult.value);
    } else {
      log.warn({ err: razorpayResult.reason }, 'Failed to fetch Razorpay payments');
    }

    allInvoices.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());

    return NextResponse.json({ invoices: allInvoices, cfg: { razorpayActive: cfg.razorpayActive } });
  })
);
