/**
 * Subscription Tier Service
 *
 * Manages subscription tier data from the database with in-memory caching.
 * Provides lookups by slug, ID, and utility methods for credit allocation,
 * rate limits, and PayPal plan IDs.
 *
 * Cache pattern matches settingsService.ts (5-minute TTL, singleton).
 */

import { PrismaClient, SubscriptionTier } from '@prisma/client';
import { logger } from '../utils/logger';

const prisma = new PrismaClient();

/**
 * Cache interface
 */
interface TierCache {
  tiers: SubscriptionTier[];
  lastRefresh: number;
  refreshInterval: number; // milliseconds
}

/**
 * In-memory cache (singleton)
 */
const cache: TierCache = {
  tiers: [],
  lastRefresh: 0,
  refreshInterval: 5 * 60 * 1000, // 5 minutes
};

/**
 * Subscription Tier Service
 */
class TierService {
  /**
   * Check if cache needs refresh
   */
  private needsRefresh(): boolean {
    return Date.now() - cache.lastRefresh > cache.refreshInterval;
  }

  /**
   * Refresh cache from database
   */
  private async refreshCache(): Promise<void> {
    try {
      logger.debug('Refreshing tier cache from database');

      const tiers = await prisma.subscriptionTier.findMany({
        orderBy: { display_order: 'asc' },
      });

      cache.tiers = tiers;
      cache.lastRefresh = Date.now();

      logger.info('Tier cache refreshed', {
        tierCount: tiers.length,
        timestamp: new Date(cache.lastRefresh).toISOString(),
      });
    } catch (error) {
      logger.error('Failed to refresh tier cache', { error });
      throw new Error('Failed to refresh tier cache');
    }
  }

  /**
   * Ensure cache is populated and fresh
   */
  private async ensureCache(): Promise<void> {
    if (cache.tiers.length === 0 || this.needsRefresh()) {
      await this.refreshCache();
    }
  }

  /**
   * Get all tiers, ordered by display_order
   */
  async getAllTiers(): Promise<SubscriptionTier[]> {
    await this.ensureCache();
    return [...cache.tiers];
  }

  /**
   * Get only active tiers, ordered by display_order
   */
  async getActiveTiers(): Promise<SubscriptionTier[]> {
    await this.ensureCache();
    return cache.tiers.filter((t) => t.is_active);
  }

  /**
   * Get tiers filtered by plugin
   */
  async getTiersByPlugin(plugin: string): Promise<SubscriptionTier[]> {
    await this.ensureCache();
    return cache.tiers.filter((t) => t.plugin === plugin);
  }

  /**
   * Get active tiers filtered by plugin
   */
  async getActiveTiersByPlugin(plugin: string): Promise<SubscriptionTier[]> {
    await this.ensureCache();
    return cache.tiers.filter((t) => t.is_active && t.plugin === plugin);
  }

  /**
   * Get a tier by slug, optionally scoped to a plugin
   */
  async getTierBySlug(slug: string, plugin?: string): Promise<SubscriptionTier | undefined> {
    await this.ensureCache();
    if (plugin) {
      return cache.tiers.find((t) => t.slug === slug && t.plugin === plugin);
    }
    return cache.tiers.find((t) => t.slug === slug);
  }

  /**
   * Get a tier by ID
   */
  async getTierById(id: string): Promise<SubscriptionTier | undefined> {
    await this.ensureCache();
    return cache.tiers.find((t) => t.id === id);
  }

  /**
   * Get credit allocation for a tier slug.
   * Falls back to 100000 if tier not found.
   */
  async getCreditAllocation(slug: string, plugin: string): Promise<number> {
    const tier = await this.getTierBySlug(slug, plugin);
    return tier?.credit_allocation ?? 100000;
  }

  /**
   * Get rate limit for a tier slug.
   * Falls back to 60 if tier not found.
   */
  async getRateLimit(slug: string, plugin: string): Promise<number> {
    const tier = await this.getTierBySlug(slug, plugin);
    return tier?.rate_limit ?? 60;
  }

  /**
   * Get PayPal plan ID for a tier slug and billing cycle.
   * Returns the paypal_plan_monthly or paypal_plan_annual field
   * from the subscription_tiers table.
   */
  async getPayPalPlanId(
    slug: string,
    cycle: 'monthly' | 'annual',
    plugin: string
  ): Promise<string | null> {
    const tier = await this.getTierBySlug(slug, plugin);
    if (!tier) return null;
    return cycle === 'monthly'
      ? tier.paypal_plan_monthly
      : tier.paypal_plan_annual;
  }

  /**
   * Clear cache. Called after CRUD operations to ensure freshness.
   */
  clearCache(): void {
    cache.tiers = [];
    cache.lastRefresh = 0;
  }
}

// Export singleton instance
export const tierService = new TierService();
