import { Collection, Message, PermissionFlagsBits } from 'discord.js';
import { logger } from '../utils/logger';

export interface AutomodConfig {
  spamThreshold?: number;
  windowMs?: number;
  linkWhitelist?: string[];
  spamTimeoutMinutes?: number;
  deleteLinks?: boolean;
  badWordFilter?: boolean;
  capsFilter?: boolean;
  customBadwords?: string[];
  whitelistRoles?: string[];
  logChannelId?: string;
  loggingConfig?: {
    logChannelId?: string;
    categories?: {
      automodActions?: boolean;
    };
  };
}

export class AutoModService {
  private spamTracker = new Collection<string, { count: number; lastMessage: number }>();
  private spamThreshold = 5;
  private windowMs = 7000;
  private defaults: AutomodConfig = {
    spamThreshold: 5,
    windowMs: 7000,
    linkWhitelist: [],
    spamTimeoutMinutes: 10,
    deleteLinks: true,
    badWordFilter: true,
    capsFilter: false,
    customBadwords: [],
    whitelistRoles: []
  };
  private defaultBadwords = ['badword', 'spamword'];

  constructor(private linkFilterEnabled = true, private antiSpamEnabled = true) {}

  public async checkMessage(message: Message, cfg?: AutomodConfig) {
    if (message.author.bot) return;
    const config = { ...this.defaults, ...(cfg ?? {}) };
    const member = message.member;

    if (member?.roles.cache.size && Array.isArray(config.whitelistRoles) && config.whitelistRoles.length) {
      const allowed = member.roles.cache.some((r) => config.whitelistRoles!.includes(r.id));
      if (allowed) return;
    }

    if (this.linkFilterEnabled && config.deleteLinks !== false && this.containsLink(message.content, config.linkWhitelist)) {
      if (message.member?.permissions.has(PermissionFlagsBits.ManageGuild)) return false;
      message.delete().catch(() => undefined);
      message.channel
        .send({ content: `${message.author}, Links sind hier nicht erlaubt.` })
        .then((m) => setTimeout(() => m.delete().catch(() => undefined), 5000));
      logger.info(`Deleted link from ${message.author.tag}`);
      await this.logAutomodAction(message, config, 'link_filter');
      return true;
    }

    if (config.badWordFilter !== false && this.containsBadword(message.content, config.customBadwords)) {
      if (message.member?.permissions.has(PermissionFlagsBits.ManageGuild)) return false;
      message.delete().catch(() => undefined);
      message.channel
        .send({ content: `${message.author}, bitte auf deine Wortwahl achten.` })
        .then((m) => setTimeout(() => m.delete().catch(() => undefined), 5000));
      await this.logAutomodAction(message, config, 'badword', message.content);
      return true;
    }

    if (config.capsFilter) {
      const letters = message.content.replace(/[^a-zA-Z]/g, '');
      const upper = letters.replace(/[^A-Z]/g, '');
      if (letters.length >= 10 && upper.length / letters.length > 0.7) {
        message.delete().catch(() => undefined);
        message.channel
          .send({ content: `${message.author}, bitte weniger Capslock nutzen.` })
          .then((m) => setTimeout(() => m.delete().catch(() => undefined), 5000));
        await this.logAutomodAction(message, config, 'capslock', message.content);
        return true;
      }
    }

    if (this.antiSpamEnabled) {
      const now = Date.now();
      const tracker = this.spamTracker.get(message.author.id) ?? { count: 0, lastMessage: now };
      if (now - tracker.lastMessage < (config.windowMs ?? this.windowMs)) {
        tracker.count += 1;
      } else {
        tracker.count = 1;
      }
      tracker.lastMessage = now;
      this.spamTracker.set(message.author.id, tracker);

      const threshold = config.spamThreshold ?? this.spamThreshold;
      if (tracker.count >= threshold) {
        const timeoutMs = (config.spamTimeoutMinutes ?? this.defaults.spamTimeoutMinutes!) * 60 * 1000;
        message.member?.timeout(timeoutMs, 'Automod: Spam').catch(() => undefined);
        message.channel
          .send({ content: `${message.author}, bitte langsamer schreiben (Spam-Schutz).` })
          .then((m) => setTimeout(() => m.delete().catch(() => undefined), 5000));
        logger.warn(`Timed out ${message.author.tag} for spam`);
        this.spamTracker.delete(message.author.id);
        await this.logAutomodAction(message, config, 'spam', `Count ${tracker.count}`);
        return true;
      }
    }
    return false;
  }

  private containsBadword(content: string, custom: string[] = []) {
    const combined = [...this.defaultBadwords, ...(custom || [])].filter(Boolean).map((w) => w.toLowerCase());
    if (!combined.length) return false;
    const lower = content.toLowerCase();
    return combined.some((w) => lower.includes(w));
  }

  private containsLink(content: string, whitelist: string[] = []) {
    const normalized = whitelist.map((w) => w.toLowerCase()).filter(Boolean);
    const match = /(https?:\/\/[^\s]+|discord\.gg\/[^\s]+|www\.[^\s]+)/i.exec(content);
    if (!match) return false;
    const url = match[0].toLowerCase();
    return !normalized.some((w) => url.includes(w));
  }

  private async logAutomodAction(message: Message, config: AutomodConfig, action: string, details?: string) {
    try {
      const guild = message.guild;
      if (!guild) return;
      const loggingCfg = config.loggingConfig || {};
      const flags = loggingCfg.categories || {};
      if (flags.automodActions === false) return;
      const channelId = loggingCfg.logChannelId || config.logChannelId;
      if (!channelId) return;
      const channel = await guild.channels.fetch(channelId).catch(() => null);
      if (!channel || !channel.isTextBased()) return;
      const content = `[Automod] ${action} by ${message.author.tag}${details ? ` | ${details}` : ''}`;
      await channel.send({ content });
    } catch (err) {
      logger.error('Automod log failed', err);
    }
  }
}
