import axios from "axios";
import { isRevenueCatApiConfigured, revenuecatConfig } from "../config/revenuecat";
import type { SubscriptionEntitlement } from "../constants/subscription";

const TAG = "[revenuecat:api]";

type EntitlementIdMap = Map<string, string>;

let entitlementIdToLookupCache: EntitlementIdMap | null = null;
let entitlementCacheAt = 0;
const ENTITLEMENT_CACHE_MS = 5 * 60 * 1000;

async function getEntitlementIdToLookupMap(): Promise<EntitlementIdMap> {
  const now = Date.now();
  if (entitlementIdToLookupCache && now - entitlementCacheAt < ENTITLEMENT_CACHE_MS) {
    return entitlementIdToLookupCache;
  }

  const url = `${revenuecatConfig.baseUrl}/projects/${revenuecatConfig.projectId}/entitlements`;
  const { data } = await axios.get<{
    items?: Array<{ id: string; lookup_key?: string }>;
  }>(url, {
    headers: {
      Authorization: `Bearer ${revenuecatConfig.secretKey}`,
      "Content-Type": "application/json",
    },
    timeout: 15000,
  });

  const map: EntitlementIdMap = new Map();
  for (const item of data?.items ?? []) {
    if (item.id && item.lookup_key) {
      map.set(item.id, item.lookup_key);
    }
  }

  entitlementIdToLookupCache = map;
  entitlementCacheAt = now;
  return map;
}

export type RevenueCatCustomerSnapshot = {
  activeEntitlements: SubscriptionEntitlement[];
  expiresAt: Date | null;
};

/**
 * Fetch active entitlements from RevenueCat API v2 for server-side sync.
 * customer_id must be the app_user_id (Mongo user _id).
 */
export async function fetchCustomerEntitlementsFromApi(
  appUserId: string,
): Promise<RevenueCatCustomerSnapshot | null> {
  if (!isRevenueCatApiConfigured()) {
    console.warn(
      `${TAG} API not configured — set REVENUECAT_SECRET_KEY and REVENUECAT_PROJECT_ID`,
    );
    return null;
  }

  const encodedId = encodeURIComponent(appUserId);
  const url = `${revenuecatConfig.baseUrl}/projects/${revenuecatConfig.projectId}/customers/${encodedId}/active_entitlements`;

  try {
    const [entitlementMap, { data }] = await Promise.all([
      getEntitlementIdToLookupMap(),
      axios.get<{
        items?: Array<{ entitlement_id: string; expires_at: number | null }>;
      }>(url, {
        headers: {
          Authorization: `Bearer ${revenuecatConfig.secretKey}`,
          "Content-Type": "application/json",
        },
        timeout: 15000,
      }),
    ]);

    const items = data?.items ?? [];
    const premium = revenuecatConfig.premiumEntitlement;
    const family = revenuecatConfig.familyEntitlement;

    let latestExpires: number | null = null;
    const active: SubscriptionEntitlement[] = [];

    for (const item of items) {
      const lookup = entitlementMap.get(item.entitlement_id) ?? item.entitlement_id;
      if (lookup === family) {
        if (!active.includes("family")) active.push("family");
        if (item.expires_at != null) {
          latestExpires =
            latestExpires == null
              ? item.expires_at
              : Math.max(latestExpires, item.expires_at);
        }
      } else if (lookup === premium) {
        if (!active.includes("premium")) active.push("premium");
        if (item.expires_at != null) {
          latestExpires =
            latestExpires == null
              ? item.expires_at
              : Math.max(latestExpires, item.expires_at);
        }
      }
    }

    return {
      activeEntitlements: active,
      expiresAt: latestExpires != null ? new Date(latestExpires) : null,
    };
  } catch (err: unknown) {
    const status = axios.isAxiosError(err) ? err.response?.status : undefined;
    if (status === 404) {
      console.log(`${TAG} No customer found for app_user_id=${appUserId}`);
      return { activeEntitlements: [], expiresAt: null };
    }
    const msg = err instanceof Error ? err.message : String(err);
    console.error(`${TAG} Failed to fetch entitlements for ${appUserId}: ${msg}`);
    throw err;
  }
}
