/**
 * RevenueCat Capacitor IAP wrapper (#100).
 * No-ops on web; only configures / purchases on native platforms.
 */
import { Purchases } from '@revenuecat/purchases-capacitor';
import type { PurchasesPackage } from '@revenuecat/purchases-capacitor';
import { decodeJwtPayload } from '../auth/jwtHelpers';
import { getAccessToken } from '../auth/tokenStorage';
import { isNativePlatform } from '../platform/nativePlatform';

let configurePromise: Promise<void> | null = null;
let configured = false;

type AccountLike = { id?: number | string | null };

function getCapacitorPlatform(): string {
  if (typeof window === 'undefined') return 'web';
  const Cap = window.Capacitor as
    | { getPlatform?: () => string; isNativePlatform?: () => boolean }
    | undefined;
  if (typeof Cap?.getPlatform === 'function') {
    return Cap.getPlatform();
  }
  return 'web';
}

function revenueCatApiKey(): string {
  const platform = getCapacitorPlatform();
  if (platform === 'ios') {
    return (process.env.REACT_APP_REVENUECAT_APPLE_API_KEY || '').trim();
  }
  if (platform === 'android') {
    return (process.env.REACT_APP_REVENUECAT_GOOGLE_API_KEY || '').trim();
  }
  // Fallback: prefer Google then Apple if platform unknown on native.
  return (
    (process.env.REACT_APP_REVENUECAT_GOOGLE_API_KEY || '').trim() ||
    (process.env.REACT_APP_REVENUECAT_APPLE_API_KEY || '').trim()
  );
}

/** Prefer numeric user pk; fall back to JWT `user_id` claim. */
export function resolveAppUserId(account?: AccountLike | null): string | null {
  if (account?.id != null && String(account.id).trim() !== '') {
    return String(account.id);
  }
  const token = getAccessToken();
  if (!token) return null;
  const payload = decodeJwtPayload(token) as { user_id?: number | string } | null;
  if (payload?.user_id != null && String(payload.user_id).trim() !== '') {
    return String(payload.user_id);
  }
  return null;
}

export async function configureRevenueCat(): Promise<boolean> {
  if (!isNativePlatform()) return false;
  if (configured) return true;
  if (configurePromise) {
    await configurePromise;
    return configured;
  }

  configurePromise = (async () => {
    const apiKey = revenueCatApiKey();
    if (!apiKey) {
      console.warn(
        'RevenueCat API key missing (REACT_APP_REVENUECAT_APPLE_API_KEY / GOOGLE).'
      );
      return;
    }
    await Purchases.configure({ apiKey });
    configured = true;
  })();

  try {
    await configurePromise;
  } finally {
    configurePromise = null;
  }
  return configured;
}

export async function logInRevenueCat(
  appUserIdOrAccount?: string | AccountLike | null
): Promise<void> {
  if (!isNativePlatform()) return;
  const appUserID =
    typeof appUserIdOrAccount === 'string'
      ? appUserIdOrAccount
      : resolveAppUserId(appUserIdOrAccount);
  if (!appUserID) {
    console.warn('RevenueCat logIn skipped: no app user id');
    return;
  }
  const ready = await configureRevenueCat();
  if (!ready) return;
  await Purchases.logIn({ appUserID });
}

export async function logOutRevenueCat(): Promise<void> {
  if (!isNativePlatform()) return;
  if (!configured) return;
  try {
    await Purchases.logOut();
  } catch (error) {
    // Anonymous / already logged out — ignore.
    console.warn('RevenueCat logOut', error);
  }
}

function packageMatchesPlan(pkg: PurchasesPackage, planSlug: string): boolean {
  const slug = planSlug.toLowerCase();
  const id = (pkg.identifier || '').toLowerCase();
  const productId = (pkg.product?.identifier || '').toLowerCase();
  return id === slug || id.includes(slug) || productId.includes(slug);
}

async function resolvePackageForPlan(
  planSlug?: string
): Promise<PurchasesPackage> {
  const offerings = await Purchases.getOfferings();
  const offeringId = (process.env.REACT_APP_REVENUECAT_OFFERING_ID || '').trim();
  const offering =
    (offeringId && offerings.all?.[offeringId]) || offerings.current || null;
  if (!offering) {
    throw new Error('No RevenueCat offerings available. Check the RC dashboard.');
  }

  const packages = offering.availablePackages || [];
  if (!packages.length) {
    throw new Error('RevenueCat offering has no packages.');
  }

  if (planSlug) {
    const match = packages.find((pkg) => packageMatchesPlan(pkg, planSlug));
    if (match) return match;
    throw new Error(`No store package matches plan "${planSlug}".`);
  }

  return (
    offering.monthly ||
    packages.find((pkg) => (pkg.identifier || '').includes('monthly')) ||
    packages[0]
  );
}

export async function purchasePlan(planSlug?: string): Promise<void> {
  if (!isNativePlatform()) {
    throw new Error('Store purchases are only available in the mobile app.');
  }
  const ready = await configureRevenueCat();
  if (!ready) {
    throw new Error('RevenueCat is not configured. Missing API key.');
  }
  const aPackage = await resolvePackageForPlan(planSlug);
  await Purchases.purchasePackage({ aPackage });
}

export async function restorePurchases(): Promise<void> {
  if (!isNativePlatform()) {
    throw new Error('Restore is only available in the mobile app.');
  }
  const ready = await configureRevenueCat();
  if (!ready) {
    throw new Error('RevenueCat is not configured. Missing API key.');
  }
  await Purchases.restorePurchases();
}

export function isPurchaseCancelledError(error: unknown): boolean {
  const err = error as { userCancelled?: boolean; code?: number | string };
  if (err?.userCancelled === true) return true;
  // PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR === 1
  return err?.code === 1 || err?.code === '1' || err?.code === 'PURCHASE_CANCELLED';
}
