import { createHash } from "node:crypto";

export interface FlagRow {
  key: string;
  enabled: boolean;
  rolloutPercent: number;
}

/** Kända flaggor – centralt register så att döda flaggor syns i kodgranskning. */
export const KNOWN_FLAGS = {
  COMMUNITY_PUBLISHING: "community_publishing",
  WEEK_PLAN_AI: "week_plan_ai",
  PLATE_PHOTO_ANALYSIS: "plate_photo_analysis",
  RECEIPT_SCANNING: "receipt_scanning",
  PANTRY_FORECAST: "pantry_forecast",
  HEALTH_INTEGRATION: "health_integration",
  WEATHER_CONTEXT: "weather_context",
  CREATOR_RANKINGS: "creator_rankings",
  FOOD_MEMORIES: "food_memories",
  VOICE_INPUT: "voice_input",
  AI_RERANK: "ai_rerank",
} as const;
export type KnownFlagKey = (typeof KNOWN_FLAGS)[keyof typeof KNOWN_FLAGS];

export interface FeatureFlagServiceOptions {
  /** Laddar alla flaggor från databasen (injiceras för att undvika DB-beroende här). */
  loadAll: () => Promise<FlagRow[]>;
  /** Cache-TTL i ms (default 30 s). */
  ttlMs?: number;
  /** Miljövariabler för override: APP_FLAG_<KEY>=true/false. */
  env?: Record<string, string | undefined>;
}

/**
 * Flaggtjänst med tre lager:
 * 1. env-override (drift/incident: stäng av utan deploy),
 * 2. databasvärde med rollout-procent (gradvis utrullning per användare),
 * 3. default false (fail closed för ny funktionalitet).
 */
export class FeatureFlagService {
  private cache = new Map<string, FlagRow>();
  private cachedAt = 0;
  private readonly ttlMs: number;
  private readonly env: Record<string, string | undefined>;
  private readonly loadAll: () => Promise<FlagRow[]>;

  constructor(options: FeatureFlagServiceOptions) {
    this.loadAll = options.loadAll;
    this.ttlMs = options.ttlMs ?? 30_000;
    this.env = options.env ?? process.env;
  }

  async isEnabled(key: string, userId?: string): Promise<boolean> {
    const envOverride = this.env[`APP_FLAG_${key.toUpperCase()}`];
    if (envOverride === "true") return true;
    if (envOverride === "false") return false;

    await this.refreshIfStale();
    const row = this.cache.get(key);
    if (!row || !row.enabled) return false;
    if (row.rolloutPercent >= 100) return true;
    if (row.rolloutPercent <= 0) return false;
    if (!userId) return false;
    return bucketFor(key, userId) < row.rolloutPercent;
  }

  async all(): Promise<FlagRow[]> {
    await this.refreshIfStale();
    return [...this.cache.values()];
  }

  invalidate(): void {
    this.cachedAt = 0;
  }

  private async refreshIfStale(): Promise<void> {
    if (Date.now() - this.cachedAt < this.ttlMs) return;
    try {
      const rows = await this.loadAll();
      this.cache = new Map(rows.map((r) => [r.key, r]));
      this.cachedAt = Date.now();
    } catch {
      // Behåll gammal cache vid DB-fel – flaggor får aldrig fälla en request.
      this.cachedAt = Date.now() - this.ttlMs + 5_000;
    }
  }
}

/** Stabil hash → 0–99: samma användare hamnar alltid i samma bucket per flagga. */
export function bucketFor(flagKey: string, userId: string): number {
  const hash = createHash("sha256").update(`${flagKey}:${userId}`).digest();
  return ((hash[0]! << 8) | hash[1]!) % 100;
}
