/**
 * Plan Change Types
 * TypeScript interfaces for subscription plan change feature
 * @module lib/types/plan-change.types
 */

export type TierId = 'tier1' | 'tier2' | 'tier3' | 'tier4' | 'tier5';
export type BillingPeriod = 'monthly' | 'yearly';

// Tier order for upgrade/downgrade determination
export const TIER_ORDER: Record<TierId, number> = {
  tier1: 1,
  tier2: 2,
  tier3: 3,
  tier4: 4,
  tier5: 5,
};

// ============================================
// REQUEST/RESPONSE INTERFACES
// ============================================

/**
 * Plan preview request parameters
 */
export interface PlanChangePreviewRequest {
  newTierId: TierId;
  billingPeriod?: BillingPeriod;
}

/**
 * Proration calculation breakdown
 */
export interface ProrationBreakdown {
  /** Days remaining in current billing period */
  daysRemaining: number;
  /** Total days in the billing period (30 for monthly, 365 for yearly) */
  totalDaysInPeriod: number;
  /** Daily rate for current plan (in smallest currency unit - fils/cents) */
  currentDailyRate: number;
  /** Daily rate for new plan (in smallest currency unit) */
  newDailyRate: number;
  /** Credit from unused current plan (positive number) */
  creditFromCurrent: number;
  /** Charge for new plan remainder (positive number) */
  chargeForNew: number;
  /** Net amount: chargeForNew - creditFromCurrent (positive = charge, negative = credit) */
  netAmount: number;
}

/**
 * Available plan information for display
 */
export interface AvailablePlanInfo {
  id: TierId;
  nameEn: string;
  nameAr: string;
  /** Price in GBP (base currency) */
  priceGBP: number;
  /** Calculated price in user's billing currency */
  priceInCurrency: number;
  /** Currency code (e.g., 'QAR') */
  currency: string;
  billingPeriod: BillingPeriod;
  featuresEn: string[];
  featuresAr: string[];
  /** Whether this is the user's current plan */
  isCurrent: boolean;
  /** Order position (1-5) for upgrade/downgrade determination */
  order: number;
  /** Whether this plan is the popular/recommended one */
  popular: boolean;
}

/**
 * Plan change preview response
 */
export interface PlanChangePreviewResponse {
  success: boolean;
  preview: {
    currentPlan: AvailablePlanInfo;
    newPlan: AvailablePlanInfo;
    proration: ProrationBreakdown;
    /** Whether this is an upgrade (true) or downgrade (false) */
    isUpgrade: boolean;
    /** Next billing date (ISO string) */
    nextBillingDate: string;
    /** Amount for next regular billing (in smallest currency unit) */
    nextBillingAmount: number;
    /** Currency code (e.g., 'QAR') */
    currency: string;
    /** Human-readable summary */
    summary: {
      en: string;
      ar: string;
    };
  };
}

/**
 * Plan change execution request
 */
export interface PlanChangeExecuteRequest {
  newTierId: TierId;
  billingPeriod?: BillingPeriod;
  /** Client-confirmed net amount for validation (in smallest currency unit) */
  confirmedAmount?: number;
}

/**
 * Plan change execution response
 */
export interface PlanChangeExecuteResponse {
  success: boolean;
  subscription: {
    id: string;
    tierId: TierId;
    status: string;
    currentPeriodEnd: string;
  };
  invoice?: {
    id: string;
    amount: number;
    status: string;
  };
  isUpgrade: boolean;
  message: {
    en: string;
    ar: string;
  };
}

/**
 * All available plans response
 */
export interface AvailablePlansResponse {
  success: boolean;
  plans: AvailablePlanInfo[];
  currentPlan: {
    tierId: TierId;
    billingPeriod: BillingPeriod;
    currentPeriodEnd: string;
    daysRemaining: number;
  };
}

// ============================================
// ERROR TYPES
// ============================================

/**
 * Plan change error codes
 */
export type PlanChangeErrorCode =
  | 'SAME_PLAN'
  | 'NO_ACTIVE_SUBSCRIPTION'
  | 'INVALID_TIER'
  | 'STRIPE_ERROR'
  | 'IN_TRIAL'
  | 'PENDING_PAYMENT'
  | 'AMOUNT_MISMATCH'
  | 'UNAUTHORIZED';

/**
 * Plan change error response
 */
export interface PlanChangeError {
  error: string;
  code: PlanChangeErrorCode;
  details?: Record<string, unknown>;
}

// ============================================
// UTILITY FUNCTIONS
// ============================================

/**
 * Check if a tier ID is valid
 */
export function isValidTierId(tierId: string): tierId is TierId {
  return ['tier1', 'tier2', 'tier3', 'tier4', 'tier5'].includes(tierId);
}

/**
 * Check if a billing period is valid
 */
export function isValidBillingPeriod(period: string): period is BillingPeriod {
  return ['monthly', 'yearly'].includes(period);
}

/**
 * Determine if plan change is an upgrade
 */
export function isUpgrade(currentTierId: TierId, newTierId: TierId): boolean {
  return TIER_ORDER[newTierId] > TIER_ORDER[currentTierId];
}

/**
 * Calculate days remaining until a date using UTC
 * Uses UTC to ensure consistent calculation across timezones
 * @deprecated Use getDaysUntilBilling from @/lib/utils/pricing-helpers instead
 */
export function getDaysRemaining(endDate: Date): number {
  const now = new Date();
  const nowUTC = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());

  const end = new Date(endDate);
  const endUTC = Date.UTC(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate());

  const diffTime = endUTC - nowUTC;
  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
  return Math.max(0, diffDays);
}

/**
 * Calculate proration for plan change (fallback method)
 * @deprecated Prefer using Stripe's invoices.upcoming() API via previewPlanChange() for accurate proration
 * This manual calculation uses simplified 30/365 day periods which may differ from actual billing
 */
export function calculateProration(params: {
  currentPricePerPeriod: number;
  newPricePerPeriod: number;
  daysRemaining: number;
  billingPeriod: BillingPeriod;
}): ProrationBreakdown {
  const { currentPricePerPeriod, newPricePerPeriod, daysRemaining, billingPeriod } = params;

  const totalDaysInPeriod = billingPeriod === 'yearly' ? 365 : 30;

  const currentDailyRate = Math.round(currentPricePerPeriod / totalDaysInPeriod);
  const newDailyRate = Math.round(newPricePerPeriod / totalDaysInPeriod);

  const creditFromCurrent = currentDailyRate * daysRemaining;
  const chargeForNew = newDailyRate * daysRemaining;
  const netAmount = chargeForNew - creditFromCurrent;

  return {
    daysRemaining,
    totalDaysInPeriod,
    currentDailyRate,
    newDailyRate,
    creditFromCurrent,
    chargeForNew,
    netAmount,
  };
}
