import { Client, GatewayIntentBits, EmbedBuilder, ChannelType, PermissionFlagsBits } 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';
import { initGuildSettings, getGuildSettings, getAllGuildSettings, setGuildSettings, deleteGuildSettings } from '../db/init.js';

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

let client = null;

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

// Server display config
const serverDisplay = {
  minecraft: { name: 'Biohazard: Project Genesis', icon: '⛏️', color: 0x4A7A2E, address: 'minecraft.zeasy.dev' },
  factorio: { name: 'Factorio', icon: '⚙️', color: 0xF97316, address: 'factorio.zeasy.dev' },
  zomboid: { name: 'Project Zomboid', icon: '🧟', color: 0x4ADE80, address: 'pz.zeasy.dev:16261' },
  vrising: { name: 'V Rising', icon: '🧛', color: 0xDC2626, address: 'vrising.zeasy.dev' },
  palworld: { name: 'Palworld', icon: '🦎', color: 0x00D4AA, address: 'palworld.zeasy.dev:8211' },
  terraria: { name: 'Terraria', icon: '⚔️', color: 0x05C46B, address: 'terraria.zeasy.dev:7777' },
  openttd: { name: 'OpenTTD', icon: '🚂', color: 0x1E90FF, address: 'openttd.zeasy.dev:3979' },
  hytale: { name: 'Hytale', icon: '🏰', color: 0x00BFFF, address: 'hytale.zeasy.dev:5520' },
  spaceengineers: { name: 'Space Engineers', icon: '🚀', color: 0xFFA500, address: 'space.zeasy.dev:27020' }
};

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

// ============================================
// Channel Setup Functions
// ============================================

async function setupGuildChannels(guild) {
  console.log('[DiscordBot] Setting up channels for guild: ' + guild.name);

  try {
    // Create category
    const category = await guild.channels.create({
      name: '🎮 Gameserver',
      type: ChannelType.GuildCategory,
      permissionOverwrites: [
        {
          id: guild.id, // @everyone
          deny: [PermissionFlagsBits.SendMessages],
          allow: [PermissionFlagsBits.ViewChannel, PermissionFlagsBits.ReadMessageHistory]
        },
        {
          id: client.user.id, // Bot
          allow: [PermissionFlagsBits.SendMessages, PermissionFlagsBits.ManageMessages, PermissionFlagsBits.EmbedLinks]
        }
      ]
    });

    // Create info channel
    const infoChannel = await guild.channels.create({
      name: 'ℹ️│info',
      type: ChannelType.GuildText,
      parent: category.id,
      topic: 'Informationen zum Gameserver Management System'
    });

    // Create status channel
    const statusChannel = await guild.channels.create({
      name: '📊│status',
      type: ChannelType.GuildText,
      parent: category.id,
      topic: 'Live-Status aller Gameserver'
    });

    // Create alerts channel
    const alertsChannel = await guild.channels.create({
      name: '📢│alerts',
      type: ChannelType.GuildText,
      parent: category.id,
      topic: 'Benachrichtigungen über Server-Events und Spieler'
    });

    // Create updates channel
    const updatesChannel = await guild.channels.create({
      name: '📰│updates',
      type: ChannelType.GuildText,
      parent: category.id,
      topic: 'Ankündigungen zu neuen Gameservern'
    });

    // Create discussion channel (users can write)
    const discussionChannel = await guild.channels.create({
      name: '💬│diskussion',
      type: ChannelType.GuildText,
      parent: category.id,
      topic: 'Diskutiert hier über die Gameserver',
      permissionOverwrites: [
        {
          id: guild.id,
          allow: [PermissionFlagsBits.SendMessages, PermissionFlagsBits.ViewChannel, PermissionFlagsBits.ReadMessageHistory]
        }
      ]
    });

    // Create requests forum channel
    const requestsChannel = await guild.channels.create({
      name: '💡│requests',
      type: ChannelType.GuildForum,
      parent: category.id,
      topic: 'Schlage neue Gameserver vor',
      defaultAutoArchiveDuration: 10080, // 7 days
      permissionOverwrites: [
        {
          id: guild.id,
          allow: [PermissionFlagsBits.SendMessages, PermissionFlagsBits.ViewChannel, PermissionFlagsBits.ReadMessageHistory, PermissionFlagsBits.CreatePublicThreads]
        }
      ]
    });

    // Create info thread in requests forum
    const infoThread = await requestsChannel.threads.create({
      name: '📌 Wie funktioniert dieser Kanal?',
      message: {
        embeds: [new EmbedBuilder()
          .setTitle('💡 Gameserver Vorschläge')
          .setDescription(
            'In diesem Kanal kannst du neue Gameserver vorschlagen!\n\n' +
            '**So funktioniert\'s:**\n' +
            '1. Erstelle einen neuen Beitrag mit dem Namen des Spiels\n' +
            '2. Beschreibe warum dieser Server cool wäre\n' +
            '3. Andere können deinen Vorschlag diskutieren und liken\n\n' +
            '**Was wir berücksichtigen:**\n' +
            '• Interesse der Community (Likes & Diskussion)\n' +
            '• Technische Machbarkeit\n' +
            '• Serverkosten\n\n' +
            'Beliebte Vorschläge werden von uns geprüft!'
          )
          .setColor(0x5865F2)
          .setFooter({ text: 'Zeasy Gameserver' })
        ]
      }
    });

    // Pin the info thread
    await infoThread.pin();

    // Create info message
    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 (Palworld, Zomboid)\n\n' +
        '**Zugang:**\n' +
        'Melde dich mit deinem Discord-Account an.'
      )
      .setColor(0x5865F2)
      .addFields({
        name: '🔗 Web-Interface',
        value: '[server.zeasy.dev](https://server.zeasy.dev)',
        inline: false
      })
      .setFooter({ text: 'Zeasy Software' })
      .setTimestamp();

    await infoChannel.send({ embeds: [infoEmbed] });

    // Create initial status message
    const statusMsg = await statusChannel.send({ embeds: [createLoadingEmbed()] });

    // Save settings to database
    const settings = {
      category_id: category.id,
      info_channel_id: infoChannel.id,
      status_channel_id: statusChannel.id,
      status_message_id: statusMsg.id,
      alerts_channel_id: alertsChannel.id,
      updates_channel_id: updatesChannel.id,
      discussion_channel_id: discussionChannel.id,
      requests_channel_id: requestsChannel.id,
      requests_info_thread_id: infoThread.id
    };

    setGuildSettings(guild.id, settings);

    console.log('[DiscordBot] Setup complete for guild: ' + guild.name);

    // Send welcome message in alerts
    const welcomeEmbed = new EmbedBuilder()
      .setTitle('🎉 Gameserver Bot eingerichtet!')
      .setDescription(
        'Die Gameserver-Kanäle wurden erfolgreich erstellt.\n\n' +
        '**Kanäle:**\n' +
        '• <#' + infoChannel.id + '> - Allgemeine Infos\n' +
        '• <#' + statusChannel.id + '> - Live Server-Status\n' +
        '• <#' + alertsChannel.id + '> - Benachrichtigungen\n' +
        '• <#' + updatesChannel.id + '> - Server-Ankündigungen\n' +
        '• <#' + discussionChannel.id + '> - Diskussion\n' +
        '• <#' + requestsChannel.id + '> - Server-Vorschläge'
      )
      .setColor(0x22C55E)
      .setTimestamp();

    await alertsChannel.send({ embeds: [welcomeEmbed] });

    return settings;

  } catch (err) {
    console.error('[DiscordBot] Error setting up guild channels:', err);
    throw err;
  }
}

// ============================================
// Alert Functions
// ============================================

async function sendAlertToAllGuilds(embed) {
  const allSettings = getAllGuildSettings();

  for (const settings of allSettings) {
    if (!settings.alerts_channel_id) continue;

    try {
      const channel = await client.channels.fetch(settings.alerts_channel_id);
      if (channel) {
        await channel.send({ embeds: [embed] });
      }
    } catch (err) {
      console.error('[DiscordBot] Error sending alert to guild ' + settings.guild_id + ':', 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();
      }

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

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

      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 sendAlertToAllGuilds(embed);
        }
      }

      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 sendAlertToAllGuilds(embed);
        }
      }

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

    previousServerState.set(server.id, server.status);
  }
}

// ============================================
// Status Update Functions
// ============================================

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

function createStatusEmbeds(serverStatuses) {
  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);
  }

  return embeds;
}

async function fetchServerStatuses() {
  const config = loadConfig();

  return 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 || server.type === 'hytale' || server.type === 'terraria' || server.type === 'spaceengineers')) {
        try {
          players = await getPlayers(server);
          playerList = await getPlayerList(server);
        } catch (e) {
          // RCON/log parsing 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: []
      };
    }
  }));
}

async function updateAllStatusMessages(skipAlerts = false) {
  if (!client) return;

  try {
    const serverStatuses = await fetchServerStatuses();
    const embeds = createStatusEmbeds(serverStatuses);

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

    // Update status message in all guilds
    const allSettings = getAllGuildSettings();

    for (const settings of allSettings) {
      if (!settings.status_channel_id || !settings.status_message_id) continue;

      try {
        const channel = await client.channels.fetch(settings.status_channel_id);
        const message = await channel.messages.fetch(settings.status_message_id);
        await message.edit({ embeds });
      } catch (err) {
        console.error('[DiscordBot] Error updating status for guild ' + settings.guild_id + ':', err.message);
      }
    }

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

// ============================================
// Public Functions
// ============================================

export async function sendUpdateToAllGuilds(embed) {
  const allSettings = getAllGuildSettings();

  for (const settings of allSettings) {
    if (!settings.updates_channel_id) continue;

    try {
      const channel = await client.channels.fetch(settings.updates_channel_id);
      if (channel) {
        await channel.send({ embeds: [embed] });
      }
    } catch (err) {
      console.error('[DiscordBot] Error sending update to guild ' + settings.guild_id + ':', err.message);
    }
  }
}

export async function initDiscordBot() {
  const token = process.env.DISCORD_BOT_TOKEN;

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

  // Initialize database table
  initGuildSettings();

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

  // Bot joined a new server
  client.on('guildCreate', async (guild) => {
    console.log('[DiscordBot] Joined new guild: ' + guild.name + ' (' + guild.id + ')');

    try {
      await setupGuildChannels(guild);
    } catch (err) {
      console.error('[DiscordBot] Failed to setup guild:', err.message);
    }
  });

  // Bot was removed from a server
  client.on('guildDelete', (guild) => {
    console.log('[DiscordBot] Left guild: ' + guild.name + ' (' + guild.id + ')');
    deleteGuildSettings(guild.id);
  });
  client.once('ready', async () => {
    console.log('[DiscordBot] Logged in as ' + client.user.tag);

    // Check for guilds without settings and set them up
    for (const [guildId, guild] of client.guilds.cache) {
      const settings = getGuildSettings(guildId);
      if (!settings) {
        console.log('[DiscordBot] Setting up missing guild: ' + guild.name);
        try {
          await setupGuildChannels(guild);
        } catch (err) {
          console.error('[DiscordBot] Failed to setup missing guild ' + guild.name + ':', err);
        }
      }
    }

    // First run - populate state without alerts
    await updateAllStatusMessages(true);

    // Regular updates every 60 seconds
    setInterval(() => updateAllStatusMessages(false), 60000);
  });
  client.login(token).catch(err => {
    console.error('[DiscordBot] Failed to login:', err.message);
  });
}

export function getDiscordClient() {
  return client;
}

// Export setup function for manual setup via API
export { setupGuildChannels };
