import { Client, GatewayIntentBits, EmbedBuilder } from 'discord.js';
import { readFileSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import { getServerStatus } from './ssh.js';
import { getPlayers, getPlayerList } from './rcon.js';

const __dirname = dirname(fileURLToPath(import.meta.url));

let client = null;
let statusMessageId = null;
let statusChannelId = null;
let infoChannelId = null;
let alertChannelId = null;

// State tracking for alerts
const previousServerState = new Map();
const previousPlayerLists = new Map();

// Server display config
const serverDisplay = {
  minecraft: { name: 'Minecraft ATM10', icon: '⛏️', color: 0x7B5E3C, address: 'minecraft.zeasy.dev' },
  factorio: { name: 'Factorio', icon: '⚙️', color: 0xF97316, address: 'factorio.zeasy.dev' },
  zomboid: { name: 'Project Zomboid', icon: '🧟', color: 0x4ADE80, address: 'zomboid.zeasy.dev' },
  vrising: { name: 'V Rising', icon: '🧛', color: 0xDC2626, address: 'vrising.zeasy.dev' }
};

function loadConfig() {
  return JSON.parse(readFileSync(join(__dirname, '..', 'config.json'), 'utf-8'));
}

async function sendAlert(embed) {
  if (!client || !alertChannelId) return;

  try {
    const channel = await client.channels.fetch(alertChannelId);
    if (channel) {
      await channel.send({ embeds: [embed] });
    }
  } catch (err) {
    console.error('[DiscordBot] Error sending alert:', err.message);
  }
}

async function checkAndSendAlerts(serverStatuses) {
  for (const server of serverStatuses) {
    const display = serverDisplay[server.id] || { name: server.name, icon: '🖥️', color: 0x6B7280 };
    const prevState = previousServerState.get(server.id);
    const prevPlayers = previousPlayerLists.get(server.id) || [];

    // Check server status changes
    if (prevState !== undefined && prevState !== server.status) {
      let embed;

      if (server.status === 'online' && prevState !== 'online') {
        embed = new EmbedBuilder()
          .setTitle(display.icon + ' Server gestartet')
          .setDescription('**' + display.name + '** ist jetzt online')
          .setColor(0x22C55E)
          .setTimestamp();
      } else if (server.status === 'offline' && prevState === 'online') {
        embed = new EmbedBuilder()
          .setTitle(display.icon + ' Server gestoppt')
          .setDescription('**' + display.name + '** ist jetzt offline')
          .setColor(0xEF4444)
          .setTimestamp();
      } else if (server.status === 'unreachable' && prevState !== 'unreachable') {
        embed = new EmbedBuilder()
          .setTitle('⚠️ Server nicht erreichbar')
          .setDescription('**' + display.name + '** ist nicht erreichbar')
          .setColor(0xF59E0B)
          .setTimestamp();
      }

      if (embed) {
        await sendAlert(embed);
      }
    }

    // Check player changes (only if server is online)
    if (server.status === 'online' && server.playerList) {
      const currentPlayers = server.playerList;

      // Find players who joined
      for (const player of currentPlayers) {
        if (!prevPlayers.includes(player)) {
          const embed = new EmbedBuilder()
            .setTitle('➡️ Spieler beigetreten')
            .setDescription('**' + player + '** hat **' + display.name + '** betreten')
            .setColor(0x22C55E)
            .setTimestamp();
          await sendAlert(embed);
        }
      }

      // Find players who left
      for (const player of prevPlayers) {
        if (!currentPlayers.includes(player)) {
          const embed = new EmbedBuilder()
            .setTitle('⬅️ Spieler verlassen')
            .setDescription('**' + player + '** hat **' + display.name + '** verlassen')
            .setColor(0xF59E0B)
            .setTimestamp();
          await sendAlert(embed);
        }
      }

      previousPlayerLists.set(server.id, [...currentPlayers]);
    } else {
      previousPlayerLists.set(server.id, []);
    }

    // Update previous state
    previousServerState.set(server.id, server.status);
  }
}

async function setupInfoMessage() {
  try {
    const channel = await client.channels.fetch(infoChannelId);
    if (!channel) {
      console.error('[DiscordBot] Info channel not found');
      return;
    }

    const messages = await channel.messages.fetch({ limit: 10 });
    const botMessage = messages.find(m => m.author.id === client.user.id);

    const infoEmbed = new EmbedBuilder()
      .setTitle('🎮 Zeasy Gameserver Management')
      .setDescription(
        'Verwalte und überwache unsere Gameserver bequem über das Web-Interface.\n\n' +
        '**Features:**\n' +
        '• Server starten, stoppen & neustarten\n' +
        '• Live Server-Status & Spielerlisten\n' +
        '• Server-Konsole & RCON-Befehle\n' +
        '• CPU, RAM & Uptime Metriken\n' +
        '• Welten-Verwaltung (Factorio)\n' +
        '• Config-Editor (Project Zomboid)\n\n' +
        '**Zugang:**\n' +
        'Melde dich mit deinem Discord-Account an. Deine Berechtigungen werden automatisch über deine Discord-Rollen bestimmt.'
      )
      .setColor(0x5865F2)
      .addFields({
        name: '🔗 Web-Interface',
        value: '[server.zeasy.dev](https://server.zeasy.dev)',
        inline: false
      })
      .setFooter({ text: 'Zeasy Software' })
      .setTimestamp();

    if (botMessage) {
      await botMessage.edit({ embeds: [infoEmbed] });
      console.log('[DiscordBot] Updated info message');
    } else {
      await channel.send({ embeds: [infoEmbed] });
      console.log('[DiscordBot] Created info message');
    }
  } catch (err) {
    console.error('[DiscordBot] Error setting up info message:', err.message);
  }
}

export async function initDiscordBot() {
  const token = process.env.DISCORD_BOT_TOKEN;
  statusChannelId = process.env.DISCORD_STATUS_CHANNEL_ID;
  infoChannelId = process.env.DISCORD_INFO_CHANNEL_ID;
  alertChannelId = process.env.DISCORD_ALERT_CHANNEL_ID;

  if (!token) {
    console.log('[DiscordBot] Missing DISCORD_BOT_TOKEN, bot disabled');
    return;
  }

  client = new Client({
    intents: [GatewayIntentBits.Guilds]
  });

  client.once('ready', async () => {
    console.log('[DiscordBot] Logged in as ' + client.user.tag);

    // Setup info channel
    if (infoChannelId) {
      await setupInfoMessage();
    }

    // Setup status channel and alerts
    if (statusChannelId) {
      await findOrCreateStatusMessage();
      // First run - just populate state without sending alerts
      await updateStatusMessage(true);
      // Then start regular updates with alerts
      setInterval(() => updateStatusMessage(false), 60000);
    }
  });

  client.login(token).catch(err => {
    console.error('[DiscordBot] Failed to login:', err.message);
  });
}

async function findOrCreateStatusMessage() {
  try {
    const channel = await client.channels.fetch(statusChannelId);
    if (!channel) {
      console.error('[DiscordBot] Status channel not found');
      return;
    }

    const messages = await channel.messages.fetch({ limit: 10 });
    const botMessage = messages.find(m => m.author.id === client.user.id);

    if (botMessage) {
      statusMessageId = botMessage.id;
      console.log('[DiscordBot] Found existing status message');
    } else {
      const msg = await channel.send({ embeds: [createLoadingEmbed()] });
      statusMessageId = msg.id;
      console.log('[DiscordBot] Created new status message');
    }
  } catch (err) {
    console.error('[DiscordBot] Error finding/creating status message:', err.message);
  }
}

function createLoadingEmbed() {
  return new EmbedBuilder()
    .setTitle('🎮 Gameserver Status')
    .setDescription('Lade Server-Status...')
    .setColor(0x6B7280)
    .setTimestamp();
}

async function updateStatusMessage(skipAlerts = false) {
  if (!client || !statusMessageId || !statusChannelId) return;

  try {
    const channel = await client.channels.fetch(statusChannelId);
    const message = await channel.messages.fetch(statusMessageId);

    const config = loadConfig();

    const serverStatuses = await Promise.all(config.servers.map(async (server) => {
      try {
        const status = await getServerStatus(server);
        const running = status === 'online';

        let players = { online: 0, max: null };
        let playerList = { players: [] };

        if (running && server.rconPassword) {
          try {
            players = await getPlayers(server);
            playerList = await getPlayerList(server);
          } catch (e) {
            // RCON might fail
          }
        }

        return {
          id: server.id,
          name: server.name,
          type: server.type,
          status: running ? 'online' : 'offline',
          running,
          players: players.online || 0,
          maxPlayers: players.max,
          playerList: playerList.players || []
        };
      } catch (err) {
        return {
          id: server.id,
          name: server.name,
          type: server.type,
          status: 'unreachable',
          running: false,
          players: 0,
          maxPlayers: null,
          playerList: []
        };
      }
    }));

    // Send alerts if enabled
    if (!skipAlerts && alertChannelId) {
      await checkAndSendAlerts(serverStatuses);
    } else if (skipAlerts) {
      // Just populate initial state
      for (const server of serverStatuses) {
        previousServerState.set(server.id, server.status);
        previousPlayerLists.set(server.id, server.playerList || []);
      }
    }

    const embeds = [];

    const onlineCount = serverStatuses.filter(s => s.running).length;
    const totalPlayers = serverStatuses.reduce((sum, s) => sum + s.players, 0);

    const headerEmbed = new EmbedBuilder()
      .setTitle('🎮 Gameserver Status')
      .setDescription('**' + onlineCount + '/' + serverStatuses.length + '** Server online • **' + totalPlayers + '** Spieler')
      .setColor(onlineCount > 0 ? 0x22C55E : 0xEF4444)
      .setTimestamp()
      .setFooter({ text: 'Aktualisiert alle 60 Sekunden' });

    embeds.push(headerEmbed);

    for (const server of serverStatuses) {
      const display = serverDisplay[server.id] || { name: server.name, icon: '🖥️', color: 0x6B7280, address: '' };

      const serverEmbed = new EmbedBuilder()
        .setTitle(display.icon + ' ' + display.name)
        .setColor(server.running ? display.color : 0x4B5563);

      if (server.running) {
        let description = '✅ **Online**\n';

        if (display.address) {
          description += '```' + display.address + '```';
        }

        description += '👥 **Spieler:** ' + server.players;
        if (server.maxPlayers) {
          description += '/' + server.maxPlayers;
        }

        if (server.playerList && server.playerList.length > 0) {
          const names = server.playerList.slice(0, 15).join(', ');
          description += '\n' + names;
          if (server.playerList.length > 15) {
            description += ' *+' + (server.playerList.length - 15) + ' mehr*';
          }
        }

        serverEmbed.setDescription(description);
      } else {
        serverEmbed.setDescription('❌ **Offline**');
      }

      embeds.push(serverEmbed);
    }

    await message.edit({ embeds });

  } catch (err) {
    console.error('[DiscordBot] Error updating status message:', err.message);
  }
}

export function getDiscordClient() {
  return client;
}
