/**
 * Server Status Poller Service
 * 
 * Posts and updates server status embeds in Discord channels.
 * Each game server category has a -status channel that shows live status.
 * 
 * Created: April 10, 2026 (Chronicler #75)
 */

const axios = require('axios');
const db = require('../database');

// Discord API
const DISCORD_API = 'https://discord.com/api/v10';
const DISCORD_TOKEN = process.env.DISCORD_BOT_TOKEN;

// Pterodactyl API (direct, not via Worker)
const PTERO_URL = process.env.PANEL_URL || 'https://panel.firefrostgaming.com';
const PTERO_KEY = process.env.PANEL_CLIENT_KEY || process.env.PTERO_CLIENT_KEY;

// Map server names to their status channel IDs
// Key: lowercase server name (from Pterodactyl)
// Value: Discord channel ID
const SERVER_CHANNEL_MAP = {
    'stoneblock 4': '1492186819918565468',
    'society: sunlit valley': '1492186823332729073',
    'society sunlit valley': '1492186823332729073',
    'all the mods 10: to the sky': '1492186826746757322',
    'atm10: to the sky': '1492186826746757322',
    'all the mons': '1492186832560193618',
    'mythcraft 5': '1492186836422889643',
    'beyond depth': '1492186839979786440',
    'beyond ascension': '1492186845742891038',
    'otherworld': '1492186850545111090',
    'deceasedcraft': '1492186854320242820',
    'submerged 2': '1492186858413883525',
    'sneak\'s pirate pack': '1492186863774204144',
    'sneaks pirate pack': '1492186863774204144',
    'cottage witch': '1492186867372785855',
    'farm crossing 6': '1493430754053722182',
    'homestead': '1492186875019005963',
    'wold\'s vaults': '1492186878269587528',
    'wolds vaults': '1492186878269587528'
};

// Store message IDs so we can edit instead of posting new
// In-memory for now, persists to DB for restarts
const statusMessageIds = {};

/**
 * Initialize - load stored message IDs from database
 */
async function init() {
    try {
        // Create table if not exists
        await db.query(`
            CREATE TABLE IF NOT EXISTS discord_status_messages (
                channel_id VARCHAR(64) PRIMARY KEY,
                message_id VARCHAR(64) NOT NULL,
                server_name VARCHAR(128),
                updated_at TIMESTAMP DEFAULT NOW()
            )
        `);
        
        // Load existing message IDs
        const result = await db.query('SELECT channel_id, message_id FROM discord_status_messages');
        for (const row of result.rows) {
            statusMessageIds[row.channel_id] = row.message_id;
        }
        
        console.log(`[StatusPoller] Loaded ${result.rows.length} existing status message IDs`);
    } catch (err) {
        console.error('[StatusPoller] Init error:', err.message);
    }
}

/**
 * Build status embed for a server
 */
function buildEmbed(server) {
    const isOnline = server.status === 'Online';
    
    return {
        embeds: [{
            title: `${isOnline ? '🟢' : '🔴'} ${server.name}`,
            color: isOnline ? 0x00FF00 : 0xFF0000,
            fields: [
                {
                    name: 'Status',
                    value: server.status,
                    inline: true
                },
                {
                    name: 'Players',
                    value: isOnline ? `${server.players || 0}` : '-',
                    inline: true
                }
            ],
            footer: {
                text: `Last updated`
            },
            timestamp: new Date().toISOString()
        }]
    };
}

/**
 * Post or update a status message in a channel
 */
async function postOrUpdateStatus(channelId, server) {
    const embed = buildEmbed(server);
    const existingMessageId = statusMessageIds[channelId];
    
    try {
        if (existingMessageId) {
            // Try to edit existing message
            const response = await axios.patch(
                `${DISCORD_API}/channels/${channelId}/messages/${existingMessageId}`,
                embed,
                { headers: { 'Authorization': `Bot ${DISCORD_TOKEN}`, 'Content-Type': 'application/json' } }
            );
            return { success: true, action: 'updated', messageId: response.data.id };
        } else {
            // Post new message
            const response = await axios.post(
                `${DISCORD_API}/channels/${channelId}/messages`,
                embed,
                { headers: { 'Authorization': `Bot ${DISCORD_TOKEN}`, 'Content-Type': 'application/json' } }
            );
            
            const messageId = response.data.id;
            statusMessageIds[channelId] = messageId;
            
            // Store in database
            await db.query(`
                INSERT INTO discord_status_messages (channel_id, message_id, server_name)
                VALUES ($1, $2, $3)
                ON CONFLICT (channel_id) DO UPDATE SET message_id = $2, server_name = $3, updated_at = NOW()
            `, [channelId, messageId, server.name]);
            
            return { success: true, action: 'posted', messageId };
        }
    } catch (err) {
        // If edit fails (message deleted?), try posting new
        if (err.response?.status === 404 && existingMessageId) {
            delete statusMessageIds[channelId];
            return postOrUpdateStatus(channelId, server);
        }
        
        console.error(`[StatusPoller] Error posting to ${channelId}:`, err.message);
        return { success: false, error: err.message };
    }
}

/**
 * Find channel ID for a server name
 */
function findChannelForServer(serverName) {
    const normalized = serverName.toLowerCase().trim();
    
    // Direct match
    if (SERVER_CHANNEL_MAP[normalized]) {
        return SERVER_CHANNEL_MAP[normalized];
    }
    
    // Partial match
    for (const [key, channelId] of Object.entries(SERVER_CHANNEL_MAP)) {
        if (normalized.includes(key) || key.includes(normalized)) {
            return channelId;
        }
    }
    
    return null;
}

/**
 * Fetch servers from Pterodactyl API
 */
async function fetchServers() {
    if (!PTERO_KEY) {
        console.error('[StatusPoller] PTERO_CLIENT_KEY not set');
        return [];
    }
    
    try {
        // Get server list
        const listResponse = await axios.get(`${PTERO_URL}/api/client`, {
            headers: {
                'Authorization': `Bearer ${PTERO_KEY}`,
                'Accept': 'application/json'
            }
        });
        
        const serverList = listResponse.data.data || [];
        const servers = [];
        
        // Get status for each server
        for (const server of serverList) {
            const id = server.attributes.identifier;
            const name = server.attributes.name;
            
            try {
                const statsResponse = await axios.get(
                    `${PTERO_URL}/api/client/servers/${id}/resources`,
                    {
                        headers: {
                            'Authorization': `Bearer ${PTERO_KEY}`,
                            'Accept': 'application/json'
                        }
                    }
                );
                
                const isRunning = statsResponse.data.attributes?.current_state === 'running';
                
                servers.push({
                    id: id,
                    name: name,
                    status: isRunning ? 'Online' : 'Offline',
                    players: isRunning ? (statsResponse.data.attributes?.resources?.players || 0) : 0
                });
            } catch (err) {
                // Server might be inaccessible
                servers.push({
                    id: id,
                    name: name,
                    status: 'Unknown',
                    players: 0
                });
            }
            
            // Rate limiting
            await new Promise(resolve => setTimeout(resolve, 200));
        }
        
        return servers;
    } catch (err) {
        console.error('[StatusPoller] Pterodactyl API error:', err.message);
        return [];
    }
}

/**
 * Poll all servers and update Discord status messages
 */
async function pollAndUpdate() {
    console.log('[StatusPoller] Polling server status...');
    
    try {
        const servers = await fetchServers();
        
        console.log(`[StatusPoller] Got ${servers.length} servers`);
        
        let updated = 0;
        let skipped = 0;
        
        for (const server of servers) {
            const channelId = findChannelForServer(server.name);
            
            if (!channelId) {
                console.log(`[StatusPoller] No channel mapping for: ${server.name}`);
                skipped++;
                continue;
            }
            
            const result = await postOrUpdateStatus(channelId, server);
            if (result.success) {
                updated++;
            }
            
            // Rate limiting - 1 request per 500ms
            await new Promise(resolve => setTimeout(resolve, 500));
        }
        
        console.log(`[StatusPoller] Updated ${updated} channels, skipped ${skipped}`);
        
    } catch (err) {
        console.error('[StatusPoller] Poll error:', err.message);
    }
}

/**
 * Start the poller with interval
 */
function start(intervalMinutes = 5) {
    console.log(`[StatusPoller] Starting with ${intervalMinutes} minute interval`);
    
    // Initialize and run immediately
    init().then(() => {
        pollAndUpdate();
    });
    
    // Then run on interval
    setInterval(pollAndUpdate, intervalMinutes * 60 * 1000);
}

module.exports = {
    init,
    fetchServers,
    pollAndUpdate,
    start,
    findChannelForServer,
    SERVER_CHANNEL_MAP
};
