/**
 * Feature Flag System
 * 
 * Lightweight feature flag utility that checks module status
 * and provides a clean API for conditionally rendering features.
 * 
 * Usage:
 *   const flags = await getFeatureFlags();
 *   if (flags.isEnabled('finance')) { ... }
 */

import { prisma } from '@/lib/db';
import { MODULE_REGISTRY } from './registry';

export interface FeatureFlags {
  enabledModules: Set<string>;
  isEnabled: (moduleId: string) => boolean;
  isAnyEnabled: (...moduleIds: string[]) => boolean;
  isAllEnabled: (...moduleIds: string[]) => boolean;
  getEnabledByCategory: (category: string) => string[];
}

/**
 * Load feature flags from database.
 * Caches for the duration of the request.
 */
let cachedFlags: FeatureFlags | null = null;
let cacheTimestamp = 0;
const CACHE_TTL = 10_000; // 10 seconds

export async function getFeatureFlags(): Promise<FeatureFlags> {
  const now = Date.now();
  if (cachedFlags && (now - cacheTimestamp) < CACHE_TTL) {
    return cachedFlags;
  }

  const configs = await prisma.moduleConfig.findMany({
    where: { isEnabled: true },
    select: { moduleId: true },
  });

  const enabledSet: Set<string> = new Set(configs.map((c: { moduleId: string }) => c.moduleId));

  // Always include core modules
  MODULE_REGISTRY.filter(m => m.isCore).forEach(m => enabledSet.add(m.moduleId));

  const flags: FeatureFlags = {
    enabledModules: enabledSet,
    isEnabled: (moduleId: string) => enabledSet.has(moduleId),
    isAnyEnabled: (...moduleIds: string[]) => moduleIds.some(id => enabledSet.has(id)),
    isAllEnabled: (...moduleIds: string[]) => moduleIds.every(id => enabledSet.has(id)),
    getEnabledByCategory: (category: string) => {
      return MODULE_REGISTRY
        .filter(m => m.category === category && enabledSet.has(m.moduleId))
        .map(m => m.moduleId);
    },
  };

  cachedFlags = flags;
  cacheTimestamp = now;
  return flags;
}

/**
 * Invalidate the cache (call after toggling modules)
 */
export function invalidateFeatureFlags() {
  cachedFlags = null;
  cacheTimestamp = 0;
}

/**
 * Initialize module configs in the database from the registry.
 * Called during seed or first boot.
 */
export async function syncModuleRegistry() {
  const registryIds = new Set(MODULE_REGISTRY.map(m => m.moduleId));

  // Upsert all modules currently in the registry
  for (const mod of MODULE_REGISTRY) {
    await prisma.moduleConfig.upsert({
      where: { moduleId: mod.moduleId },
      create: {
        moduleId: mod.moduleId,
        name: mod.name,
        description: mod.description,
        category: mod.category,
        icon: mod.icon,
        isEnabled: mod.defaultEnabled || mod.isCore,
        isCore: mod.isCore,
        sortOrder: mod.sortOrder,
        dependencies: mod.dependencies,
        metadata: {
          features: mod.features,
          tier: mod.tier,
          agentId: mod.agentId || null,
        },
        enabledAt: (mod.defaultEnabled || mod.isCore) ? new Date() : null,
      },
      update: {
        name: mod.name,
        description: mod.description,
        category: mod.category,
        icon: mod.icon,
        isCore: mod.isCore,
        sortOrder: mod.sortOrder,
        dependencies: mod.dependencies,
        metadata: {
          features: mod.features,
          tier: mod.tier,
          agentId: mod.agentId || null,
        },
      },
    });
  }

  // Remove DB records for modules no longer in the registry
  await prisma.moduleConfig.deleteMany({
    where: {
      moduleId: { notIn: Array.from(registryIds) },
    },
  });
}
