const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const axios = require('axios');

const app = express();
const server = http.createServer(app);
const io = new Server(server, { cors: { origin: "*" } });

const ACS_URL = 'http://103.165.157.83:7557';

/**
 * PROJECTION FIELDS: Diupdate sesuai nama Virtual Parameter asli di ACS Mas
 */
const projectionFields = [
    '_id', '_lastInform', '_deviceId._SerialNumber', '_deviceId._OUI',
    'InternetGatewayDevice.DeviceInfo.ModelName',
    'InternetGatewayDevice.DeviceInfo.HardwareVersion',
    'InternetGatewayDevice.DeviceInfo.SoftwareVersion',
    'InternetGatewayDevice.WANDevice.1.WANCommonInterfaceConfig.WANAccessType',
    'InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID',
    
    // Virtual Parameters (WAJIB SAMA DENGAN clientConfig MAS)
    'VirtualParameters.RXPower',          // Redaman
    'VirtualParameters.gettemp',          // Temperatur 
    'VirtualParameters.pppoeUsername',    // PPPoE User
    'VirtualParameters.pppoeIP',          // IP PPPoE
    'VirtualParameters.IPTR069',          // IP TR069
    'VirtualParameters.getdeviceuptime',  // Uptime Device
    'VirtualParameters.getpppuptime',     // Uptime PPP
    'VirtualParameters.getSerialNumber',  // SN
    'VirtualParameters.activedevices'     // Total Wifi
].join(',');

function getVal(obj, paths) {
    if (!Array.isArray(paths)) paths = [paths];
    for (let path of paths) {
        let current = obj;
        const parts = path.split('.');
        let found = true;
        for (let part of parts) {
            if (!current || !current.hasOwnProperty(part)) { found = false; break; }
            current = current[part];
        }
        if (found && current !== null && current !== undefined) {
            return current._value !== undefined ? current._value : current;
        }
    }
    return '-';
}

async function fetchACS() {
    try {
        console.log("🔄 Menarik data dari GenieACS (Monster Mode)...");
        const res = await axios.get(`${ACS_URL}/devices/?projection=${projectionFields}`);
        
        const allDevices = res.data;
        const chunkSize = 100; // Kirim per 100 data agar Laravel tidak pingsan
        console.log(`📦 Total ${allDevices.length} perangkat. Memulai sinkronisasi bertahap...`);

        for (let i = 0; i < allDevices.length; i += chunkSize) {
            const chunk = allDevices.slice(i, i + chunkSize);
            const realtimeData = {};

            chunk.forEach(d => {
                // 1. Ambil Username PPPOE
                let pppoe = getVal(d, [
                    'VirtualParameters.pppoeUsername',
                    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANPPPConnection.1.Username'
                ]);
                
                if (pppoe === '-' || !pppoe) return;
                pppoe = String(pppoe).toLowerCase().trim();

                const lastInformRaw = d._lastInform;
                const isOnline = lastInformRaw ? ((new Date() - new Date(lastInformRaw)) / 60000) < 10 : false;
                
                // 2. AMBIL LINK TYPE (GPON/EPON) - Fallback jika VP Kosong
                let pon = getVal(d, [
                    'VirtualParameters.getponmode', 
                    'InternetGatewayDevice.WANDevice.1.WANCommonInterfaceConfig.WANAccessType'
                ]);

                // 3. Ambil RX Power & Temp
                let rx = getVal(d, 'VirtualParameters.RXPower');
                let temp = getVal(d, 'VirtualParameters.gettemp');

                let color = 'merah';
                if (isOnline && rx !== '-') {
                    const valRx = parseFloat(rx);
                    if (valRx >= -25 && valRx <= -10) color = 'hijau';
                    else if (valRx < -25 && valRx >= -28) color = 'kuning';
                    else color = 'biru';
                }

                realtimeData[pppoe] = { 
                    status: isOnline ? 'Online' : 'Offline', 
                    color_key: color,
                    rx_power: rx,
                    last_inform: lastInformRaw || null,
                    device_uptime: getVal(d, 'VirtualParameters.getdeviceuptime'),
                    ppp_uptime: getVal(d, 'VirtualParameters.getpppuptime'),
                    device_type: getVal(d, 'InternetGatewayDevice.DeviceInfo.ModelName'),
                    sn_ont: getVal(d, 'VirtualParameters.getSerialNumber'),
                    hardware_version: getVal(d, 'InternetGatewayDevice.DeviceInfo.HardwareVersion'),
                    software_version: getVal(d, 'InternetGatewayDevice.DeviceInfo.SoftwareVersion'),
                    oui: getVal(d, '_deviceId._OUI'),
                    link_type: pon, // Ini yang akan masuk ke kolom pon_mode
                    temperature: temp,
                    ip_pppoe: getVal(d, 'VirtualParameters.pppoeIP'),
                    ip_tr069: getVal(d, 'VirtualParameters.IPTR069'),
                    total_perangkat: getVal(d, 'VirtualParameters.activedevices'),
                    wifi_ssid: getVal(d, 'InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID')
                };
            });

            // Kirim Kloter ke Laravel
            if (Object.keys(realtimeData).length > 0) {
                try {
                    await axios.post('http://127.0.0.1:8000/api/map/sync-acs', { data: realtimeData });
                    console.log(`✅ Berhasil sinkron kloter ke-${(i/chunkSize)+1}`);
                } catch (err) {
                    console.error(`❌ Kloter ${(i/chunkSize)+1} gagal:`, err.message);
                }
            }

            // Jeda 1 detik antar kloter agar database MySQL tidak terkunci (Lock)
            await new Promise(resolve => setTimeout(resolve, 1000));
        }

        io.emit('acs_update', true); 
        console.log("🏁 Semua kloter sinkronisasi selesai.");

    } catch (e) {
        console.error("❌ Error GenieACS:", e.message);
    }
}

const PORT = 3001;
server.listen(PORT, () => {
    console.log(`🚀 Bridge Monster Aktif di Port ${PORT}`);
    fetchACS(); 
    setInterval(fetchACS, 15000);
});