import type { DashboardModuleId } from '@nexumi/shared';
import type { PrismaClient } from '@prisma/client';
import type { Redis } from 'ioredis';
import { createHash } from 'node:crypto';

const REDIS_ONLY_MODULES = new Set<DashboardModuleId>([
  'giveaways',
  'tags',
  'selfroles',
  'feeds',
  'scheduler',
  'guildbackup',
  'messages'
]);

/** Slash command name → dashboard module. Core/GDPR/utility (except gated) omit. */
const COMMAND_MODULE_MAP: Record<string, DashboardModuleId> = {
  ban: 'moderation',
  unban: 'moderation',
  kick: 'moderation',
  timeout: 'moderation',
  untimeout: 'moderation',
  warn: 'moderation',
  purge: 'moderation',
  slowmode: 'moderation',
  lock: 'moderation',
  unlock: 'moderation',
  nick: 'moderation',
  case: 'moderation',
  modnote: 'moderation',
  automod: 'automod',
  welcome: 'welcome',
  verify: 'verification',
  rank: 'leveling',
  leaderboard: 'leveling',
  xp: 'leveling',
  balance: 'economy',
  daily: 'economy',
  weekly: 'economy',
  work: 'economy',
  pay: 'economy',
  gamble: 'economy',
  slots: 'economy',
  blackjack: 'economy',
  coinflip: 'economy',
  shop: 'economy',
  inventory: 'economy',
  eco: 'economy',
  '8ball': 'fun',
  dice: 'fun',
  rps: 'fun',
  choose: 'fun',
  trivia: 'fun',
  tictactoe: 'fun',
  connect4: 'fun',
  hangman: 'fun',
  meme: 'fun',
  cat: 'fun',
  dog: 'fun',
  giveaway: 'giveaways',
  ticket: 'tickets',
  selfroles: 'selfroles',
  tag: 'tags',
  starboard: 'starboard',
  suggest: 'suggestions',
  suggestion: 'suggestions',
  birthday: 'birthdays',
  voice: 'tempvoice',
  invites: 'stats',
  stats: 'stats',
  feeds: 'feeds',
  schedule: 'scheduler',
  announce: 'scheduler',
  backup: 'guildbackup',
  embed: 'messages'
};

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

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

function hashPercent(input: string): number {
  const digest = createHash('sha256').update(input).digest();
  return digest.readUInt32BE(0) % 100;
}

export function moduleForCommand(commandName: string): DashboardModuleId | null {
  return COMMAND_MODULE_MAP[commandName] ?? null;
}

/** Component customId → dashboard module (null = no module gate). */
export function moduleForComponent(customId: string): DashboardModuleId | null {
  if (customId.startsWith('mod:confirm:') || customId.startsWith('mod:cancel:')) {
    return 'moderation';
  }
  if (customId.startsWith('verify:')) {
    return 'verification';
  }
  if (customId.startsWith('eco:bj:')) {
    return 'economy';
  }
  if (customId.startsWith('fun:')) {
    return 'fun';
  }
  if (customId.startsWith('gw:')) {
    return 'giveaways';
  }
  if (customId.startsWith('ticket:') || customId === 'ticket:select') {
    return 'tickets';
  }
  if (customId.startsWith('sr:')) {
    return 'selfroles';
  }
  if (customId.startsWith('sug:')) {
    return 'suggestions';
  }
  if (customId.startsWith('tv:')) {
    return 'tempvoice';
  }
  if (customId.startsWith('gbackup:')) {
    return 'guildbackup';
  }
  return null;
}

export async function isFeatureFlagEnabled(
  prisma: PrismaClient,
  key: string,
  guildId: string | null
): Promise<boolean> {
  const flag = await prisma.featureFlag.findUnique({ where: { key } });
  if (!flag) {
    return true;
  }
  if (guildId && flag.whitelistGuildIds.includes(guildId)) {
    return true;
  }
  if (!flag.enabled) {
    return false;
  }
  if (flag.rolloutPercent >= 100) {
    return true;
  }
  if (flag.rolloutPercent <= 0 || !guildId) {
    return false;
  }
  return hashPercent(`${flag.key}:${guildId}`) < flag.rolloutPercent;
}

async function isRedisModuleEnabled(
  redis: Redis,
  guildId: string,
  moduleId: DashboardModuleId
): Promise<boolean> {
  const value = await redis.hget(redisModulesKey(guildId), moduleId);
  if (value === null) {
    return true;
  }
  return value === 'true';
}

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

export async function isModuleEnabled(
  prisma: PrismaClient,
  redis: Redis,
  guildId: string,
  moduleId: DashboardModuleId
): Promise<boolean> {
  const flagOk = await isFeatureFlagEnabled(prisma, moduleId, guildId);
  if (!flagOk) {
    return false;
  }

  if (REDIS_ONLY_MODULES.has(moduleId)) {
    return isRedisModuleEnabled(redis, guildId, moduleId);
  }

  switch (moduleId) {
    case 'moderation': {
      const settings = await prisma.guildSettings.findUnique({
        where: { guildId },
        select: { moderationEnabled: true }
      });
      return settings?.moderationEnabled ?? true;
    }
    case 'automod': {
      const config = await prisma.autoModConfig.findUnique({
        where: { guildId },
        select: { enabled: true }
      });
      return config?.enabled ?? true;
    }
    case 'logging': {
      const config = await prisma.loggingConfig.findUnique({
        where: { guildId },
        select: { enabled: true }
      });
      return config?.enabled ?? true;
    }
    case 'welcome': {
      const config = await prisma.welcomeConfig.findUnique({
        where: { guildId },
        select: { welcomeEnabled: true, leaveEnabled: true }
      });
      if (!config) {
        return true;
      }
      return Boolean(config.welcomeEnabled || config.leaveEnabled);
    }
    case 'verification': {
      const config = await prisma.verificationConfig.findUnique({
        where: { guildId },
        select: { enabled: true }
      });
      return config?.enabled ?? false;
    }
    case 'leveling': {
      const config = await prisma.levelingConfig.findUnique({
        where: { guildId },
        select: { enabled: true }
      });
      return config?.enabled ?? true;
    }
    case 'economy': {
      const config = await prisma.economyConfig.findUnique({
        where: { guildId },
        select: { enabled: true }
      });
      return config?.enabled ?? true;
    }
    case 'fun':
      return isFunEnabled(redis, guildId);
    case 'tickets': {
      const config = await prisma.ticketConfig.findUnique({
        where: { guildId },
        select: { enabled: true }
      });
      return config?.enabled ?? true;
    }
    case 'starboard': {
      const config = await prisma.starboardConfig.findUnique({
        where: { guildId },
        select: { enabled: true }
      });
      return config?.enabled ?? false;
    }
    case 'suggestions': {
      const config = await prisma.suggestionConfig.findUnique({
        where: { guildId },
        select: { enabled: true }
      });
      return config?.enabled ?? true;
    }
    case 'birthdays': {
      const config = await prisma.birthdayConfig.findUnique({
        where: { guildId },
        select: { enabled: true }
      });
      return config?.enabled ?? true;
    }
    case 'tempvoice': {
      const config = await prisma.tempVoiceConfig.findUnique({
        where: { guildId },
        select: { enabled: true }
      });
      return config?.enabled ?? false;
    }
    case 'stats': {
      const config = await prisma.statsConfig.findUnique({
        where: { guildId },
        select: { enabled: true }
      });
      return config?.enabled ?? false;
    }
    default:
      return true;
  }
}

export async function isUserBlacklisted(prisma: PrismaClient, userId: string): Promise<boolean> {
  const row = await prisma.globalUserBlacklist.findUnique({
    where: { userId },
    select: { id: true }
  });
  return Boolean(row);
}

export async function isGuildBlacklisted(prisma: PrismaClient, guildId: string): Promise<boolean> {
  const row = await prisma.guildBlacklist.findUnique({
    where: { guildId },
    select: { id: true }
  });
  return Boolean(row);
}
