import { Client } from 'discord.js';

type LogLevel = 'INFO' | 'WARN' | 'ERROR';

export interface AdminLogEntry {
  timestamp: number;
  level: LogLevel;
  message: string;
  guildId?: string;
  category?: string;
}

export class AdminService {
  private startTime = Date.now();
  private client: Client | null = null;
  private hourBuckets = new Map<string, number>();
  private activeGuilds = new Map<string, number>();
  private logs: AdminLogEntry[] = [];
  private logLimit = 120;
  private guildLogs = new Map<string, AdminLogEntry[]>();
  private guildActivity = new Map<
    string,
    { messages: number[]; commands: number[]; automod: number[] }
  >();

  public setStartTime(ts: number) {
    this.startTime = ts;
  }

  public setClient(client: Client) {
    this.client = client;
  }

  public trackCommand(guildId?: string | null) {
    this.bumpActivity(guildId || 'unknown');
    this.trackGuildActivity(guildId || 'unknown', 'commands');
  }

  public trackEvent(_event: string, guildId?: string | null) {
    this.bumpActivity(guildId || 'unknown');
    this.trackGuildActivity(guildId || 'unknown', 'messages');
  }

  public trackGuildEvent(guildId: string, type: 'messages' | 'commands' | 'automod') {
    this.trackGuildActivity(guildId, type);
  }

  private bumpActivity(guildId: string) {
    const now = Date.now();
    const hour = new Date(now);
    hour.setMinutes(0, 0, 0);
    const key = hour.toISOString();
    this.hourBuckets.set(key, (this.hourBuckets.get(key) ?? 0) + 1);
    this.activeGuilds.set(guildId, now);
    // cleanup older than 24h
    const cutoff = now - 24 * 60 * 60 * 1000;
    for (const [k] of this.hourBuckets) {
      if (new Date(k).getTime() < cutoff) this.hourBuckets.delete(k);
    }
    for (const [g, ts] of this.activeGuilds) {
      if (ts < cutoff) this.activeGuilds.delete(g);
    }
  }

  public pushLog(entry: AdminLogEntry) {
    this.logs.push(entry);
    if (this.logs.length > this.logLimit) this.logs.splice(0, this.logs.length - this.logLimit);
  }

  public pushGuildLog(entry: AdminLogEntry & { guildId: string; category?: string }) {
    this.pushLog(entry);
    const arr = this.guildLogs.get(entry.guildId) ?? [];
    arr.push(entry);
    if (arr.length > this.logLimit) arr.splice(0, arr.length - this.logLimit);
    this.guildLogs.set(entry.guildId, arr);
  }

  public getOverview() {
    const guildCount = this.client?.guilds.cache.size ?? 0;
    const activeGuilds24 = this.activeGuilds.size;
    return {
      guildCount,
      activeGuilds24,
      startTime: this.startTime,
      uptimeMs: Date.now() - this.startTime
    };
  }

  public getActivity() {
    const points = Array.from(this.hourBuckets.entries())
      .map(([iso, count]) => ({ hour: iso, count }))
      .sort((a, b) => new Date(a.hour).getTime() - new Date(b.hour).getTime());
    return { points };
  }

  public getLogs() {
    return this.logs.slice().reverse();
  }

  public getGuildLogs(guildId: string) {
    return (this.guildLogs.get(guildId) ?? []).slice().reverse();
  }

  public getGuildActivity(guildId: string) {
    const now = Date.now();
    const cutoff24 = now - 24 * 60 * 60 * 1000;
    const data = this.guildActivity.get(guildId) || { messages: [], commands: [], automod: [] };
    const filter = (arr: number[]) => arr.filter((ts) => ts >= cutoff24);
    const messages = filter(data.messages);
    const commands = filter(data.commands);
    const automod = filter(data.automod);
    data.messages = messages;
    data.commands = commands;
    data.automod = automod;
    this.guildActivity.set(guildId, data);
    return { messages24h: messages.length, commands24h: commands.length, automod24h: automod.length };
  }

  private trackGuildActivity(guildId: string, type: 'messages' | 'commands' | 'automod') {
    if (!guildId) return;
    const entry = this.guildActivity.get(guildId) || { messages: [], commands: [], automod: [] };
    entry[type].push(Date.now());
    this.guildActivity.set(guildId, entry);
  }
}
