import { PaymentMethodType } from '@/app/(root)/account/constants';
import {
  PlanKey,
  SubscriptionInfo,
  UsagePlanSchema,
} from '@/state/sessionStore';
import { SubscriptionPeriod } from '@/utils/session';

export enum SubscriptionAction {
  CurrentPlan = 'currentPlan',
  Subscribe = 'subscribe',
  ChangeCommitment = 'changeCommitment',
  ChangeCommitmentDelayedOnly = 'changeCommitmentDelayedOnly',
  Upgrade = 'upgrade',
  UpgradeDelayedOnly = 'upgradeDelayedOnly',
  Downgrade = 'downgrade',
  Cancel = 'cancel',
  Inactive = 'inactive',
  Unavailable = 'unavailable',
}

/**
 * Check if UPI payment method is attempting to upgrade to Premier Annual plan
 * UPI users cannot upgrade to Premier Annual plan
 */
function isUnavailableUpgrade({
  target,
  period,
  paymentMethodType,
}: {
  target: UsagePlanSchema;
  period: SubscriptionPeriod;
  paymentMethodType: PaymentMethodType | null;
}): boolean {
  // UPI mandate does not allow users to upgrade to Premier Annual plan
  return (
    paymentMethodType === PaymentMethodType.UPI &&
    target.plan_key === PlanKey.Premier &&
    period === SubscriptionPeriod.Annual
  );
}

/**
 * Check if user is attempting to downgrade billing period from Annual to Monthly
 * Period downgrades require end-of-cycle transitions to avoid billing complexity
 */
function isPeriodDowngrade({
  currentSubInfo,
  targetPeriod,
}: {
  currentSubInfo: SubscriptionInfo | undefined;
  targetPeriod: SubscriptionPeriod;
}): boolean {
  return (
    currentSubInfo?.period === SubscriptionPeriod.Annual &&
    targetPeriod === SubscriptionPeriod.Monthly
  );
}

/**
 * Determine what action the subscription card should present to the user
 * given their current subscription, the target plan, and the billing period
 * they are viewing.
 */
export function getSubscriptionAction(
  current: SubscriptionInfo | undefined,
  target: UsagePlanSchema,
  period: SubscriptionPeriod
): SubscriptionAction {
  const currentPlan = current?.plan;
  const cancelDate = !!current?.cancel_on;

  const noCurrentPlan = !currentPlan;
  const targetIsCurrent = currentPlan?.plan_key === target.plan_key;
  const targetIsFree = target.plan_key === PlanKey.Free;
  const currentIsFree = currentPlan?.plan_key === PlanKey.Free;
  const targetIsUpgrade = target.level > (currentPlan?.level || 0);
  const commitmentDiffers = current?.period !== period;

  // Check if UPI user trying to upgrade to Premier Annual (not allowed)
  // This must be checked before targetIsCurrent to prevent bypassing restrictions for commitment changes
  if (
    isUnavailableUpgrade({
      target,
      period,
      paymentMethodType: current?.payment_method_type as PaymentMethodType,
    })
  ) {
    return SubscriptionAction.Unavailable;
  }

  // Handle when target matches current plan
  if (targetIsCurrent) {
    if (commitmentDiffers) {
      // Period downgrades (Annual → Monthly) or payment restrictions require end-of-cycle transitions
      if (
        isPeriodDowngrade({ currentSubInfo: current, targetPeriod: period }) ||
        !canUpgradeImmediately(current)
      ) {
        return SubscriptionAction.ChangeCommitmentDelayedOnly;
      }
      return SubscriptionAction.ChangeCommitment;
    }
    return SubscriptionAction.CurrentPlan;
  }

  // Handle users with no plan or free plan
  if (noCurrentPlan || currentIsFree) {
    return targetIsFree
      ? SubscriptionAction.CurrentPlan
      : SubscriptionAction.Subscribe;
  }

  // Handle plan changes for existing paid subscribers
  if (targetIsUpgrade) {
    // Period downgrades (Annual → Monthly) or payment restrictions require end-of-cycle transitions
    if (
      isPeriodDowngrade({ currentSubInfo: current, targetPeriod: period }) ||
      !canUpgradeImmediately(current)
    ) {
      return SubscriptionAction.UpgradeDelayedOnly;
    }
    return SubscriptionAction.Upgrade;
  }

  return targetIsFree
    ? cancelDate
      ? SubscriptionAction.Inactive
      : SubscriptionAction.Cancel
    : SubscriptionAction.Downgrade;
}

export const canUpgradeImmediately = (
  current: SubscriptionInfo | undefined
) => {
  // if null / undefined, default to true
  // because this is a new field
  return current?.can_upgrade_immediately !== false;
};
