import { apiClient } from '../client';
import {
  // New types
  SubscriptionTier,
  SUBSCRIPTION_TIERS,
  BillingCycle,
  PlanMetadata,
  AvailablePlans,
  UsageSummary,
  FeatureCheckResponse,
  QuotaCheckResponse,
  PlanUpgradeValidation,
  PlanUpgradeResult,
  doesPlanMeetMinimum,
  getPlanColor,
  getYearlyDiscountPercentage,
  PLAN_HIERARCHY,

  // Analytics levels
  ANALYTICS_LEVELS,
  AnalyticsLevel,
  ANALYTICS_HIERARCHY
} from '../types/subscription';

// Map plan tiers to analytics levels based on backend data
const TIER_TO_ANALYTICS_LEVEL: Record<SubscriptionTier | string, AnalyticsLevel> = {
  [SUBSCRIPTION_TIERS.STARTER]: ANALYTICS_LEVELS.BASIC,
  [SUBSCRIPTION_TIERS.PROFESSIONAL]: ANALYTICS_LEVELS.ADVANCED,
  [SUBSCRIPTION_TIERS.ENTERPRISE]: ANALYTICS_LEVELS.PREDICTIVE,
  'demo': ANALYTICS_LEVELS.ADVANCED,  // Treat demo tier same as professional for analytics access
};

// Cache for available plans
let cachedPlans: AvailablePlans | null = null;
let lastFetchTime: number | null = null;
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes

export class SubscriptionService {
  private readonly baseUrl = '/tenants';
  private readonly plansUrl = '/plans';

  // ============================================================================
  // NEW METHODS - Centralized Plans API
  // ============================================================================

  /**
   * Invalidate cached plan data
   * Call this when subscription changes to ensure fresh data on next fetch
   */
  invalidateCache(): void {
    cachedPlans = null;
    lastFetchTime = null;
  }

  /**
   * Fetch available subscription plans with complete metadata
   * Uses cached data if available and fresh (5 min cache)
   */
  async fetchAvailablePlans(): Promise<AvailablePlans> {
    const now = Date.now();

    // Return cached data if it's still valid
    if (cachedPlans && lastFetchTime && (now - lastFetchTime) < CACHE_DURATION) {
      return cachedPlans;
    }

    try {
      const plans = await apiClient.get<AvailablePlans>(this.plansUrl);
      cachedPlans = plans;
      lastFetchTime = now;
      return plans;
    } catch (error) {
      console.error('Failed to fetch subscription plans:', error);
      throw error;
    }
  }

  /**
   * Get metadata for a specific plan tier
   */
  async getPlanMetadata(tier: SubscriptionTier): Promise<PlanMetadata | null> {
    try {
      const plans = await this.fetchAvailablePlans();
      return plans.plans[tier] || null;
    } catch (error) {
      console.error('Failed to get plan metadata:', error);
      return null;
    }
  }

  /**
   * Get all available features for a tier
   */
  async getPlanFeatures(tier: SubscriptionTier): Promise<string[]> {
    try {
      const metadata = await this.getPlanMetadata(tier);
      return metadata?.features || [];
    } catch (error) {
      console.error('Failed to get plan features:', error);
      return [];
    }
  }

  /**
   * Check if a feature is available in a tier
   */
  async hasFeatureInTier(tier: SubscriptionTier, featureName: string): Promise<boolean> {
    try {
      const features = await this.getPlanFeatures(tier);
      return features.includes(featureName);
    } catch (error) {
      console.error('Failed to check feature availability:', error);
      return false;
    }
  }

  /**
   * Get plan comparison data for pricing page
   */
  async getPlanComparison(): Promise<{
    tiers: SubscriptionTier[];
    metadata: Record<SubscriptionTier, PlanMetadata>;
  }> {
    try {
      const plans = await this.fetchAvailablePlans();
      return {
        tiers: [
          SUBSCRIPTION_TIERS.STARTER,
          SUBSCRIPTION_TIERS.PROFESSIONAL,
          SUBSCRIPTION_TIERS.ENTERPRISE
        ],
        metadata: plans.plans
      };
    } catch (error) {
      console.error('Failed to get plan comparison:', error);
      throw error;
    }
  }

  /**
   * Calculate savings for yearly billing
   */
  calculateYearlySavings(monthlyPrice: number, yearlyPrice: number): {
    savingsAmount: number;
    savingsPercentage: number;
    monthsFree: number;
  } {
    const yearlyAnnual = monthlyPrice * 12;
    const savingsAmount = yearlyAnnual - yearlyPrice;
    const savingsPercentage = getYearlyDiscountPercentage(monthlyPrice, yearlyPrice);
    const monthsFree = Math.round(savingsAmount / monthlyPrice);

    return {
      savingsAmount,
      savingsPercentage,
      monthsFree
    };
  }

  /**
   * Check if user's plan meets minimum requirement
   */
  checkPlanMeetsMinimum(userPlan: SubscriptionTier, requiredPlan: SubscriptionTier): boolean {
    return doesPlanMeetMinimum(userPlan, requiredPlan);
  }

  /**
   * Get plan display color
   */
  getPlanDisplayColor(tier: SubscriptionTier): string {
    return getPlanColor(tier);
  }

  // ============================================================================
  // TENANT SUBSCRIPTION STATUS & USAGE
  // ============================================================================

  /**
   * Get current usage summary for a tenant
   */
  async getUsageSummary(tenantId: string): Promise<UsageSummary> {
    return apiClient.get<UsageSummary>(`/tenants/${tenantId}/subscription/usage`);
  }

  /**
   * Check if tenant has access to a specific feature
   */
  async checkFeatureAccess(
    tenantId: string,
    featureName: string
  ): Promise<FeatureCheckResponse> {
    return apiClient.get<FeatureCheckResponse>(
      `/tenants/${tenantId}/subscription/features/${featureName}`
    );
  }

  /**
   * Check if tenant can perform an action within quota limits
   */
 async checkQuotaLimit(
    tenantId: string,
    quotaType: string,
    requestedAmount?: number
  ): Promise<QuotaCheckResponse> {
    // Map quotaType to the new subscription limit endpoints
    let endpoint: string;
    switch (quotaType) {
      case 'inventory_items':
      case 'products':
        endpoint = 'products';
        break;
      case 'users':
        endpoint = 'users';
        break;
      case 'locations':
        endpoint = 'locations';
        break;
      case 'recipes':
        endpoint = 'recipes';
        break;
      case 'suppliers':
        endpoint = 'suppliers';
        break;
      default:
        throw new Error(`Unsupported quota type: ${quotaType}`);
    }

    const url = `/tenants/${tenantId}/subscription/limits/${endpoint}`;
    
    // Get the response from the endpoint (returns different format than expected)
    const response = await apiClient.get<{
      can_add: boolean;
      current_count?: number;
      max_allowed?: number;
      reason?: string;
      message?: string;
    }>(url);
    
    // Map the response to QuotaCheckResponse format
    return {
      allowed: response.can_add,
      current: response.current_count || 0,
      limit: response.max_allowed || null,
      remaining: response.max_allowed !== undefined && response.current_count !== undefined 
        ? response.max_allowed - response.current_count 
        : null,
      message: response.reason || response.message || ''
    };
  }

  async validatePlanUpgrade(tenantId: string, planKey: string): Promise<PlanUpgradeValidation> {
    return apiClient.get<PlanUpgradeValidation>(`/tenants/${tenantId}/subscription/validate-upgrade/${planKey}`);
  }

  async upgradePlan(tenantId: string, planKey: string, billingCycle: BillingCycle = 'monthly'): Promise<PlanUpgradeResult> {
    // The backend expects new_plan and billing_cycle as query parameters
    return apiClient.post<PlanUpgradeResult>(
      `/tenants/${tenantId}/subscription/upgrade?new_plan=${planKey}&billing_cycle=${billingCycle}`,
      {}
    );
  }

  async canAddLocation(tenantId: string): Promise<{ can_add: boolean; reason?: string; current_count?: number; max_allowed?: number }> {
    return apiClient.get(`/tenants/${tenantId}/subscription/limits/locations`);
  }

  async canAddProduct(tenantId: string): Promise<{ can_add: boolean; reason?: string; current_count?: number; max_allowed?: number }> {
    return apiClient.get(`/tenants/${tenantId}/subscription/limits/products`);
  }

  async canAddUser(tenantId: string): Promise<{ can_add: boolean; reason?: string; current_count?: number; max_allowed?: number }> {
    return apiClient.get(`/tenants/${tenantId}/subscription/limits/users`);
  }

  async canAddRecipe(tenantId: string): Promise<{ can_add: boolean; reason?: string; current_count?: number; max_allowed?: number }> {
    return apiClient.get(`/tenants/${tenantId}/subscription/limits/recipes`);
  }

  async canAddSupplier(tenantId: string): Promise<{ can_add: boolean; reason?: string; current_count?: number; max_allowed?: number }> {
    return apiClient.get(`/tenants/${tenantId}/subscription/limits/suppliers`);
  }

  async hasFeature(tenantId: string, featureName: string): Promise<{ has_feature: boolean; feature_value?: any; plan?: string; reason?: string }> {
    return apiClient.get(`/tenants/${tenantId}/subscription/features/${featureName}`);
  }

  formatPrice(amount: number): string {
    return new Intl.NumberFormat('es-ES', {
      style: 'currency',
      currency: 'EUR',
      minimumFractionDigits: 0,
      maximumFractionDigits: 2
    }).format(amount);
  }


  /**
   * Get plan display information
   */
  async getPlanDisplayInfo(planKey: string) {
    try {
      const plans = await this.fetchAvailablePlans();
      const plan = plans.plans[planKey as SubscriptionTier];

      if (plan) {
        return {
          name: plan.name,
          color: this.getPlanColor(planKey as SubscriptionTier),
          description: plan.description,
          monthlyPrice: plan.monthly_price
        };
      }

      return { name: 'Desconocido', color: 'gray', description: '', monthlyPrice: 0 };
    } catch (error) {
      console.error('Failed to get plan display info:', error);
      return { name: 'Desconocido', color: 'gray', description: '', monthlyPrice: 0 };
    }
  }

  /**
   * Get plan color based on plan key
   */
  getPlanColor(planKey: string): string {
    switch (planKey) {
      case SUBSCRIPTION_TIERS.STARTER:
        return 'blue';
      case SUBSCRIPTION_TIERS.PROFESSIONAL:
        return 'purple';
      case SUBSCRIPTION_TIERS.ENTERPRISE:
        return 'amber';
      default:
        return 'gray';
    }
  }

  /**
   * Get analytics level for a plan tier
   */
  getAnalyticsLevelForTier(tier: SubscriptionTier): AnalyticsLevel {
    return TIER_TO_ANALYTICS_LEVEL[tier] || ANALYTICS_LEVELS.NONE;
  }

  /**
   * Get analytics level for a plan (alias for getAnalyticsLevelForTier)
   * @deprecated Use getAnalyticsLevelForTier instead
   */
  getAnalyticsLevelForPlan(tier: SubscriptionTier): AnalyticsLevel {
    return this.getAnalyticsLevelForTier(tier);
  }

  /**
   * Check if analytics level meets minimum requirements
   */
  doesAnalyticsLevelMeetMinimum(level: AnalyticsLevel, minimumRequired: AnalyticsLevel): boolean {
    return ANALYTICS_HIERARCHY[level] >= ANALYTICS_HIERARCHY[minimumRequired];
  }

  /**
   * Cancel subscription - Downgrade to read-only mode
   */
  async cancelSubscription(tenantId: string, reason?: string): Promise<{
    success: boolean;
    message: string;
    status: string;
    cancellation_effective_date: string;
    days_remaining: number;
    read_only_mode_starts: string;
  }> {
    return apiClient.post(`/tenants/${tenantId}/subscription/cancel`, {
      reason: reason || ''
    });
  }

  /**
   * Reactivate a cancelled or inactive subscription
   */
  async reactivateSubscription(tenantId: string, plan: string = 'starter'): Promise<{
    success: boolean;
    message: string;
    status: string;
    plan: string;
    next_billing_date: string | null;
  }> {
    return apiClient.post(`/tenants/${tenantId}/subscription/reactivate`, {
      plan
    });
  }

  /**
   * Get subscription status including read-only mode info
   */
  async getSubscriptionStatus(tenantId: string): Promise<{
    tenant_id: string;
    status: string;
    plan: string;
    is_read_only: boolean;
    cancellation_effective_date: string | null;
    days_until_inactive: number | null;
    billing_cycle?: string;
    next_billing_date?: string;
  }> {
    return apiClient.get(`/tenants/${tenantId}/subscription/status`);
  }

  /**
   * Get invoice history for a tenant
   */
  async getInvoices(tenantId: string): Promise<Array<{
    id: string;
    date: string;
    amount: number;
    currency: string;
    status: string;
    description: string | null;
    invoice_pdf: string | null;
    hosted_invoice_url: string | null;
  }>> {
    return apiClient.get(`/tenants/${tenantId}/subscription/invoices`);
  }

  /**
   * Get the current payment method for a subscription
   */
  async getCurrentPaymentMethod(
    tenantId: string
  ): Promise<{
    brand: string;
    last4: string;
    exp_month?: number;
    exp_year?: number;
  } | null> {
    try {
      const response = await apiClient.get(`/tenants/${tenantId}/subscription/payment-method`);
      return response;
    } catch (error) {
      console.error('Failed to get current payment method:', error);
      return null;
    }
  }

  /**
   * Update the default payment method for a subscription
   */
  async updatePaymentMethod(
    tenantId: string,
    paymentMethodId: string
  ): Promise<{
    success: boolean;
    message: string;
    payment_method_id: string;
    brand: string;
    last4: string;
    exp_month?: number;
    exp_year?: number;
    requires_action?: boolean;
    client_secret?: string;
    payment_intent_status?: string;
  }> {
    return apiClient.post(`/tenants/${tenantId}/subscription/payment-method`, {
      payment_method_id: paymentMethodId
    });
  }



  // ============================================================================
  // NEW METHODS - Usage Forecasting & Predictive Analytics
  // ============================================================================

  /**
   * Get usage forecast for all metrics
   * Returns predictions for when tenant will hit limits based on growth rate
   */
  async getUsageForecast(tenantId: string): Promise<{
    tenant_id: string;
    forecasted_at: string;
    metrics: Array<{
      metric: string;
      label: string;
      current: number;
      limit: number | null;
      unit: string;
      daily_growth_rate: number | null;
      predicted_breach_date: string | null;
      days_until_breach: number | null;
      usage_percentage: number;
      status: string;
      trend_data: Array<{ date: string; value: number }>;
    }>;
  }> {
    return apiClient.get(`/usage-forecast?tenant_id=${tenantId}`);
  }

  /**
   * Track daily usage (called by cron jobs or manually)
   * Stores usage snapshots in Redis for trend analysis
   */
  async trackDailyUsage(
    tenantId: string,
    metric: string,
    value: number
  ): Promise<{
    success: boolean;
    tenant_id: string;
    metric: string;
    value: number;
    date: string;
  }> {
    return apiClient.post('/usage-forecast/track-usage', {
      tenant_id: tenantId,
      metric,
      value,
    });
  }

  /**
   * Get current subscription for a tenant
   * Combines subscription data with available plans metadata
   */
  async getCurrentSubscription(tenantId: string): Promise<{
    tier: SubscriptionTier;
    billing_cycle: 'monthly' | 'yearly';
    monthly_price: number;
    yearly_price: number;
    renewal_date: string;
    trial_ends_at?: string;
    limits: {
      users: number | null;
      locations: number | null;
      products: number | null;
      recipes: number | null;
      suppliers: number | null;
      trainingJobsPerDay: number | null;
      forecastsPerDay: number | null;
      storageGB: number | null;
    };
    availablePlans: AvailablePlans;
  }> {
    // Fetch both subscription status and available plans
    const [status, plans] = await Promise.all([
      this.getSubscriptionStatus(tenantId),
      this.fetchAvailablePlans(),
    ]);

    const currentPlan = plans.plans[status.plan as SubscriptionTier];

    return {
      tier: status.plan as SubscriptionTier,
      billing_cycle: (status.billing_cycle as 'monthly' | 'yearly') || 'monthly',
      monthly_price: currentPlan?.monthly_price || 0,
      yearly_price: currentPlan?.yearly_price || 0,
      renewal_date: status.next_billing_date || new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
      limits: {
        users: currentPlan?.limits?.users ?? null,
        locations: currentPlan?.limits?.locations ?? null,
        products: currentPlan?.limits?.products ?? null,
        recipes: currentPlan?.limits?.recipes ?? null,
        suppliers: currentPlan?.limits?.suppliers ?? null,
        trainingJobsPerDay: currentPlan?.limits?.training_jobs_per_day ?? null,
        forecastsPerDay: currentPlan?.limits?.forecasts_per_day ?? null,
        storageGB: currentPlan?.limits?.storage_gb ?? null,
      },
      availablePlans: plans,
    };
  }
}

export const subscriptionService = new SubscriptionService();
