import { createAdminClient } from "@/lib/supabase/admin";
import {
  BasePlanEntitlements,
  EffectiveEntitlements,
  ActiveOverrideDetail,
} from "@/types/entitlement";
import {
  getOrSetCache,
  invalidateCache,
  cacheKeys,
  getCachedJson,
  setCachedJson,
  bumpCacheVersion,
  getCacheVersion,
  CACHE_TTL,
} from "@/lib/redis";

export type GlobalListingLimitsMode = "UNLIMITED" | "ENFORCED";

// In-memory fallback if Redis is unavailable
let inMemoryLimitsMode: GlobalListingLimitsMode = "UNLIMITED";

const DEFAULT_FREE_ENTITLEMENTS: BasePlanEntitlements = {
  max_active_listings: 3, // 3 listings per month for Normal User / Direct Owner
  featured_listing_credits: 0,
  sub_agents_allowed: 0,
  lead_analytics_enabled: false,
  verified_agency_badge: false,
  custom_branding: false,
  priority_support: false,
};

/**
 * Retrieve the current Global Listing Limits Mode.
 * Defaults to "UNLIMITED" for the platform rollout and testing period.
 */
export async function getGlobalListingLimitsMode(): Promise<GlobalListingLimitsMode> {
  try {
    const cached = await getCachedJson<GlobalListingLimitsMode>(cacheKeys.globalListingLimits());
    if (cached === "ENFORCED" || cached === "UNLIMITED") {
      inMemoryLimitsMode = cached;
      return cached;
    }
    return inMemoryLimitsMode;
  } catch {
    return inMemoryLimitsMode;
  }
}

/**
 * Set the Global Listing Limits Mode.
 * Restricted to Super Admin actions.
 */
export async function setGlobalListingLimitsMode(
  mode: GlobalListingLimitsMode,
  actor?: { id: string; email?: string }
): Promise<void> {
  inMemoryLimitsMode = mode;
  await setCachedJson(cacheKeys.globalListingLimits(), mode, CACHE_TTL.STATIC);
  // Bust all cached user and agency entitlements across the platform in O(1) time
  await bumpCacheVersion("entitlements");
}

/**
 * Invalidate cached entitlements in Redis
 */
export async function invalidateEntitlementsCache(targetId: string): Promise<void> {
  if (!targetId) return;
  await invalidateCache(cacheKeys.entitlements(targetId));
  const ver = await getCacheVersion("entitlements");
  await invalidateCache(cacheKeys.entitlements(targetId, ver));
}

/**
 * Calculates the Effective Entitlements for a User or Agency (Cached in Redis)
 * Handles:
 * 1. Global Launch Mode (Unlimited Listings Active) vs Plan Enforced Mode
 * 2. Plan Quotas: Free (3 listings/month), Agent Pro (Unlimited), Agency Growth (Unlimited)
 * 3. Granular Super Admin Overrides
 */
export async function getEffectiveEntitlements(params: {
  userId?: string;
  agencyId?: string;
}): Promise<EffectiveEntitlements> {
  const { userId, agencyId } = params;
  const targetId = agencyId || userId || "anonymous";

  const cacheVer = await getCacheVersion("entitlements");

  return getOrSetCache(
    cacheKeys.entitlements(targetId, cacheVer),
    async () => {
      const supabase = createAdminClient();

      // 1. Fetch Global Limits Mode (Launch Unlimited vs Enforced)
      const limitsMode = await getGlobalListingLimitsMode();
      const isUnlimitedMode = limitsMode === "UNLIMITED";

      // 2. Fetch active subscription & plan
      let baseEntitlements: BasePlanEntitlements = { ...DEFAULT_FREE_ENTITLEMENTS };

      const subQuery = supabase
        .from("subscriptions")
        .select("status, plan:subscription_plans(entitlements)")
        .eq("status", "ACTIVE");

      if (agencyId) {
        subQuery.eq("agency_id", agencyId);
      } else if (userId) {
        subQuery.eq("user_id", userId);
      }

      const { data: subData } = await subQuery.maybeSingle();
      const hasActiveSubscription = subData?.status === "ACTIVE";

      if (subData?.plan && typeof subData.plan === "object" && "entitlements" in subData.plan) {
        const planEntitlements = subData.plan.entitlements as Partial<BasePlanEntitlements>;
        baseEntitlements = {
          ...baseEntitlements,
          ...planEntitlements,
        };
      }

      // 3. Fetch active non-expired admin overrides
      const now = new Date().toISOString();
      const overrideQuery = supabase
        .from("entitlement_overrides")
        .select("entitlement_key, override_value, expires_at, reason")
        .eq("is_active", true)
        .or(`expires_at.is.null,expires_at.gt.${now}`);

      if (agencyId) {
        overrideQuery.eq("target_agency_id", agencyId);
      } else if (userId) {
        overrideQuery.eq("target_user_id", userId);
      }

      const { data: overrides } = await overrideQuery;

      const activeOverrides: ActiveOverrideDetail[] = (overrides || []).map((o) => ({
        entitlementKey: o.entitlement_key,
        overrideValue: o.override_value,
        expiresAt: o.expires_at,
        reason: o.reason,
      }));

      // 4. Compute effective merged entitlements
      let maxActiveListings = baseEntitlements.max_active_listings;
      let featuredListingCredits = baseEntitlements.featured_listing_credits;
      let subAgentsAllowed = baseEntitlements.sub_agents_allowed;
      let leadAnalyticsEnabled = baseEntitlements.lead_analytics_enabled;
      let verifiedAgencyBadge = baseEntitlements.verified_agency_badge;
      let customBranding = baseEntitlements.custom_branding;
      let prioritySupport = baseEntitlements.priority_support;

      for (const override of activeOverrides) {
        switch (override.entitlementKey) {
          case "max_active_listings":
            maxActiveListings = Math.max(maxActiveListings, Number(override.overrideValue) || 0);
            break;
          case "featured_listing_credits":
            featuredListingCredits += Number(override.overrideValue) || 0;
            break;
          case "sub_agents_allowed":
            subAgentsAllowed = Math.max(subAgentsAllowed, Number(override.overrideValue) || 0);
            break;
          case "lead_analytics_enabled":
            if (override.overrideValue === true) leadAnalyticsEnabled = true;
            break;
          case "verified_agency_badge":
            if (override.overrideValue === true) verifiedAgencyBadge = true;
            break;
          case "custom_branding":
            if (override.overrideValue === true) customBranding = true;
            break;
          case "priority_support":
            if (override.overrideValue === true) prioritySupport = true;
            break;
        }
      }

      // 5. Query active property usage
      const countQuery = supabase
        .from("properties")
        .select("id", { count: "exact", head: true })
        .in("status", ["PUBLISHED", "PENDING_REVIEW", "APPROVED"])
        .is("deleted_at", null);

      if (agencyId) {
        countQuery.eq("agency_id", agencyId);
      } else if (userId) {
        countQuery.eq("created_by_user_id", userId);
      }

      const { count } = await countQuery;
      const currentActiveListingsCount = count || 0;

      // 6. Calculate canCreateListing
      let canCreateListing = true;
      let monthlyUsage = currentActiveListingsCount;

      if (isUnlimitedMode) {
        // Launch Mode: All users (normal users, agents, agencies) can post unlimited listings
        canCreateListing = true;
        maxActiveListings = 999999;
      } else if (hasActiveSubscription) {
        // Enforced Mode - Paid Tier: Agent Pro and Agency Growth have unlimited listings
        canCreateListing = true;
        maxActiveListings = 999999;
      } else {
        // Enforced Mode - Free Tier: Normal user gets 3 listings per calendar month
        try {
          const startOfMonth = new Date();
          startOfMonth.setDate(1);
          startOfMonth.setHours(0, 0, 0, 0);

          const monthlyQuery = supabase
            .from("properties")
            .select("id", { count: "exact", head: true })
            .gte("created_at", startOfMonth.toISOString())
            .is("deleted_at", null);

          if (agencyId) {
            monthlyQuery.eq("agency_id", agencyId);
          } else if (userId) {
            monthlyQuery.eq("created_by_user_id", userId);
          }

          const { count: monthlyCount } = await monthlyQuery;
          monthlyUsage = typeof monthlyCount === "number" ? monthlyCount : currentActiveListingsCount;
        } catch {
          monthlyUsage = currentActiveListingsCount;
        }

        const effectiveMonthlyLimit = Math.max(3, maxActiveListings);
        canCreateListing = monthlyUsage < effectiveMonthlyLimit;
        maxActiveListings = effectiveMonthlyLimit;
      }

      return {
        maxActiveListings,
        featuredListingCredits,
        subAgentsAllowed,
        leadAnalyticsEnabled,
        verifiedAgencyBadge,
        customBranding,
        prioritySupport,
        activeOverrides,
        currentActiveListingsCount,
        canCreateListing,
        isUnlimitedMode,
        monthlyUsage,
      };
    },
    CACHE_TTL.MEDIUM
  );
}
