import { Guild, EmbedBuilder, TextChannel, Colors } from 'discord.js';
import { prisma } from '../database';
import { env } from '../config/env';

export type AuditSeverity = 'INFO' | 'WARN' | 'ERROR';
export type AuditCategory = 'SYSTEM' | 'BOOT' | 'VOICE' | 'PERMISSION' | 'MIMIC';

export interface AuditLogPayload {
  category: AuditCategory;
  severity: AuditSeverity;
  title: string;
  description: string;
  fields?: { name: string; value: string; inline?: boolean }[];
  errorCode?: string;
}

const SEVERITY_INFO: Record<AuditSeverity, { color: number; icon: string }> = {
  INFO: { color: 0x5865f2, icon: '🔵' },
  WARN: { color: 0xfee75c, icon: '🟡' },
  ERROR: { color: 0xed4245, icon: '🔴' },
};

export class AuditLogService {
  /**
   * 감사 채널에 로그 메시지를 발송합니다.
   * 지정된 카테고리가 채널의 필터(disabledCategories)에 포함되어 있거나
   * 채널이 설정되지 않은 경우 조용히 무시(Silent Fail)합니다.
   */
  async log(guild: Guild, payload: AuditLogPayload): Promise<void> {
    try {
      const config = await this.getChannel(guild.id);
      if (!config) return;

      // 카테고리 필터링 적용
      if (config.disabledCategories.includes(payload.category)) {
        return;
      }

      const channel = await guild.channels.fetch(config.channelId).catch(() => null);
      if (!channel || !channel.isTextBased() || !(channel instanceof TextChannel)) {
        return;
      }

      const { color, icon } = SEVERITY_INFO[payload.severity];
      
      const embed = new EmbedBuilder()
        .setTitle(`[Kord Audit Log - ${payload.category}]`)
        .setDescription(`**${payload.title}**\n\n${payload.description}`)
        .setColor(color)
        .setTimestamp()
        .setFooter({ text: `${icon} ${payload.severity}  ·  Kord System [${env.INSTANCE_ID}]` });

      if (payload.fields && payload.fields.length > 0) {
        embed.addFields(payload.fields);
      }

      if (payload.errorCode) {
        embed.addFields({ name: 'Error Code', value: `\`${payload.errorCode}\``, inline: true });
      }

      await channel.send({ embeds: [embed] });
    } catch (error) {
      // 전송 실패 시 메인 로직에 영향을 주지 않도록 격리 후 콘솔에만 기록
      console.error(`[AuditLogService] Error logging to guild ${guild.id}:`, error);
    }
  }

  /**
   * 서버의 감사 채널을 설정(Upsert)합니다.
   */
  async setChannel(guildId: string, channelId: string): Promise<void> {
    await prisma.auditChannel.upsert({
      where: { guildId },
      create: { 
        guildId, 
        channelId,
        // 기본적으로 부팅 로그(BOOT)와 시스템 로그(SYSTEM)는 받지 않도록 설정
        disabledCategories: ['BOOT', 'SYSTEM'] 
      },
      update: { channelId },
    });
  }

  /**
   * 서버의 감사 채널 설정을 해제합니다.
   */
  async clearChannel(guildId: string): Promise<void> {
    await prisma.auditChannel.deleteMany({
      where: { guildId }
    });
  }

  /**
   * 현재 감사 채널 설정 정보를 가져옵니다.
   */
  async getChannel(guildId: string) {
    return prisma.auditChannel.findUnique({
      where: { guildId }
    });
  }

  /**
   * 특정 카테고리의 수신 여부를 토글하거나 지정합니다.
   * @param enable true면 수신(disabledCategories에서 제거), false면 차단(추가)
   * @returns 조작된 결과 category 목록
   */
  async setFilter(guildId: string, category: AuditCategory, enable: boolean): Promise<string[]> {
    const config = await this.getChannel(guildId);
    if (!config) {
      throw new Error('Audit channel not configured');
    }

    let updatedCategories = [...config.disabledCategories];

    if (enable) {
      // 수신 설정 (비활성화 목록에서 제거)
      updatedCategories = updatedCategories.filter(c => c !== category);
    } else {
      // 차단 설정 (비활성화 목록에 추가)
      if (!updatedCategories.includes(category)) {
        updatedCategories.push(category);
      }
    }

    const updated = await prisma.auditChannel.update({
      where: { guildId },
      data: { disabledCategories: updatedCategories }
    });

    return updated.disabledCategories;
  }
}

export const auditLogService = new AuditLogService();
