import { Collection, Message } from 'discord.js';
import { logger } from '../utils/logger';
import { settingsStore } from '../config/state';
import { prisma } from '../database';

interface LevelData {
  xp: number;
  level: number;
}

export class LevelService {
  private cache = new Collection<string, LevelData>();
  private cooldown = new Set<string>();

  private key(guildId: string, userId: string) {
    return `${guildId}:${userId}`;
  }

  async handleMessage(message: Message) {
    if (!message.guild || message.author.bot) return;
    const guildConfig = settingsStore.get(message.guild.id);
    if (guildConfig?.levelingEnabled !== true) return;

    const key = this.key(message.guild.id, message.author.id);
    if (this.cooldown.has(key)) return;
    this.cooldown.add(key);
    setTimeout(() => this.cooldown.delete(key), 60_000);

    const entry = await this.loadLevel(message.guild.id, message.author.id);
    const xpGain = 10;
    entry.xp += xpGain;
    const nextLevel = Math.floor(0.2 * Math.sqrt(entry.xp));
    if (nextLevel > entry.level) {
      entry.level = nextLevel;
      message.channel.send({ content: `${message.author} hat Level ${entry.level} erreicht!` }).catch(() => undefined);
      logger.info(`Level up: ${message.author.tag} -> ${entry.level}`);
    }
    this.cache.set(key, entry);
    await prisma.level.upsert({
      where: { userId_guildId: { userId: message.author.id, guildId: message.guild.id } },
      update: { xp: entry.xp, level: entry.level },
      create: { userId: message.author.id, guildId: message.guild.id, xp: entry.xp, level: entry.level }
    });
  }

  async getLevel(userId: string, guildId: string) {
    const key = this.key(guildId, userId);
    const cached = this.cache.get(key);
    if (cached) return cached;
    return this.loadLevel(guildId, userId);
  }

  private async loadLevel(guildId: string, userId: string): Promise<LevelData> {
    const key = this.key(guildId, userId);
    if (this.cache.has(key)) return this.cache.get(key)!;
    const row = await prisma.level.findUnique({ where: { userId_guildId: { guildId, userId } } }).catch(() => null);
    const entry: LevelData = { xp: row?.xp ?? 0, level: row?.level ?? 0 };
    this.cache.set(key, entry);
    return entry;
  }
}
