import { DASHBOARD_MODULES, type DashboardModuleId, type ModuleStatus } from '@nexumi/shared';
import { prisma } from './prisma';
import { redis } from './redis';

/**
 * Modules that have no dedicated "enabled" column on any Prisma model.
 * Their dashboard toggle state is tracked in a Redis hash instead.
 */
const REDIS_ONLY_MODULES = new Set<DashboardModuleId>([
  'giveaways',
  'tags',
  'selfroles',
  'feeds',
  'scheduler',
  'guildbackup',
  'messages'
]);

function redisModulesKey(guildId: string): string {
  return `dashboard:modules:${guildId}`;
}

function funConfigKey(guildId: string): string {
  return `fun:config:${guildId}`;
}

interface FunConfigLike {
  enabled: boolean;
  mediaEnabled: boolean;
}

async function getRedisModuleFlags(guildId: string): Promise<Partial<Record<DashboardModuleId, boolean>>> {
  const raw = await redis.hgetall(redisModulesKey(guildId));
  const result: Partial<Record<DashboardModuleId, boolean>> = {};
  for (const [moduleId, value] of Object.entries(raw)) {
    result[moduleId as DashboardModuleId] = value === 'true';
  }
  return result;
}

async function setRedisModuleFlag(guildId: string, moduleId: DashboardModuleId, enabled: boolean): Promise<void> {
  await redis.hset(redisModulesKey(guildId), moduleId, enabled ? 'true' : 'false');
}

async function getFunConfig(guildId: string): Promise<FunConfigLike> {
  const raw = await redis.get(funConfigKey(guildId));
  if (!raw) {
    return { enabled: true, mediaEnabled: true };
  }
  try {
    const parsed = JSON.parse(raw) as { enabled?: boolean; mediaEnabled?: boolean };
    return { enabled: parsed.enabled ?? true, mediaEnabled: parsed.mediaEnabled ?? true };
  } catch {
    return { enabled: true, mediaEnabled: true };
  }
}

async function setFunConfigEnabled(guildId: string, enabled: boolean): Promise<void> {
  const current = await getFunConfig(guildId);
  await redis.set(funConfigKey(guildId), JSON.stringify({ ...current, enabled }));
}

/**
 * Aggregates the enabled/disabled status of every dashboard module for a
 * guild, reading from each module's Prisma config table (when it has an
 * `enabled` column), the Fun module's Redis config, or the generic
 * `dashboard:modules:{guildId}` Redis hash for modules without any
 * dedicated storage yet.
 */
export async function getModuleStatuses(guildId: string): Promise<ModuleStatus[]> {
  const [
    guildSettings,
    autoModConfig,
    loggingConfig,
    welcomeConfig,
    verificationConfig,
    levelingConfig,
    economyConfig,
    funConfig,
    ticketConfig,
    starboardConfig,
    suggestionConfig,
    birthdayConfig,
    tempVoiceConfig,
    statsConfig,
    redisFlags
  ] = await Promise.all([
    prisma.guildSettings.findUnique({ where: { guildId } }),
    prisma.autoModConfig.findUnique({ where: { guildId } }),
    prisma.loggingConfig.findUnique({ where: { guildId } }),
    prisma.welcomeConfig.findUnique({ where: { guildId } }),
    prisma.verificationConfig.findUnique({ where: { guildId } }),
    prisma.levelingConfig.findUnique({ where: { guildId } }),
    prisma.economyConfig.findUnique({ where: { guildId } }),
    getFunConfig(guildId),
    prisma.ticketConfig.findUnique({ where: { guildId } }),
    prisma.starboardConfig.findUnique({ where: { guildId } }),
    prisma.suggestionConfig.findUnique({ where: { guildId } }),
    prisma.birthdayConfig.findUnique({ where: { guildId } }),
    prisma.tempVoiceConfig.findUnique({ where: { guildId } }),
    prisma.statsConfig.findUnique({ where: { guildId } }),
    getRedisModuleFlags(guildId)
  ]);

  const enabledById: Record<DashboardModuleId, boolean> = {
    moderation: guildSettings?.moderationEnabled ?? true,
    automod: autoModConfig?.enabled ?? true,
    logging: loggingConfig?.enabled ?? true,
    welcome: Boolean(welcomeConfig?.welcomeEnabled || welcomeConfig?.leaveEnabled),
    verification: verificationConfig?.enabled ?? false,
    leveling: levelingConfig?.enabled ?? true,
    economy: economyConfig?.enabled ?? true,
    fun: funConfig.enabled,
    giveaways: redisFlags.giveaways ?? true,
    tickets: ticketConfig?.enabled ?? true,
    selfroles: redisFlags.selfroles ?? true,
    tags: redisFlags.tags ?? true,
    starboard: starboardConfig?.enabled ?? false,
    suggestions: suggestionConfig?.enabled ?? true,
    birthdays: birthdayConfig?.enabled ?? true,
    tempvoice: tempVoiceConfig?.enabled ?? false,
    stats: statsConfig?.enabled ?? false,
    feeds: redisFlags.feeds ?? true,
    scheduler: redisFlags.scheduler ?? true,
    guildbackup: redisFlags.guildbackup ?? true,
    messages: redisFlags.messages ?? true
  };

  return DASHBOARD_MODULES.map((module) => ({
    id: module.id,
    group: module.group,
    href: module.href,
    enabled: enabledById[module.id]
  }));
}

async function setModuleEnabled(guildId: string, moduleId: DashboardModuleId, enabled: boolean): Promise<void> {
  if (REDIS_ONLY_MODULES.has(moduleId)) {
    await setRedisModuleFlag(guildId, moduleId, enabled);
    return;
  }

  switch (moduleId) {
    case 'moderation':
      await prisma.guildSettings.upsert({
        where: { guildId },
        update: { moderationEnabled: enabled },
        create: { guildId, moderationEnabled: enabled }
      });
      return;
    case 'automod':
      await prisma.autoModConfig.upsert({
        where: { guildId },
        update: { enabled },
        create: { guildId, enabled }
      });
      return;
    case 'logging':
      await prisma.loggingConfig.upsert({
        where: { guildId },
        update: { enabled },
        create: { guildId, enabled }
      });
      return;
    case 'welcome':
      await prisma.welcomeConfig.upsert({
        where: { guildId },
        update: { welcomeEnabled: enabled, leaveEnabled: enabled },
        create: { guildId, welcomeEnabled: enabled, leaveEnabled: enabled }
      });
      return;
    case 'verification':
      await prisma.verificationConfig.upsert({
        where: { guildId },
        update: { enabled },
        create: { guildId, enabled }
      });
      return;
    case 'leveling':
      await prisma.levelingConfig.upsert({
        where: { guildId },
        update: { enabled },
        create: { guildId, enabled }
      });
      return;
    case 'economy':
      await prisma.economyConfig.upsert({
        where: { guildId },
        update: { enabled },
        create: { guildId, enabled }
      });
      return;
    case 'fun':
      await setFunConfigEnabled(guildId, enabled);
      return;
    case 'tickets':
      await prisma.ticketConfig.upsert({
        where: { guildId },
        update: { enabled },
        create: { guildId, enabled }
      });
      return;
    case 'starboard':
      await prisma.starboardConfig.upsert({
        where: { guildId },
        update: { enabled },
        create: { guildId, enabled }
      });
      return;
    case 'suggestions':
      await prisma.suggestionConfig.upsert({
        where: { guildId },
        update: { enabled },
        create: { guildId, enabled }
      });
      return;
    case 'birthdays':
      await prisma.birthdayConfig.upsert({
        where: { guildId },
        update: { enabled },
        create: { guildId, enabled }
      });
      return;
    case 'tempvoice':
      await prisma.tempVoiceConfig.upsert({
        where: { guildId },
        update: { enabled },
        create: { guildId, enabled }
      });
      return;
    case 'stats':
      await prisma.statsConfig.upsert({
        where: { guildId },
        update: { enabled },
        create: { guildId, enabled }
      });
      return;
    default:
      throw new Error(`Unknown or unsupported module: ${String(moduleId)}`);
  }
}

export async function updateModuleStatuses(
  guildId: string,
  updates: Partial<Record<DashboardModuleId, boolean>>
): Promise<ModuleStatus[]> {
  await prisma.guild.upsert({ where: { id: guildId }, update: {}, create: { id: guildId } });

  for (const [moduleId, enabled] of Object.entries(updates)) {
    if (enabled === undefined) continue;
    await setModuleEnabled(guildId, moduleId as DashboardModuleId, enabled);
  }

  return getModuleStatuses(guildId);
}
