import { getSupabaseAdmin } from '@/lib/supabase/server';

interface FeatureFlag {
  key: string;
  name: string;
  flag_type: 'boolean' | 'percentage' | 'experiment';
  enabled: boolean;
  rollout_percentage: number;
  variants: Array<{ key: string; weight: number }>;
  target_user_types: string[];
  active: boolean;
}

/**
 * Check if a boolean feature flag is enabled for a user.
 * Returns false if flag doesn't exist or is inactive.
 */
export async function isFeatureEnabled(
  flagKey: string,
  userId?: string,
  userType?: string
): Promise<boolean> {
  try {
    const admin = getSupabaseAdmin();
    const { data: flag } = await admin
      .from('feature_flags')
      .select('*')
      .eq('key', flagKey)
      .eq('active', true)
      .single();

    if (!flag) return false;

    // Check user type targeting
    if (flag.target_user_types?.length > 0 && userType) {
      if (!flag.target_user_types.includes(userType)) return false;
    }

    if (flag.flag_type === 'boolean') {
      return flag.enabled;
    }

    if (flag.flag_type === 'percentage') {
      if (!userId) return false;
      // Deterministic hash based on userId + flagKey for consistent assignment
      const hash = simpleHash(`${userId}:${flagKey}`);
      return (hash % 100) < flag.rollout_percentage;
    }

    // For experiments, check if user has a variant assigned
    if (flag.flag_type === 'experiment') {
      return true; // Experiment is active, use getVariant() for which variant
    }

    return false;
  } catch {
    return false;
  }
}

/**
 * Get the experiment variant for a user.
 * Assigns a variant if not already assigned (sticky assignment).
 * Returns 'control' as default if anything fails.
 */
export async function getVariant(
  flagKey: string,
  userId: string,
  userType?: string
): Promise<string> {
  try {
    const admin = getSupabaseAdmin();

    // Check flag exists and is active
    const { data: flag } = await admin
      .from('feature_flags')
      .select('*')
      .eq('key', flagKey)
      .eq('active', true)
      .single();

    if (!flag || flag.flag_type !== 'experiment') return 'control';

    // Check user type targeting
    if (flag.target_user_types?.length > 0 && userType) {
      if (!flag.target_user_types.includes(userType)) return 'control';
    }

    // Check existing assignment
    const { data: existing } = await admin
      .from('experiment_assignments')
      .select('variant')
      .eq('flag_key', flagKey)
      .eq('user_id', userId)
      .single();

    if (existing) return existing.variant;

    // Assign variant based on weighted random
    const variants = flag.variants as Array<{ key: string; weight: number }>;
    if (!variants || variants.length === 0) return 'control';

    const totalWeight = variants.reduce((sum, v) => sum + v.weight, 0);
    const hash = simpleHash(`${userId}:${flagKey}`);
    let roll = hash % totalWeight;
    let selectedVariant = variants[0].key;

    for (const v of variants) {
      roll -= v.weight;
      if (roll < 0) {
        selectedVariant = v.key;
        break;
      }
    }

    // Save assignment (sticky)
    await admin
      .from('experiment_assignments')
      .upsert(
        { flag_key: flagKey, user_id: userId, variant: selectedVariant },
        { onConflict: 'flag_key,user_id', ignoreDuplicates: true }
      );

    return selectedVariant;
  } catch {
    return 'control';
  }
}

/**
 * Track an experiment event (exposure, conversion, etc).
 * Fire-and-forget — never blocks the caller.
 */
export async function trackEvent(
  flagKey: string,
  eventType: string,
  userId?: string,
  variant?: string,
  metadata?: Record<string, unknown>
): Promise<void> {
  try {
    const admin = getSupabaseAdmin();
    await admin.from('experiment_events').insert({
      flag_key: flagKey,
      user_id: userId || null,
      variant: variant || 'unknown',
      event_type: eventType,
      metadata: metadata || {},
    });
  } catch {
    // Silent fail — analytics should never break UX
  }
}

/**
 * Simple deterministic hash for consistent user bucketing.
 * Not crypto-grade — just needs to be evenly distributed.
 */
function simpleHash(str: string): number {
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash = hash & hash; // Convert to 32bit integer
  }
  return Math.abs(hash);
}
