/**
 * Feature Flags Service
 * Permite activar/desactivar funcionalidades por tenant, usuario o porcentaje
 */

export interface FeatureFlag {
  enabled: boolean;
  enabledTenants?: string[];
  disabledTenants?: string[];
  enabledUsers?: string[];
  disabledUsers?: string[];
  rolloutPercentage?: number;
  description?: string;
  metadata?: Record<string, any>;
}

export interface FeatureFlagContext {
  tenantId?: string;
  userId?: string;
  profileCode?: string;
  platform?: string;
}

export class FeatureFlagService {
  private flags: Map<string, FeatureFlag> = new Map();
  private static instance: FeatureFlagService;

  private constructor() {
    this.loadDefaultFlags();
  }

  static getInstance(): FeatureFlagService {
    if (!FeatureFlagService.instance) {
      FeatureFlagService.instance = new FeatureFlagService();
    }
    return FeatureFlagService.instance;
  }

  private loadDefaultFlags(): void {
    // Flags por defecto
    this.flags.set('mobile_app_enabled', {
      enabled: true,
      description: 'Habilita el acceso a la aplicacion movil',
    });

    this.flags.set('biometric_auth', {
      enabled: true,
      description: 'Habilita autenticacion biometrica',
    });

    this.flags.set('offline_mode', {
      enabled: true,
      description: 'Habilita modo offline en la app movil',
    });

    this.flags.set('payment_terminals', {
      enabled: true,
      description: 'Habilita integracion con terminales de pago',
    });

    this.flags.set('geofencing', {
      enabled: true,
      description: 'Habilita validacion de geofencing',
    });

    this.flags.set('push_notifications', {
      enabled: true,
      description: 'Habilita notificaciones push',
    });

    this.flags.set('usage_billing', {
      enabled: true,
      description: 'Habilita facturacion por uso',
    });
  }

  async isEnabled(flagName: string, context?: FeatureFlagContext): Promise<boolean> {
    const flag = this.flags.get(flagName);

    if (!flag) {
      return false;
    }

    // Global flag deshabilitado
    if (!flag.enabled) {
      return false;
    }

    // Tenant especificamente deshabilitado
    if (context?.tenantId && flag.disabledTenants?.includes(context.tenantId)) {
      return false;
    }

    // Tenant especificamente habilitado (lista blanca)
    if (context?.tenantId && flag.enabledTenants?.length) {
      if (!flag.enabledTenants.includes(context.tenantId)) {
        return false;
      }
    }

    // Usuario especificamente deshabilitado
    if (context?.userId && flag.disabledUsers?.includes(context.userId)) {
      return false;
    }

    // Usuario especificamente habilitado (para beta testing)
    if (context?.userId && flag.enabledUsers?.length) {
      if (!flag.enabledUsers.includes(context.userId)) {
        // Si hay lista de usuarios habilitados y este no esta, verificar rollout
        if (flag.rolloutPercentage === undefined) {
          return false;
        }
      } else {
        return true;
      }
    }

    // Percentage rollout
    if (flag.rolloutPercentage !== undefined && flag.rolloutPercentage < 100) {
      const identifier = context?.userId || context?.tenantId || flagName;
      const hash = this.hashString(`${flagName}-${identifier}`);
      return (hash % 100) < flag.rolloutPercentage;
    }

    return true;
  }

  async setFlag(flagName: string, config: FeatureFlag): Promise<void> {
    this.flags.set(flagName, config);
    // Aqui se podria persistir en BD si es necesario
  }

  async getFlag(flagName: string): Promise<FeatureFlag | undefined> {
    return this.flags.get(flagName);
  }

  async getAllFlags(): Promise<Map<string, FeatureFlag>> {
    return new Map(this.flags);
  }

  async updateFlag(flagName: string, updates: Partial<FeatureFlag>): Promise<void> {
    const existing = this.flags.get(flagName);
    if (existing) {
      this.flags.set(flagName, { ...existing, ...updates });
    }
  }

  async deleteFlag(flagName: string): Promise<void> {
    this.flags.delete(flagName);
  }

  async enableForTenant(flagName: string, tenantId: string): Promise<void> {
    const flag = this.flags.get(flagName);
    if (flag) {
      const enabledTenants = flag.enabledTenants || [];
      if (!enabledTenants.includes(tenantId)) {
        enabledTenants.push(tenantId);
      }
      flag.enabledTenants = enabledTenants;

      // Remover de deshabilitados si estaba
      if (flag.disabledTenants) {
        flag.disabledTenants = flag.disabledTenants.filter((t) => t !== tenantId);
      }
    }
  }

  async disableForTenant(flagName: string, tenantId: string): Promise<void> {
    const flag = this.flags.get(flagName);
    if (flag) {
      const disabledTenants = flag.disabledTenants || [];
      if (!disabledTenants.includes(tenantId)) {
        disabledTenants.push(tenantId);
      }
      flag.disabledTenants = disabledTenants;

      // Remover de habilitados si estaba
      if (flag.enabledTenants) {
        flag.enabledTenants = flag.enabledTenants.filter((t) => t !== tenantId);
      }
    }
  }

  private hashString(str: string): number {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      hash = ((hash << 5) - hash) + str.charCodeAt(i);
      hash |= 0; // Convert to 32bit integer
    }
    return Math.abs(hash);
  }
}

// Export singleton instance
export const featureFlagService = FeatureFlagService.getInstance();
