export interface BillingSubscription {
  id: string;
  restaurantId: string;
  planId: string | null;
  status: string;
  currentPeriodEnd: string | null;
  trialStart: string | null;
  trialEnd: string | null;
  createdAt: string;
  planName: string | null;
  priceMonthly: number;
  priceAnnual: number;
  features: string[];
  limits: Record<string, number>;
  stripeCustomerId: string | null;
  stripeSubscriptionId: string | null;
  trialDays: number;
  billingContactEmail: string | null;
}

export interface BillingUsage {
  conversations: number;
  branches: number;
  apiCalls: number;
  voiceMinutes: number;
}

export interface Plan {
  id: string;
  name: string;
  slug: string | null;
  description: string | null;
  priceMonthly: number;
  priceAnnual: number;
  effectivePriceMonthly: number;
  effectivePriceAnnual: number;
  features: string[];
  limits: Record<string, number>;
  isActive: boolean;
  stripePriceIdMonthly: string | null;
  stripePriceIdAnnual: string | null;
  trialDays: number;
}

export interface GatewayInfo {
  id: 'stripe' | 'razorpay';
  active: boolean;
  currency: string;
  promoCodesEnabled?: boolean;
  gracePeriodDays?: number;
}

export interface UnifiedInvoice {
  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 interface StripeInvoice extends UnifiedInvoice {
  gateway: 'stripe';
}

export interface PaymentMethod {
  id: string;
  brand: string;
  last4: string;
  expMonth: number;
  expYear: number;
}

function normalizeSubscription(row: Record<string, unknown>): BillingSubscription {
  return {
    id: row.id as string,
    restaurantId: (row.restaurant_id ?? row.restaurantId) as string,
    planId: (row.plan_id ?? row.planId ?? null) as string | null,
    status: row.status as string,
    currentPeriodEnd: (row.current_period_end ?? row.currentPeriodEnd ?? null) as string | null,
    trialStart: (row.trial_start ?? row.trialStart ?? null) as string | null,
    trialEnd: (row.trial_end ?? row.trialEnd ?? null) as string | null,
    createdAt: (row.created_at ?? row.createdAt) as string,
    planName: (row.plan_name ?? row.planName ?? null) as string | null,
    priceMonthly: Number(row.price_monthly ?? row.priceMonthly ?? 0),
    priceAnnual: Number(row.price_annual ?? row.priceAnnual ?? 0),
    features: (row.features ?? []) as string[],
    limits: (row.limits ?? {}) as Record<string, number>,
    stripeCustomerId: (row.stripe_customer_id ?? row.stripeCustomerId ?? null) as string | null,
    stripeSubscriptionId: (row.stripe_subscription_id ?? row.stripeSubscriptionId ?? null) as string | null,
    trialDays: Number(row.trial_days ?? row.trialDays ?? 14),
    billingContactEmail: (row.billing_contact_email ?? row.billingContactEmail ?? null) as string | null,
  };
}

function normalizePlan(row: Record<string, unknown>): Plan {
  const priceMonthly = Number(row.price_monthly ?? row.priceMonthly ?? 0);
  const priceAnnual = Number(row.price_annual ?? row.priceAnnual ?? 0);
  return {
    id: row.id as string,
    name: row.name as string,
    slug: (row.slug ?? null) as string | null,
    description: (row.description ?? null) as string | null,
    priceMonthly,
    priceAnnual,
    effectivePriceMonthly: Number(row.effective_price_monthly ?? row.custom_price_monthly ?? priceMonthly),
    effectivePriceAnnual: Number(row.effective_price_annual ?? row.custom_price_annual ?? priceAnnual),
    features: (row.features ?? []) as string[],
    limits: (row.limits ?? {}) as Record<string, number>,
    isActive: (row.is_active ?? row.isActive ?? true) as boolean,
    stripePriceIdMonthly: (row.stripe_price_id_monthly ?? row.stripePriceIdMonthly ?? null) as string | null,
    stripePriceIdAnnual: (row.stripe_price_id_annual ?? row.stripePriceIdAnnual ?? null) as string | null,
    trialDays: Number(row.trial_days ?? row.trialDays ?? 0),
  };
}

export async function getSubscription(): Promise<BillingSubscription | null> {
  const res = await fetch('/api/billing');
  if (!res.ok) throw new Error('Failed to fetch subscription');
  const data = await res.json();
  return data.subscription ? normalizeSubscription(data.subscription) : null;
}

export async function getUsage(): Promise<BillingUsage> {
  const res = await fetch('/api/billing/usage');
  if (!res.ok) throw new Error('Failed to fetch usage');
  const data = await res.json();
  return data.usage;
}

export async function listPlans(currency?: string): Promise<Plan[]> {
  const url = currency ? `/api/billing/plans?currency=${encodeURIComponent(currency)}` : '/api/billing/plans';
  const res = await fetch(url);
  if (!res.ok) throw new Error('Failed to fetch plans');
  const data = await res.json();
  return (data.plans ?? []).map((p: Record<string, unknown>) => normalizePlan(p));
}

export async function getActiveGateways(): Promise<GatewayInfo[]> {
  const res = await fetch('/api/billing/gateways');
  if (!res.ok) return [];
  const data = await res.json();
  return data.gateways ?? [];
}

export async function getAvailableCurrencies(): Promise<string[]> {
  const res = await fetch('/api/billing/currencies');
  if (!res.ok) return [];
  const data = await res.json();
  return data.currencies ?? [];
}

export async function getApiUsageChart(): Promise<{ day: string; calls: number }[]> {
  const res = await fetch('/api/billing/api-usage-chart');
  if (!res.ok) throw new Error('Failed to fetch API usage chart');
  const data = await res.json();
  return data.chart ?? [];
}

export async function fetchProrationPreview(planId: string, billingCycle: 'monthly' | 'annual'): Promise<{
  prorationAmount: number | null;
  currency: string;
  lines: { description: string; amount: number; currency: string }[];
  noSubscription: boolean;
  staticPreview?: boolean;
}> {
  const res = await fetch('/api/billing/proration-preview', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ planId, billingCycle }),
  });
  const data = await res.json();
  if (!res.ok) return { prorationAmount: null, currency: 'USD', lines: [], noSubscription: false };
  return data;
}

export async function startCheckout(planId: string, billingCycle: 'monthly' | 'annual', promoCode?: string): Promise<string> {
  const res = await fetch('/api/billing/checkout', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ planId, billingCycle, ...(promoCode ? { promoCode } : {}) }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data.error ?? 'Failed to start checkout');
  return (data.url ?? data.redirect) as string;
}

export async function startRazorpayCheckout(planId: string, billingCycle: 'monthly' | 'annual'): Promise<{
  subscriptionId: string; keyId: string; currency: string; planName: string;
}> {
  const res = await fetch('/api/billing/razorpay-checkout', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ planId, billingCycle }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data.error ?? 'Failed to start Razorpay checkout');
  return data;
}

export async function verifyRazorpayPayment(params: {
  razorpaySubscriptionId: string;
  razorpayPaymentId: string;
  razorpaySignature: string;
}): Promise<void> {
  const res = await fetch('/api/billing/razorpay-verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(params),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data.error ?? 'Payment verification failed');
}

export async function validatePromoCode(params: {
  promoCode: string;
  planId: string;
  billingCycle: string;
}): Promise<{
  valid: boolean;
  promotionCodeId?: string;
  originalAmount?: number;
  discountedAmount?: number;
  currency?: string;
  discountDescription?: string;
  error?: string;
}> {
  const res = await fetch('/api/billing/promo-validate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(params),
  });
  return res.json();
}

export async function openCustomerPortal(): Promise<string> {
  const res = await fetch('/api/billing/portal', { method: 'POST' });
  const data = await res.json();
  if (!res.ok) throw new Error(data.error ?? 'Failed to open portal');
  return data.url as string;
}

export async function listInvoices(): Promise<UnifiedInvoice[]> {
  const res = await fetch('/api/billing/invoices');
  if (!res.ok) throw new Error('Failed to fetch invoices');
  const data = await res.json();
  return data.invoices ?? [];
}

export async function getBillingContact(): Promise<string | null> {
  const res = await fetch('/api/billing/billing-contact');
  if (!res.ok) return null;
  const data = await res.json();
  return data.billingContactEmail ?? null;
}

export async function saveBillingContact(email: string | null): Promise<void> {
  const res = await fetch('/api/billing/billing-contact', {
    method: 'PATCH',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ billingContactEmail: email }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data.error ?? 'Failed to save billing contact');
}

export async function getPaymentMethod(): Promise<PaymentMethod | null> {
  const res = await fetch('/api/billing/payment-method');
  if (!res.ok) throw new Error('Failed to fetch payment method');
  const data = await res.json();
  return data.paymentMethod ?? null;
}

export async function createSetupIntent(): Promise<string> {
  const res = await fetch('/api/billing/setup-intent', { method: 'POST' });
  const data = await res.json();
  if (!res.ok) throw new Error(data.error ?? 'Failed to create setup intent');
  return data.clientSecret as string;
}

export async function updatePaymentMethod(paymentMethodId: string): Promise<void> {
  const res = await fetch('/api/billing/setup-intent', {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ paymentMethodId }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data.error ?? 'Failed to update payment method');
}
