import type { Package } from '../../api';

type PackageChange = {
  isUpgrade: boolean;
  isDowngrade: boolean;
};

export type PackageComparisonRow =
  | {
      id: string;
      type: 'limit';
      limitKey: 'max_photos' | 'max_guests' | 'gallery_days' | 'max_events_per_year';
    }
  | {
      id: string;
      type: 'value';
      valueKey: 'included_package_slug';
    }
  | {
      id: string;
      type: 'feature';
      featureKey: string;
    };

function normalizePackageFeatures(pkg: Package | null): string[] {
  if (!pkg?.features) {
    return [];
  }

  if (Array.isArray(pkg.features)) {
    return pkg.features.filter((feature): feature is string => typeof feature === 'string' && feature.trim().length > 0);
  }

  if (typeof pkg.features === 'object') {
    return Object.entries(pkg.features)
      .filter(([, enabled]) => enabled)
      .map(([key]) => key);
  }

  return [];
}

export function getEnabledPackageFeatures(pkg: Package): string[] {
  return normalizePackageFeatures(pkg);
}

function collectFeatures(pkg: Package | null): Set<string> {
  return new Set(normalizePackageFeatures(pkg));
}

function compareLimit(candidate: number | null, active: number | null): number {
  if (active === null) {
    return candidate === null ? 0 : -1;
  }

  if (candidate === null) {
    return 1;
  }

  if (candidate > active) return 1;
  if (candidate < active) return -1;
  return 0;
}

export function classifyPackageChange(pkg: Package, active: Package | null): PackageChange {
  if (!active) {
    return { isUpgrade: false, isDowngrade: false };
  }

  if (pkg.type === 'reseller' || active.type === 'reseller') {
    return { isUpgrade: false, isDowngrade: false };
  }

  const activeFeatures = collectFeatures(active);
  const candidateFeatures = collectFeatures(pkg);

  const hasFeatureUpgrade = Array.from(candidateFeatures).some((feature) => !activeFeatures.has(feature));
  const hasFeatureDowngrade = Array.from(activeFeatures).some((feature) => !candidateFeatures.has(feature));

  const limitKeys: Array<keyof Package> = ['max_photos', 'max_guests', 'gallery_days'];
  let hasLimitUpgrade = false;
  let hasLimitDowngrade = false;

  limitKeys.forEach((key) => {
    const candidateLimit = pkg[key] ?? null;
    const activeLimit = active[key] ?? null;
    const delta = compareLimit(candidateLimit, activeLimit);
    if (delta > 0) {
      hasLimitUpgrade = true;
    } else if (delta < 0) {
      hasLimitDowngrade = true;
    }
  });

  const hasUpgrade = hasFeatureUpgrade || hasLimitUpgrade;
  const hasDowngrade = hasFeatureDowngrade || hasLimitDowngrade;

  if (hasUpgrade && !hasDowngrade) {
    return { isUpgrade: true, isDowngrade: false };
  }

  if (hasDowngrade) {
    return { isUpgrade: false, isDowngrade: true };
  }

  return { isUpgrade: false, isDowngrade: false };
}

export function selectRecommendedPackageId(
  packages: Package[],
  feature: string | null,
  activePackage: Package | null
): number | null {
  if (!feature) {
    return null;
  }

  if (packages.some((pkg) => pkg.type === 'reseller')) {
    return null;
  }

  const candidates = feature === 'watermark_allowed'
    ? packages.filter((pkg) => pkg.watermark_allowed === true)
    : packages.filter((pkg) => normalizePackageFeatures(pkg).includes(feature));
  if (candidates.length === 0) {
    return null;
  }

  const upgrades = candidates.filter((pkg) => classifyPackageChange(pkg, activePackage).isUpgrade);
  const pool = upgrades.length ? upgrades : candidates;
  const sorted = [...pool].sort((a, b) => a.price - b.price);

  return sorted[0]?.id ?? null;
}

export function buildPackageComparisonRows(packages: Package[]): PackageComparisonRow[] {
  const isResellerCatalog = packages.some(
    (pkg) => pkg.type === 'reseller' || pkg.max_events_per_year !== undefined || pkg.included_package_slug !== undefined
  );

  const limitRows: PackageComparisonRow[] = isResellerCatalog
    ? [
        { id: 'value.included_package_slug', type: 'value', valueKey: 'included_package_slug' },
        { id: 'limit.max_events_per_year', type: 'limit', limitKey: 'max_events_per_year' },
      ]
    : [
        { id: 'limit.max_photos', type: 'limit', limitKey: 'max_photos' },
        { id: 'limit.max_guests', type: 'limit', limitKey: 'max_guests' },
        { id: 'limit.gallery_days', type: 'limit', limitKey: 'gallery_days' },
      ];

  const featureKeys = new Set<string>();
  packages.forEach((pkg) => {
    normalizePackageFeatures(pkg).forEach((key) => {
      if (key !== 'photos') {
        featureKeys.add(key);
      }
    });
  });

  const featureRows = Array.from(featureKeys)
    .sort((a, b) => a.localeCompare(b))
    .map((featureKey) => ({
      id: `feature.${featureKey}`,
      type: 'feature' as const,
      featureKey,
    }));

  return [...limitRows, ...featureRows];
}
