import { NextRequest, NextResponse } from 'next/server';
import { db, schema } from '@/lib/db';
import { eq } from 'drizzle-orm';
import { updatePaymentMethodSchema } from '@/lib/validators';
import { getSession } from '@/lib/auth';
import { isCompanyOwner, updateCompanyPaymentMethod, getCompanyById } from '@/lib/companies';
import { stripe } from '@/lib/stripe';
import { getOrCreateStripeCustomer } from '@/lib/billing-service';
import type Stripe from 'stripe';

type CompanyPaymentMethodValue = NonNullable<(typeof schema.companies.$inferInsert)['paymentMethod']>;

function isCompanyPaymentMethodType(
  type: string
): type is CompanyPaymentMethodValue['type'] {
  return [
    'card',
    'sepa_debit',
    'sepa',
    'paypal',
    'link',
    'apple_pay',
    'google_pay',
  ].includes(type as CompanyPaymentMethodValue['type']);
}

function normalizeStripePaymentMethodForCompany(pm: Stripe.PaymentMethod): CompanyPaymentMethodValue {
  if (!isCompanyPaymentMethodType(pm.type)) {
    throw new Error(`Unsupported Stripe payment method type for company: ${pm.type}`);
  }

  const base: CompanyPaymentMethodValue = {
    type: pm.type,
    stripePaymentMethodId: pm.id,
  };

  if (pm.type === 'card' || pm.type === 'link') {
    return {
      ...base,
      brand: pm.card?.brand,
      last4: pm.card?.last4,
      expiryMonth: pm.card?.exp_month,
      expiryYear: pm.card?.exp_year,
    };
  }

  if (pm.type === 'sepa_debit') {
    return {
      ...base,
      last4: pm.sepa_debit?.last4 ?? undefined,
      bankCode: pm.sepa_debit?.bank_code ?? undefined,
      country: pm.sepa_debit?.country ?? undefined,
    };
  }

  if (pm.type === 'paypal') {
    return {
      ...base,
      email: (pm as Stripe.PaymentMethod & { paypal?: { payer_email?: string | null } }).paypal?.payer_email ?? undefined,
    };
  }

  return base;
}

/**
 * GET /api/companies/[id]/payment-method
 * Get company payment method
 * - Owner only: can view payment method
 */
export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const { id } = await params;

    // Verify authentication
    const accessToken = request.cookies.get('scriba.access_token')?.value;
    const sessionData = await getSession(accessToken);

    if (!sessionData) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionData;

    // Verify user belongs to this company
    if (user.companyId !== id) {
      return NextResponse.json(
        { error: 'Access denied. You are not a member of this company.' },
        { status: 403 }
      );
    }

    // Verify ownership - only owner can view payment method
    const isOwner = await isCompanyOwner(user.id, id);
    if (!isOwner) {
      return NextResponse.json(
        { error: 'Only the company owner can view payment method' },
        { status: 403 }
      );
    }

    // Get company
    const company = await getCompanyById(id);
    if (!company) {
      return NextResponse.json({ error: 'Company not found' }, { status: 404 });
    }

    // If company payment method is already saved, return it.
    if (company.paymentMethod) {
      return NextResponse.json({
        paymentMethod: company.paymentMethod,
      });
    }

    // Fallback: auto-sync from owner's Stripe customer so company view stays in sync
    // with owner-level setup (PaymentGate / Settings).
    try {
      const customerId = await getOrCreateStripeCustomer(
        user.id,
        user.email,
        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 allMethods = [...cards.data, ...sepaDebits.data, ...paypals.data, ...links.data];
      if (allMethods.length === 0) {
        return NextResponse.json({ paymentMethod: null });
      }

      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 selected = (defaultPmId
        ? allMethods.find((pm) => pm.id === defaultPmId)
        : undefined) ?? allMethods[0];

      const normalized = normalizeStripePaymentMethodForCompany(selected);
      await updateCompanyPaymentMethod(id, normalized);

      return NextResponse.json({
        paymentMethod: normalized,
      });
    } catch {
      return NextResponse.json({
        paymentMethod: null,
      });
    }

  } catch (error) {
    console.error('Get payment method error:', error);
    return NextResponse.json(
      { error: 'Failed to retrieve payment method' },
      { status: 500 }
    );
  }
}

/**
 * PATCH /api/companies/[id]/payment-method
 * Update company payment method
 * - Owner only: can edit payment method
 */
export async function PATCH(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const { id } = await params;

    // Verify authentication
    const accessToken = request.cookies.get('scriba.access_token')?.value;
    const sessionData = await getSession(accessToken);

    if (!sessionData) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionData;

    // Verify ownership
    const isOwner = await isCompanyOwner(user.id, id);
    if (!isOwner) {
      return NextResponse.json(
        { error: 'Only the company owner can edit payment method' },
        { status: 403 }
      );
    }

    // Parse and validate request body
    const body = await request.json();
    const parsed = updatePaymentMethodSchema.safeParse(body);

    if (!parsed.success) {
      return NextResponse.json(
        { error: parsed.error.issues[0]?.message ?? 'Invalid input' },
        { status: 400 }
      );
    }

    // Update payment method
    const updated = await updateCompanyPaymentMethod(id, parsed.data);

    if (!updated) {
      return NextResponse.json(
        { error: 'Company not found' },
        { status: 404 }
      );
    }

    return NextResponse.json({
      success: true,
      paymentMethod: updated.paymentMethod,
      message: 'Payment method updated successfully',
    });

  } catch (error) {
    console.error('Update payment method error:', error);
    return NextResponse.json(
      { error: 'Failed to update payment method' },
      { status: 500 }
    );
  }
}

/**
 * DELETE /api/companies/[id]/payment-method
 * Remove company payment method
 * - Owner only: can remove payment method
 */
export async function DELETE(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const { id } = await params;

    // Verify authentication
    const accessToken = request.cookies.get('scriba.access_token')?.value;
    const sessionData = await getSession(accessToken);

    if (!sessionData) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionData;

    // Verify ownership
    const isOwner = await isCompanyOwner(user.id, id);
    if (!isOwner) {
      return NextResponse.json(
        { error: 'Only the company owner can remove payment method' },
        { status: 403 }
      );
    }

    const customerId = await getOrCreateStripeCustomer(
      user.id,
      user.email,
      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];
    if (allMethods.length <= 1) {
      return NextResponse.json(
        { error: 'Add a second payment method before removing the current one.' },
        { status: 400 }
      );
    }

    // Remove payment method
    const [updated] = await db
      .update(schema.companies)
      .set({
        paymentMethod: null,
        updatedAt: new Date(),
      })
      .where(eq(schema.companies.id, id))
      .returning();

    if (!updated) {
      return NextResponse.json(
        { error: 'Company not found' },
        { status: 404 }
      );
    }

    return NextResponse.json({
      success: true,
      message: 'Payment method removed successfully',
    });

  } catch (error) {
    console.error('Remove payment method error:', error);
    return NextResponse.json(
      { error: 'Failed to remove payment method' },
      { status: 500 }
    );
  }
}
