import { NextRequest, NextResponse } from 'next/server';
import { getSession } from '@/lib/auth';
import { stripe } from '@/lib/stripe';
import { getOrCreateStripeCustomer } from '@/lib/billing-service';
import type Stripe from 'stripe';

function normalizePaymentMethod(pm: Stripe.PaymentMethod, defaultPmId: string | null) {
  const base = { id: pm.id, type: pm.type, isDefault: pm.id === defaultPmId };
  if (pm.type === 'card' || pm.type === 'link') {
    return { ...base, brand: pm.card?.brand, last4: pm.card?.last4, expMonth: pm.card?.exp_month, expYear: pm.card?.exp_year };
  }
  if (pm.type === 'sepa_debit') {
    return { ...base, last4: pm.sepa_debit?.last4, bankCode: pm.sepa_debit?.bank_code, country: pm.sepa_debit?.country };
  }
  if (pm.type === 'paypal') {
    return { ...base, email: (pm as Stripe.PaymentMethod & { paypal?: { payer_email?: string } }).paypal?.payer_email };
  }
  return base;
}

/**
 * GET /api/billing/payment-method
 * Returns the list of saved payment methods (all types) and the default.
 */
export async function GET(request: NextRequest) {
  const accessToken = request.cookies.get('scriba.access_token')?.value;
  const session = await getSession(accessToken);
  if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });

  try {
    const customerId = await getOrCreateStripeCustomer(
      session.user.id,
      session.user.email,
      session.user.name,
    );

    const [cards, sepaDebits, paypals, links, customer] = await Promise.all([
      stripe.paymentMethods.list({ customer: customerId, type: 'card' }).catch(() => ({ data: [] })),
      stripe.paymentMethods.list({ customer: customerId, type: 'sepa_debit' }).catch(() => ({ data: [] })),
      stripe.paymentMethods.list({ customer: customerId, type: 'paypal' }).catch(() => ({ data: [] })),
      stripe.paymentMethods.list({ customer: customerId, type: 'link' }).catch(() => ({ data: [] })),
      stripe.customers.retrieve(customerId),
    ]);

    const activeCustomer = customer as Stripe.Customer;
    const defaultPmId = !activeCustomer.deleted
      ? (typeof activeCustomer.invoice_settings?.default_payment_method === 'string'
          ? activeCustomer.invoice_settings.default_payment_method
          : (activeCustomer.invoice_settings?.default_payment_method as Stripe.PaymentMethod | null)?.id ?? null)
      : null;

    const allPms = [...cards.data, ...sepaDebits.data, ...paypals.data, ...links.data];
    const methods = allPms.map((pm) => normalizePaymentMethod(pm, defaultPmId));

    return NextResponse.json({ methods });
  } catch (err) {
    console.error('List payment methods error:', err);
    return NextResponse.json({ error: 'Failed to list payment methods' }, { status: 500 });
  }
}

/**
 * POST /api/billing/payment-method
 * Sets up a confirmed payment method as the default after a SetupIntent succeeds.
 * Body: { paymentMethodId }
 */
export async function POST(request: NextRequest) {
  const accessToken = request.cookies.get('scriba.access_token')?.value;
  const session = await getSession(accessToken);
  if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });

  const { paymentMethodId } = await request.json();
  if (!paymentMethodId) return NextResponse.json({ error: 'paymentMethodId required' }, { status: 400 });

  try {
    const customerId = await getOrCreateStripeCustomer(
      session.user.id,
      session.user.email,
      session.user.name,
    );

    await stripe.paymentMethods.attach(paymentMethodId, { customer: customerId });
    await stripe.customers.update(customerId, {
      invoice_settings: { default_payment_method: paymentMethodId },
    });

    return NextResponse.json({ success: true });
  } catch (err) {
    console.error('Attach payment method error:', err);
    return NextResponse.json({ error: 'Failed to save payment method' }, { status: 500 });
  }
}

/**
 * DELETE /api/billing/payment-method
 * Detaches a payment method.
 * Body: { paymentMethodId }
 */
export async function DELETE(request: NextRequest) {
  const accessToken = request.cookies.get('scriba.access_token')?.value;
  const session = await getSession(accessToken);
  if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });

  const { paymentMethodId } = await request.json();
  if (!paymentMethodId) return NextResponse.json({ error: 'paymentMethodId required' }, { status: 400 });

  try {
    const customerId = await getOrCreateStripeCustomer(
      session.user.id,
      session.user.email,
      session.user.name,
    );
    const [cards, sepaDebits, paypals, links] = await Promise.all([
      stripe.paymentMethods.list({ customer: customerId, type: 'card' }).catch(() => ({ data: [] })),
      stripe.paymentMethods.list({ customer: customerId, type: 'sepa_debit' }).catch(() => ({ data: [] })),
      stripe.paymentMethods.list({ customer: customerId, type: 'paypal' }).catch(() => ({ data: [] })),
      stripe.paymentMethods.list({ customer: customerId, type: 'link' }).catch(() => ({ data: [] })),
    ]);
    const allMethods = [...cards.data, ...sepaDebits.data, ...paypals.data, ...links.data];
    const ownsMethod = allMethods.some((pm) => pm.id === paymentMethodId);
    if (!ownsMethod) {
      return NextResponse.json({ error: 'Payment method not found for customer' }, { status: 404 });
    }
    if (allMethods.length <= 1) {
      return NextResponse.json(
        { error: 'You must add a second payment method before removing the current one.' },
        { status: 400 }
      );
    }

    await stripe.paymentMethods.detach(paymentMethodId);
    return NextResponse.json({ success: true });
  } catch (err) {
    console.error('Detach payment method error:', err);
    return NextResponse.json({ error: 'Failed to remove payment method' }, { status: 500 });
  }
}
