/**
 * PayPal Billing Plan Management Service
 *
 * Automatically creates, updates, and deactivates PayPal billing plans
 * when subscription tiers are managed in the admin panel.
 */

import { getPayPalConfig } from '../config';
import { logger } from '../utils/logger';

// PayPal API base URLs
const PAYPAL_API_BASE = {
  sandbox: 'https://api-m.sandbox.paypal.com',
  live: 'https://api-m.paypal.com',
};

/**
 * Get OAuth2 access token from PayPal
 */
async function getAccessToken(): Promise<string> {
  const config = getPayPalConfig();
  const baseUrl = PAYPAL_API_BASE[config.mode as 'sandbox' | 'live'] || PAYPAL_API_BASE.sandbox;

  const response = await fetch(`${baseUrl}/v1/oauth2/token`, {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': `Basic ${Buffer.from(`${config.clientId}:${config.clientSecret}`).toString('base64')}`,
    },
    body: 'grant_type=client_credentials',
  });

  if (!response.ok) {
    throw new Error(`PayPal OAuth failed: ${response.status} ${response.statusText}`);
  }

  const data = await response.json() as { access_token: string };
  return data.access_token;
}

/**
 * Get the PayPal API base URL based on mode
 */
function getBaseUrl(): string {
  const config = getPayPalConfig();
  return PAYPAL_API_BASE[config.mode as 'sandbox' | 'live'] || PAYPAL_API_BASE.sandbox;
}

/**
 * Create a PayPal billing plan for a tier
 *
 * @param tierName - Display name (e.g., "Starter")
 * @param price - Price in USD (e.g., 29.00)
 * @param interval - MONTH or YEAR
 * @param productId - PayPal product ID
 * @returns PayPal plan ID (e.g., "P-xxx")
 */
export async function createPayPalPlan(
  tierName: string,
  price: number,
  interval: 'MONTH' | 'YEAR',
  productId: string
): Promise<string> {
  const token = await getAccessToken();
  const baseUrl = getBaseUrl();
  const cycleName = interval === 'MONTH' ? 'Monthly' : 'Annual';

  const response = await fetch(`${baseUrl}/v1/billing/plans`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`,
    },
    body: JSON.stringify({
      product_id: productId,
      name: `${tierName} ${cycleName}`,
      billing_cycles: [{
        frequency: { interval_unit: interval, interval_count: 1 },
        tenure_type: 'REGULAR',
        sequence: 1,
        total_cycles: 0,
        pricing_scheme: {
          fixed_price: { value: price.toFixed(2), currency_code: 'USD' },
        },
      }],
      payment_preferences: {
        auto_bill_outstanding: true,
        payment_failure_threshold: 3,
      },
    }),
  });

  if (!response.ok) {
    const error = await response.text();
    throw new Error(`Failed to create PayPal plan: ${response.status} ${error}`);
  }

  const data = await response.json() as { id: string };
  logger.info('PayPal plan created', { planId: data.id, tierName, interval, price });
  return data.id;
}

/**
 * Update pricing on an existing PayPal billing plan
 *
 * NOTE: PayPal only allows updating pricing, not the billing interval.
 *
 * @param planId - PayPal plan ID
 * @param newPrice - New price in USD
 */
export async function updatePayPalPlanPricing(
  planId: string,
  newPrice: number
): Promise<void> {
  const token = await getAccessToken();
  const baseUrl = getBaseUrl();

  const response = await fetch(`${baseUrl}/v1/billing/plans/${planId}/update-pricing-schemes`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`,
    },
    body: JSON.stringify({
      pricing_schemes: [{
        billing_cycle_sequence: 1,
        pricing_scheme: {
          fixed_price: { value: newPrice.toFixed(2), currency_code: 'USD' },
        },
      }],
    }),
  });

  if (!response.ok) {
    const error = await response.text();
    throw new Error(`Failed to update PayPal plan pricing: ${response.status} ${error}`);
  }

  logger.info('PayPal plan pricing updated', { planId, newPrice });
}

/**
 * Deactivate a PayPal billing plan
 * Deactivated plans cannot accept new subscriptions but existing ones continue.
 *
 * @param planId - PayPal plan ID
 */
export async function deactivatePayPalPlan(planId: string): Promise<void> {
  const token = await getAccessToken();
  const baseUrl = getBaseUrl();

  const response = await fetch(`${baseUrl}/v1/billing/plans/${planId}/deactivate`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`,
    },
  });

  if (!response.ok) {
    const error = await response.text();
    throw new Error(`Failed to deactivate PayPal plan: ${response.status} ${error}`);
  }

  logger.info('PayPal plan deactivated', { planId });
}

/**
 * Activate a PayPal billing plan (reactivate after deactivation)
 *
 * @param planId - PayPal plan ID
 */
export async function activatePayPalPlan(planId: string): Promise<void> {
  const token = await getAccessToken();
  const baseUrl = getBaseUrl();

  const response = await fetch(`${baseUrl}/v1/billing/plans/${planId}/activate`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`,
    },
  });

  if (!response.ok) {
    const error = await response.text();
    throw new Error(`Failed to activate PayPal plan: ${response.status} ${error}`);
  }

  logger.info('PayPal plan activated', { planId });
}

/**
 * Sync a tier's PayPal plans: create both monthly and annual plans.
 * Returns the plan IDs to be stored in the database.
 *
 * @param tierName - Display name
 * @param monthlyPrice - Monthly price in USD
 * @param annualPrice - Annual price in USD
 * @param productId - PayPal product ID
 * @returns Object with monthly and annual plan IDs
 */
export async function createPlansForTier(
  tierName: string,
  monthlyPrice: number,
  annualPrice: number,
  productId: string
): Promise<{ monthlyPlanId: string; annualPlanId: string }> {
  const [monthlyPlanId, annualPlanId] = await Promise.all([
    createPayPalPlan(tierName, monthlyPrice, 'MONTH', productId),
    createPayPalPlan(tierName, annualPrice, 'YEAR', productId),
  ]);

  return { monthlyPlanId, annualPlanId };
}

/**
 * Update pricing for both monthly and annual plans of a tier.
 * Only updates plans where the price has actually changed.
 * Creates new plans if plan IDs don't exist yet.
 *
 * @param currentTier - Current tier data from database
 * @param newMonthlyPrice - New monthly price
 * @param newAnnualPrice - New annual price
 * @param productId - PayPal product ID (needed if creating new plans)
 * @returns Updated plan IDs (only if new plans were created)
 */
export async function syncTierPricing(
  currentTier: {
    name: string;
    monthly_price: number | { toString(): string };
    annual_price: number | { toString(): string };
    paypal_plan_monthly: string | null;
    paypal_plan_annual: string | null;
  },
  newMonthlyPrice: number | undefined,
  newAnnualPrice: number | undefined,
  productId: string
): Promise<{ paypal_plan_monthly?: string; paypal_plan_annual?: string }> {
  const updates: { paypal_plan_monthly?: string; paypal_plan_annual?: string } = {};
  const currentMonthly = Number(currentTier.monthly_price);
  const currentAnnual = Number(currentTier.annual_price);

  // Handle monthly plan
  if (newMonthlyPrice !== undefined && newMonthlyPrice !== currentMonthly) {
    if (currentTier.paypal_plan_monthly) {
      await updatePayPalPlanPricing(currentTier.paypal_plan_monthly, newMonthlyPrice);
    } else {
      updates.paypal_plan_monthly = await createPayPalPlan(
        currentTier.name, newMonthlyPrice, 'MONTH', productId
      );
    }
  } else if (!currentTier.paypal_plan_monthly && newMonthlyPrice !== undefined) {
    updates.paypal_plan_monthly = await createPayPalPlan(
      currentTier.name, newMonthlyPrice, 'MONTH', productId
    );
  }

  // Handle annual plan
  if (newAnnualPrice !== undefined && newAnnualPrice !== currentAnnual) {
    if (currentTier.paypal_plan_annual) {
      await updatePayPalPlanPricing(currentTier.paypal_plan_annual, newAnnualPrice);
    } else {
      updates.paypal_plan_annual = await createPayPalPlan(
        currentTier.name, newAnnualPrice, 'YEAR', productId
      );
    }
  } else if (!currentTier.paypal_plan_annual && newAnnualPrice !== undefined) {
    updates.paypal_plan_annual = await createPayPalPlan(
      currentTier.name, newAnnualPrice, 'YEAR', productId
    );
  }

  return updates;
}

/**
 * Deactivate both plans for a tier
 */
export async function deactivatePlansForTier(
  monthlyPlanId: string | null,
  annualPlanId: string | null
): Promise<void> {
  const promises: Promise<void>[] = [];
  if (monthlyPlanId) promises.push(deactivatePayPalPlan(monthlyPlanId));
  if (annualPlanId) promises.push(deactivatePayPalPlan(annualPlanId));
  await Promise.all(promises);
}
