const express = require('express');
const router = express.Router();
const rawAxios = require('axios');
const db = require('../config/database');
const { getSetting, getSettings } = require('../config/settingsManager');
const sidebarMenuSvc = require('../services/sidebarMenuService');
const customerDevice = require('../services/customerDeviceService');
const mikrotikSvc = require('../services/mikrotikService');
const fs = require('fs');
const path = require('path');
const { createAxiosInstance, isBuiltinAcsEnabled } = require('../config/genieacs');

// Proxy axios to support local built-in ACS proxy
const axios = {
    get: async (url, config = {}) => {
        if (isBuiltinAcsEnabled() && (url.startsWith('local/') || url === 'local')) {
            const path = url.replace(/^local/, '');
            const instance = createAxiosInstance({ id: 'builtin', url: 'local' });
            return instance.get(path, config);
        }
        return rawAxios.get(url, config);
    },
    post: async (url, data, config = {}) => {
        if (isBuiltinAcsEnabled() && url.startsWith('local/')) {
            const path = url.replace(/^local/, '');
            const instance = createAxiosInstance({ id: 'builtin', url: 'local' });
            return instance.post(path, data, config);
        }
        return rawAxios.post(url, data, config);
    },
    delete: async (url, config = {}) => {
        if (isBuiltinAcsEnabled() && url.startsWith('local/')) {
            const path = url.replace(/^local/, '');
            const instance = createAxiosInstance({ id: 'builtin', url: 'local' });
            return instance.delete(path, config);
        }
        return rawAxios.delete(url, config);
    },
    put: async (url, data, config = {}) => {
        if (isBuiltinAcsEnabled() && url.startsWith('local/')) {
            const path = url.replace(/^local/, '');
            const instance = createAxiosInstance({ id: 'builtin', url: 'local' });
            return instance.put(path, data, config);
        }
        return rawAxios.put(url, data, config);
    }
};

// Helper for DB queries (using better-sqlite3)
function getACSServers(id = null) {
    if (isBuiltinAcsEnabled()) {
        const builtinServer = {
            id: 'builtin',
            name: 'Built-in ACS',
            url: 'local',
            status: 'active'
        };
        if (id && id !== 'all') {
            return id === 'builtin' ? [builtinServer] : [];
        }
        return [builtinServer];
    }

    const legacyACS = getLegacyACS();
    const legacyServer = legacyACS.acs_url ? { 
        id: 'legacy', 
        name: 'Default ACS', 
        url: legacyACS.acs_url, 
        username: legacyACS.acs_user, 
        password: legacyACS.acs_pass 
    } : null;

    if (id === 'legacy') return legacyServer ? [legacyServer] : [];

    let query = 'SELECT * FROM genieacs_servers';
    let params = [];
    if (id && id !== 'all') {
        query += ' WHERE id = ?';
        params.push(id);
        const row = db.prepare(query).get(params);
        return row ? [row] : [];
    }
    
    const rows = db.prepare(query).all(params);
    return legacyServer ? [legacyServer, ...rows] : rows;
}

function getLegacyACS() {
    return {
        acs_url: getSetting('genieacs_url', ''),
        acs_user: getSetting('genieacs_username', ''),
        acs_pass: getSetting('genieacs_password', ''),
        acs_vparams: '', // Default empty for now
        acs_path_pppoe: 'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANPPPConnection.1.Username',
        acs_path_ip: 'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.ExternalIPAddress'
    };
}

function getAxiosConfig(server) {
    const config = {
        timeout: 15000,
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        }
    };
    if (server.username && server.password) {
        config.auth = {
            username: server.username,
            password: server.password
        };
    }
    return config;
}

// Helper to normalize URL
function normalizeUrl(url) {
    if (!url) return '';
    return url.endsWith('/') ? url.slice(0, -1) : url;
}

// Helper to get nested value like genieacs.js
function getNestedValue(obj, path) {
    try {
        const parts = path.split('.');
        let current = obj;
        for (const part of parts) {
            if (!current) return null;
            current = current[part];
        }
        if (current && typeof current === 'object' && '_value' in current) {
            return current._value;
        }
        if (current && typeof current === 'object' && current.hasOwnProperty('_value')) {
            return current._value;
        }
        return current;
    } catch (e) {
        return null;
    }
}

// Standard paths for RX Power
const RX_POWER_PATHS = [
    'VirtualParameters.RXPower',
    'VirtualParameters.RXpower',
    'VirtualParameters.rx_power',
    'VirtualParameters.redaman',
    'InternetGatewayDevice.WANDevice.1.WANPONInterfaceConfig.RXPower',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANOAM.RXPower',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.X_HW_OpticalSignal.RXPower',
    'InternetGatewayDevice.WANDevice.1.X_GponInterfaceConfig.RXPower',
    'InternetGatewayDevice.WANDevice.1.X_GponInterfaceConfig.RxPower',
    'InternetGatewayDevice.WANDevice.1.X_GponInterafceConfig.RXPower',
    'InternetGatewayDevice.WANDevice.1.X_GponInterafceConfig.RxPower',
    'InternetGatewayDevice.WANDevice.1.X_ZTE_GponInterfaceConfig.RXPower',
    'InternetGatewayDevice.WANDevice.1.X_ZTE_GponInterfaceConfig.RxPower',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.X_ZTE_OpticalSignal.RXPower',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.X_ZTE_OpticalSignal.RxPower',
    'InternetGatewayDevice.WANDevice.1.X_HW_GponInterfaceConfig.RXPower',
    'InternetGatewayDevice.WANDevice.1.X_HW_GponInterfaceConfig.RxPower',
    'InternetGatewayDevice.WANDevice.1.X_ZTE-COM_WANPONInterfaceConfig.RXPower',
    'InternetGatewayDevice.WANDevice.1.X_FH_GponInterfaceConfig.RXPower',
    'InternetGatewayDevice.WANDevice.1.X_CMCC_EponInterfaceConfig.RXPower',
    'InternetGatewayDevice.WANDevice.1.X_CMCC_GponInterfaceConfig.RXPower',
    'InternetGatewayDevice.WANDevice.1.X_CT-COM_EponInterfaceConfig.RXPower',
    'InternetGatewayDevice.WANDevice.1.X_CT-COM_GponInterfaceConfig.RXPower',
    'InternetGatewayDevice.WANDevice.1.X_CU_WANEPONInterfaceConfig.OpticalTransceiver.RXPower',
    'Device.Optical.Interface.1.OpticalSignalLevel',
    'Device.XPON.Interface.1.Stats.RXPower',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANDSLDiagnostics.FECOutput' // some devices
];

// PPPoE IP search keys matching user's template
const PPPOE_IP_KEYS = [
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANPPPConnection.1.ExternalIPAddress',
    'InternetGatewayDevice.WANDevice.*.WANConnectionDevice.1.WANPPPConnection.2.ExternalIPAddress',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.2.WANPPPConnection.1.ExternalIPAddress',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.2.WANPPPConnection.2.ExternalIPAddress',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.3.WANPPPConnection.1.ExternalIPAddress',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.4.WANPPPConnection.1.ExternalIPAddress',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.5.WANPPPConnection.1.ExternalIPAddress',
    'InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANPPPConnection.*.ExternalIPAddress',
    'Device.PPP.Interface.1.ExternalIPAddress',
    'Device.IP.Interface.1.IPv4Address.1.IPAddress'
];

// PPPoE Username search keys matching user's template
const PPPOE_USER_KEYS = [
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANPPPConnection.1.Username',
    'InternetGatewayDevice.WANDevice.*.WANConnectionDevice.1.WANPPPConnection.2.Username',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.2.WANPPPConnection.1.Username',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.2.WANPPPConnection.2.Username',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.3.WANPPPConnection.1.Username',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.3.WANPPPConnection.2.Username',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.4.WANPPPConnection.1.Username',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.4.WANPPPConnection.2.Username',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.5.WANPPPConnection.1.Username',
    'InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANPPPConnection.*.Username',
    'Device.PPP.Interface.1.Username',
    'Device.PPP.Interface.2.Username',
    'Device.PPP.Interface.3.Username'
];

function getWildcardMatches(device, path) {
    const parts = path.split('.');
    const results = [];

    function recurse(current, index, currentPathParts) {
        if (current === undefined || current === null) return;
        
        if (index === parts.length) {
            let val = current;
            if (typeof current === 'object' && '_value' in current) {
                val = current._value;
            }
            results.push({
                path: currentPathParts.join('.'),
                value: val
            });
            return;
        }

        const part = parts[index];
        if (part === '*') {
            if (typeof current === 'object') {
                for (const key of Object.keys(current)) {
                    if (!key.startsWith('_')) {
                        recurse(current[key], index + 1, [...currentPathParts, key]);
                    }
                }
            }
        } else {
            if (typeof current === 'object') {
                const targetLower = part.toLowerCase();
                for (const key of Object.keys(current)) {
                    if (key.toLowerCase() === targetLower) {
                        recurse(current[key], index + 1, [...currentPathParts, key]);
                    }
                }
            }
        }
    }

    recurse(device, 0, []);
    return results;
}

function getDeviceParameterValue(device, keys, filterFn) {
    for (const key of keys) {
        const matches = getWildcardMatches(device, key);
        for (const match of matches) {
            if (filterFn) {
                if (filterFn(match.path, match.value, device)) {
                    return match.value;
                }
            } else if (match.value !== undefined && match.value !== null && match.value !== '') {
                return match.value;
            }
        }
    }
    return '';
}

function extractPppoeIp(d) {
    const ip = getDeviceParameterValue(d, PPPOE_IP_KEYS, (matchedPath, value, device) => {
        if (!value || value === '0.0.0.0' || value === '-') return false;
        
        if (matchedPath.includes('WANPPPConnection.')) {
            const connectionTypePath = matchedPath.replace('ExternalIPAddress', 'ConnectionType');
            const connTypeMatches = getWildcardMatches(device, connectionTypePath);
            if (connTypeMatches.length > 0 && connTypeMatches[0].value === 'bridge') {
                return false;
            }
        }
        return true;
    });
    
    if (ip) return ip;
    if (d._ip && d._ip !== '-' && d._ip !== '0.0.0.0') return d._ip;
    return '-';
}

function extractPppoeUser(d) {
    const user = getDeviceParameterValue(d, PPPOE_USER_KEYS, (matchedPath, value, device) => {
        if (!value || value === '-') return false;
        
        if (matchedPath.includes('WANPPPConnection.')) {
            const connectionTypePath = matchedPath.replace('Username', 'ConnectionType');
            const connTypeMatches = getWildcardMatches(device, connectionTypePath);
            if (connTypeMatches.length > 0 && connTypeMatches[0].value === 'PPPoE_Bridged') {
                return false;
            }
        }
        return true;
    });
    
    return user || '-';
}

function formatUptime(seconds) {
    if (!seconds || seconds === 'N/A' || seconds === '-') return seconds || '-';
    if (typeof seconds === 'string' && (seconds.includes('d') || seconds.includes(':')) && isNaN(seconds)) {
        return seconds;
    }
    const totalSecs = parseInt(seconds, 10);
    if (isNaN(totalSecs)) return seconds || '-';
    const days = Math.floor(totalSecs / 86400);
    const rem = totalSecs % 86400;
    let hrs = Math.floor(rem / 3600);
    if (hrs < 10) hrs = "0" + hrs;
    const rem2 = rem % 3600;
    let mins = Math.floor(rem2 / 60);
    if (mins < 10) mins = "0" + mins;
    let secs = rem2 % 60;
    if (secs < 10) secs = "0" + secs;
    return days + "d " + hrs + ":" + mins + ":" + secs;
}

const PPPOE_UPTIME_KEYS = [
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANPPPConnection.1.Uptime',
    'InternetGatewayDevice.WANDevice.*.WANConnectionDevice.1.WANPPPConnection.2.Uptime',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.2.WANPPPConnection.1.Uptime',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.2.WANPPPConnection.2.Uptime',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.3.WANPPPConnection.1.Uptime',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.4.WANPPPConnection.1.Uptime',
    'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.5.WANPPPConnection.1.Uptime',
    'InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANPPPConnection.*.Uptime',
    'Device.PPP.Interface.1.UpTime'
];

function extractPppoeUptime(d) {
    let uptimeVal = getDeviceParameterValue(d, PPPOE_UPTIME_KEYS, (matchedPath, value, device) => {
        if (value === undefined || value === null || value === '' || value === '-') return false;
        
        if (matchedPath.toLowerCase().includes('wanpppconnection')) {
            const connTypePath = matchedPath.substring(0, matchedPath.toLowerCase().lastIndexOf('.uptime')) + '.ConnectionType';
            const connTypeMatches = getWildcardMatches(device, connTypePath);
            if (connTypeMatches.length > 0 && connTypeMatches[0].value === 'PPPoE_Bridged') {
                return false;
            }
        }
        return true;
    });

    if (!uptimeVal || uptimeVal === '-') {
        const UPTIME_PATHS = [
            'VirtualParameters.getdeviceuptime',
            'InternetGatewayDevice.DeviceInfo.UpTime',
            'Device.DeviceInfo.UpTime'
        ];
        for (const path of UPTIME_PATHS) {
            const val = getNestedValue(d, path);
            if (val && val !== '-' && val !== '') {
                uptimeVal = val;
                break;
            }
        }
    }

    if (uptimeVal) {
        return formatUptime(uptimeVal);
    }
    return '-';
}

function formatRxPower(val) {
    if (val === undefined || val === null || val === '-' || val === '') return '-';
    const num = parseFloat(val);
    if (isNaN(num)) return val;
    if (num > 0) {
        const dbVal = 30 + (Math.log10(num * Math.pow(10, -7)) * 10);
        return (Math.ceil(dbVal * 100) / 100).toFixed(2);
    }
    return String(num);
}

function extractRxPower(d) {
    let rxPower = '-';
    for (const path of RX_POWER_PATHS) {
        const val = getNestedValue(d, path);
        if (val && val !== '-') {
            rxPower = val;
            break;
        }
    }
    return formatRxPower(rxPower);
}

function extractSsid(d) {
    const SSID_PATHS = [
        'InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID',
        'Device.WiFi.SSID.1.SSID',
        'Device.WiFi.SSID.2.SSID'
    ];
    for (const path of SSID_PATHS) {
        const val = getNestedValue(d, path);
        if (val && val !== '-' && val !== '') return val;
    }
    return '-';
}

function extractSoftwareVersion(d) {
    const SW_PATHS = [
        'InternetGatewayDevice.DeviceInfo.SoftwareVersion',
        'Device.DeviceInfo.SoftwareVersion'
    ];
    for (const path of SW_PATHS) {
        const val = getNestedValue(d, path);
        if (val && val !== '-' && val !== '') return val;
    }
    return '-';
}

function extractUptime(d) {
    const UPTIME_PATHS = [
        'VirtualParameters.getdeviceuptime',
        'InternetGatewayDevice.DeviceInfo.UpTime',
        'Device.DeviceInfo.UpTime'
    ];
    for (const path of UPTIME_PATHS) {
        const val = getNestedValue(d, path);
        if (val && val !== '-' && val !== '') {
            if (typeof val === 'string' && (val.includes('d') || val.includes(':')) && isNaN(val)) {
                return val;
            }
            const totalSecs = parseInt(val, 10);
            if (isNaN(totalSecs)) return val;
            const days = Math.floor(totalSecs / 86400);
            const rem = totalSecs % 86400;
            
            let hrs = Math.floor(rem / 3600);
            if (hrs < 10) hrs = "0" + hrs;
            
            const rem2 = rem % 3600;
            let mins = Math.floor(rem2 / 60);
            if (mins < 10) mins = "0" + mins;
            
            let secs = rem2 % 60;
            if (secs < 10) secs = "0" + secs;
            
            return days + "d " + hrs + ":" + mins + ":" + secs;
        }
    }
    return '-';
}

// Middleware: Require Admin Session
const requireAdmin = (req, res, next) => {
    if (req.session && req.session.isAdmin) {
        return next();
    }
    res.status(403).json({ success: false, message: 'Forbidden' });
};

const requireAdminSession = (req, res, next) => {
    if (req.session && req.session.isAdmin) {
        return next();
    }
    res.redirect('/admin/login');
};

function company() { return getSetting('company_header', 'ISP Admin'); }

function requireSidebarMenuAccess(menuKey) {
    return (req, res, next) => {
        const access = sidebarMenuSvc.evaluateMenuAccess(menuKey, req.session);
        if (access.allowed) return next();

        if (access.reason === 'hidden') {
            req.session._msg = { type: 'error', text: `Menu "${access.menu.labelDefault}" sedang disembunyikan dari sidebar.` };
            return res.redirect('/admin');
        }

        if (access.reason === 'locked') {
            req.session._msg = { type: 'error', text: `Menu "${access.menu.labelDefault}" terkunci. Hubungi ${sidebarMenuSvc.getFeatureContactPhone()} untuk mendapatkan password.` };
            return res.redirect('/admin/sidebar-settings');
        }

        req.session._msg = { type: 'error', text: 'Anda tidak memiliki akses ke menu ini.' };
        return res.redirect('/admin');
    };
}

router.use((req, res, next) => {
    res.locals.session = req.session;
    res.locals.sidebarSections = sidebarMenuSvc.getSidebarSections(req.session);
    res.locals.sidebarBottomNavItems = sidebarMenuSvc.getBottomNavItems(req.session);
    res.locals.settings = getSettings();
    res.locals.company = company();
    next();
});

router.use(requireAdminSession, requireSidebarMenuAccess('acs_pro'));

async function getLANHosts(deviceId, serverConfig) {
    try {
        const baseUrl = normalizeUrl(serverConfig.url);
        const [hostsResponse, wifiResponse] = await Promise.all([
            axios.get(`${baseUrl}/devices/`, {
                ...getAxiosConfig(serverConfig),
                params: {
                    query: JSON.stringify({ _id: deviceId }),
                    projection: 'InternetGatewayDevice.LANDevice.1.Hosts'
                }
            }).catch(() => ({ data: [] })),
            axios.get(`${baseUrl}/devices/`, {
                ...getAxiosConfig(serverConfig),
                params: {
                    query: JSON.stringify({ _id: deviceId }),
                    projection: 'InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.AssociatedDevice,InternetGatewayDevice.LANDevice.1.WLANConfiguration.5.AssociatedDevice'
                }
            }).catch(() => ({ data: [] }))
        ]);

        const device = Array.isArray(hostsResponse.data) && hostsResponse.data.length > 0 ? hostsResponse.data[0] : null;
        if (!device) return [];

        const hostsData = device.InternetGatewayDevice?.LANDevice?.['1']?.Hosts;
        if (!hostsData) return [];

        let hostArray = [];
        if (hostsData.Host) {
            if (Array.isArray(hostsData.Host)) {
                hostArray = hostsData.Host;
            } else if (typeof hostsData.Host === 'object') {
                hostArray = Object.values(hostsData.Host).filter(v => v && typeof v === 'object');
            }
        }

        const wifiRssiMap = new Map();
        const wifiDevice = Array.isArray(wifiResponse.data) && wifiResponse.data.length > 0 ? wifiResponse.data[0] : null;
        if (wifiDevice) {
            const wlanConfig = wifiDevice.InternetGatewayDevice?.LANDevice?.['1']?.WLANConfiguration;
            if (wlanConfig) {
                for (const bandKey of ['1', '5']) {
                    const band = wlanConfig[bandKey];
                    if (!band || !band.AssociatedDevice) continue;

                    let devArray = [];
                    if (Array.isArray(band.AssociatedDevice)) {
                        devArray = band.AssociatedDevice;
                    } else if (typeof band.AssociatedDevice === 'object') {
                        devArray = Object.values(band.AssociatedDevice).filter(v => v && typeof v === 'object');
                    }

                    const bandLabel = bandKey === '5' ? '5GHz' : '2.4GHz';
                    devArray.forEach(dev => {
                        const mac = dev.AssociatedDeviceMACAddress?._value || dev.MACAddress?._value || null;
                        const rssi = dev.X_HW_RSSI?._value || dev.SignalStrength?._value || null;
                        const rate = dev.LastDataTransmitRate?._value || dev.X_HW_TxRate?._value || null;

                        if (mac) {
                            wifiRssiMap.set(mac.toString().toLowerCase(), {
                                rssi: rssi !== null ? parseInt(rssi) : null,
                                rate: rate,
                                band: bandLabel
                            });
                        }
                    });
                }
            }
        }

        return hostArray.map((host, index) => {
            const getHostVal = (key) => {
                const val = host[key];
                if (val && typeof val === 'object' && '_value' in val) return val._value;
                return val;
            };

            const mac = getHostVal('MACAddress') || '-';
            const ip = getHostVal('IPAddress') || '-';
            const hostname = getHostVal('HostName') || 'Unknown';
            const activeRaw = getHostVal('Active');
            const interfaceType = getHostVal('InterfaceType') || '';
            const layer2Interface = getHostVal('Layer2Interface') || '';
            
            let bytesReceived = 0;
            let bytesSent = 0;
            const stats = host['X_HW_Stats'];
            if (stats && typeof stats === 'object') {
                bytesReceived = parseInt(stats.BytesReceived?._value || stats.BytesReceived || 0);
                bytesSent = parseInt(stats.BytesSent?._value || stats.BytesSent || 0);
            }

            const l2Str = layer2Interface.toString().toLowerCase();
            const isWiFi = interfaceType.toString().toLowerCase().includes('802.11') || l2Str.includes('wlan') || l2Str.includes('wifi');
            
            let finalRssi = null;
            let band = l2Str.includes('5') ? '5GHz' : '2.4GHz';
            const macLower = mac.toString().toLowerCase();

            if (isWiFi && wifiRssiMap.has(macLower)) {
                const wifiInfo = wifiRssiMap.get(macLower);
                finalRssi = wifiInfo.rssi;
                band = wifiInfo.band;
            }

            return {
                index: index + 1,
                mac, ip, hostname,
                active: activeRaw === true || activeRaw === 'true' || activeRaw === 1,
                isWiFi, band, rssi: finalRssi,
                bytesReceived, bytesSent
            };
        });
    } catch (err) {
        console.error(`[getLANHosts] Error:`, err.message);
        return [];
    }
}

// ============================================
// DEVICE FETCH HELPERS
// ============================================

async function fetchDevicesFromACS(server, vParams = [], paths = {}, options = {}) {
    const { page = 1, limit = null } = options;
    try {
        const baseUrl = normalizeUrl(server.url);
        // Gabungkan proyeksi dasar dengan path pencarian
        let projection = '_id,_lastInform,_ip,_deviceId._Manufacturer,_deviceId._ProductClass,_deviceId._SerialNumber,VirtualParameters,InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1';
        
        const params = { projection };
        if (limit !== null) {
            params.limit = limit + 1;
            params.skip = (page - 1) * limit;
        }

        const response = await axios.get(`${baseUrl}/devices`, {
            ...getAxiosConfig(server),
            params
        });

        if (!Array.isArray(response.data)) return { server, devices: [], hasMore: false };

        const hasMore = limit !== null && response.data.length > limit;
        const devicesData = hasMore ? response.data.slice(0, limit) : response.data;

        const devices = devicesData.map(d => {
            // Fallback PPPoE
            let pppoeUser = extractPppoeUser(d);

            // Fallback RX Power
            let rxPower = extractRxPower(d);

            // Fallback IP
            let ip = extractPppoeIp(d);

            // Customer Name
            const customerName = getNestedValue(d, 'VirtualParameters.CustomerName') || 
                                getNestedValue(d, 'VirtualParameters.customer_name') || 
                                '-';

            return {
                id: d._id,
                sn: d._deviceId?._SerialNumber || d._id,
                last_inform: d._lastInform,
                isOnline: d._lastInform ? (Date.now() - new Date(d._lastInform).getTime() < 900000) : false,
                manufacturer: d._deviceId?._Manufacturer || '-',
                model: d._deviceId?._ProductClass || '-',
                customer_name: customerName,
                rx_power: rxPower,
                pppoe_user: pppoeUser,
                ip: ip,
                acs_server_name: server.name,
                acs_server_id: server.id
            };
        });

        return { server, devices, hasMore };
    } catch (err) {
        console.error(`[fetchDevicesFromACS] Error on ${server.name}:`, err.message);
        return { server, devices: [], hasMore: false, error: err.message };
    }
}

// ============================================
// ROUTES
// ============================================

router.get('/', async (req, res) => {
    try {
        const searchQuery = String(req.query.q || '').trim() || null;
        const acsServers = getACSServers();
        const legacyACS = getLegacyACS();
        
        const activeServers = acsServers.length > 0 ? acsServers :
            (legacyACS.acs_url ? [{ id: 'legacy', name: 'Default ACS', url: legacyACS.acs_url, username: legacyACS.acs_user, password: legacyACS.acs_pass }] : []);

        const selectedAcsId = req.query.acs || (activeServers[0]?.id);
        const targetServers = selectedAcsId && selectedAcsId !== 'all' ? activeServers.filter(s => String(s.id) === String(selectedAcsId)) : activeServers;

        let allDevices = [];
        if (targetServers.length > 0) {
            if (searchQuery) {
                // Search mode: query devices with search filter
                const query = JSON.stringify({
                    $or: [
                        { '_deviceId._SerialNumber': { $regex: searchQuery, $options: 'i' } },
                        { 'VirtualParameters.CustomerName': { $regex: searchQuery, $options: 'i' } },
                        { 'VirtualParameters.customer_name': { $regex: searchQuery, $options: 'i' } },
                        { 'VirtualParameters.PPPoEUser': { $regex: searchQuery, $options: 'i' } },
                        { '_tags': searchQuery }
                    ]
                });
                
                for (const server of targetServers) {
                    try {
                        const baseUrl = normalizeUrl(server.url);
                        const response = await axios.get(`${baseUrl}/devices`, {
                            ...getAxiosConfig(server),
                            params: { query }
                        });
                        
                        if (Array.isArray(response.data)) {
                            const devices = response.data.map(d => {
                                 let rxPower = extractRxPower(d);
                                
                                let pppoeUser = extractPppoeUser(d);
                                
                                let ip = extractPppoeIp(d);
                                
                                const customerName = getNestedValue(d, 'VirtualParameters.CustomerName') ||
                                                    getNestedValue(d, 'VirtualParameters.customer_name') || '-';
                                
                                return {
                                    id: d._id,
                                    sn: d._deviceId?._SerialNumber || d._id,
                                    last_inform: d._lastInform,
                                    isOnline: d._lastInform ? (Date.now() - new Date(d._lastInform).getTime() < 900000) : false,
                                    manufacturer: d._deviceId?._Manufacturer || '-',
                                    model: d._deviceId?._ProductClass || '-',
                                    rx_power: rxPower,
                                    pppoe_ip: ip,
                                    pppoe_user: pppoeUser,
                                    customer_name: customerName,
                                    acs_server_id: server.id,
                                    acs_server_name: server.name
                                };
                            });
                            allDevices = allDevices.concat(devices);
                        }
                    } catch (err) {
                        console.error(`Search error on server ${server.name}:`, err.message);
                    }
                }
            } else {
                // Normal mode: fetch all devices
                const results = await Promise.allSettled(targetServers.map(s => fetchDevicesFromACS(s, [], legacyACS)));
                results.forEach(r => { if (r.status === 'fulfilled') allDevices = allDevices.concat(r.value.devices); });
            }
        }

        let pppoeProfiles = [];
        try {
            pppoeProfiles = await mikrotikSvc.getPppoeProfiles();
        } catch (e) {
            console.error('Failed to load PPPoE profiles from MikroTik:', e.message);
        }

        res.render('admin/acs', {
            user: req.session,
            devices: allDevices,
            acsServers: activeServers,
            selectedAcsId,
            searchQuery,
            pppoeProfiles,
            currentPage: 'acs_pro'
        });
    } catch (err) {
        console.error('ACS page error:', err);
        res.render('admin/acs', { user: req.session, devices: [], acsServers: [], selectedAcsId: null, searchQuery: null, pppoeProfiles: [], currentPage: 'acs_pro' });
    }
});

router.get('/device/:deviceId', async (req, res) => {
    try {
        const acsId = String(req.query.acsId || req.query.acs || '').trim() || null;
        const deviceToken = String(req.params.deviceId || '');

        const legacyData = await customerDevice.getCustomerDeviceData(deviceToken);
        if (legacyData && legacyData.phone) {
            const isOnline = String(legacyData.status || '').toLowerCase() === 'online';
            const clients = Array.isArray(legacyData.connectedUsers) ? legacyData.connectedUsers : [];
            return res.render('admin/acs_device', {
                user: req.session,
                device: legacyData,
                clients,
                isOnline,
                acsId: acsId || 'legacy',
                acsName: 'Default ACS',
                currentPage: 'acs_pro'
            });
        }

        const servers = getACSServers(acsId);
        if (servers.length === 0) return res.status(404).send('ACS Server not found');

        const server = servers[0];
        const baseUrl = normalizeUrl(server.url);
        const deviceId = deviceToken;

        const response = await axios.get(`${baseUrl}/devices`, {
            ...getAxiosConfig(server),
            params: {
                query: JSON.stringify({ _id: deviceId }),
                projection: '_id,_lastInform,_deviceId,_registered,_ip,_tags,_events,VirtualParameters,InternetGatewayDevice'
            }
        });

        const deviceData = Array.isArray(response.data) && response.data.length > 0 ? response.data[0] : null;
        if (!deviceData) return res.status(404).send('Device not found');

        const lastInform = deviceData._lastInform;
        const isOnline = lastInform ? (Date.now() - new Date(lastInform).getTime() < 900000) : false;

        // Fallbacks for detail page using the same logic as listing
        let rxPower = extractRxPower(deviceData);

        let pppoeUser = extractPppoeUser(deviceData);

        const customerName = getNestedValue(deviceData, 'VirtualParameters.CustomerName') || 
                            getNestedValue(deviceData, 'VirtualParameters.customer_name') || 
                            '-';

        let ip = extractPppoeIp(deviceData);

        const rawClients = await getLANHosts(deviceData._id, server);
        const clients = (Array.isArray(rawClients) ? rawClients : []).map((c) => ({
            hostname: c.hostname || 'Unknown',
            ip: c.ip || '-',
            mac: c.mac || '-',
            iface: c.isWiFi ? `WiFi ${c.band || ''}`.trim() : 'LAN',
            status: c.active ? 'Online' : 'Offline',
            rssi: typeof c.rssi === 'number' ? c.rssi : null
        }));

        res.render('admin/acs_device', {
            user: req.session,
            device: {
                phone: deviceData._id,
                serialNumber: deviceData._deviceId?._SerialNumber || deviceData._id,
                model: deviceData._deviceId?._ProductClass || '-',
                softwareVersion: extractSoftwareVersion(deviceData),
                status: isOnline ? 'Online' : 'Offline',
                lastInform: lastInform || null,
                rxPower: rxPower,
                pppoeIP: ip,
                pppoeUsername: pppoeUser,
                pppoeUptime: extractPppoeUptime(deviceData),
                ssid: extractSsid(deviceData),
                uptime: extractUptime(deviceData)
            },
            clients,
            isOnline,
            acsId: server.id,
            acsName: server.name,
            currentPage: 'acs_pro'
        });
    } catch (err) {
        res.status(500).send(err.message);
    }
});

// POST /admin/acs/api/servers
router.post('/api/servers', requireAdmin, async (req, res) => {
    const { name, url, username, password, location } = req.body;
    try {
        db.prepare(
            'INSERT INTO genieacs_servers (name, url, username, password, location) VALUES (?, ?, ?, ?, ?)'
        ).run(name, url, username || null, password || null, location || '');
        res.json({ success: true, message: 'ACS server added' });
    } catch (e) {
        res.status(500).json({ success: false, message: e.message });
    }
});

// PUT /admin/acs/api/servers/legacy (Default ACS)
router.put('/api/servers/legacy', requireAdmin, express.json(), async (req, res) => {
    try {
        const url = String(req.body?.url || '').trim();
        if (!url) return res.status(400).json({ success: false, message: 'URL wajib diisi' });
        if (!/^https?:\/\//i.test(url)) return res.status(400).json({ success: false, message: 'URL harus diawali http:// atau https://' });

        const clearUsername = Boolean(req.body?.clear_username);
        const clearPassword = Boolean(req.body?.clear_password);
        const usernameInput = String(req.body?.username || '').trim();
        const passwordInput = String(req.body?.password || '');

        const currentSettings = getSettings();
        currentSettings.genieacs_url = url;

        if (clearUsername) currentSettings.genieacs_username = '';
        else if (usernameInput) currentSettings.genieacs_username = usernameInput;

        if (clearPassword) currentSettings.genieacs_password = '';
        else if (String(passwordInput || '').trim()) currentSettings.genieacs_password = String(passwordInput || '');

        const settingsPath = path.join(__dirname, '../settings.json');
        fs.writeFileSync(settingsPath, JSON.stringify(currentSettings, null, 2), 'utf8');

        res.json({ success: true, message: 'Default ACS berhasil diperbarui.' });
    } catch (e) {
        res.status(500).json({ success: false, message: e.message });
    }
});

// PUT /admin/acs/api/servers/:id
router.put('/api/servers/:id', requireAdmin, async (req, res) => {
    try {
        const id = String(req.params.id || '').trim();
        if (!id) return res.status(400).json({ success: false, message: 'Invalid server id' });

        const name = String(req.body?.name || '').trim();
        const url = String(req.body?.url || '').trim();
        if (!name || !url) return res.status(400).json({ success: false, message: 'Name and URL are required' });

        const existing = db.prepare('SELECT id, password FROM genieacs_servers WHERE id = ?').get(id);
        if (!existing) return res.status(404).json({ success: false, message: 'ACS server not found' });

        const usernameRaw = req.body?.username;
        const passwordRaw = req.body?.password;
        const location = String(req.body?.location || '');

        const clearUsername = Boolean(req.body?.clear_username);
        const clearPassword = Boolean(req.body?.clear_password);

        const username = clearUsername ? null : (String(usernameRaw || '').trim() || null);

        let password = existing.password || null;
        if (clearPassword) password = null;
        else if (String(passwordRaw || '').trim()) password = String(passwordRaw || '');

        db.prepare(
            'UPDATE genieacs_servers SET name = ?, url = ?, username = ?, password = ?, location = ? WHERE id = ?'
        ).run(name, url, username, password, location, id);

        res.json({ success: true, message: 'ACS server updated' });
    } catch (e) {
        res.status(500).json({ success: false, message: e.message });
    }
});

// DELETE /admin/acs/api/servers/:id
router.delete('/api/servers/:id', requireAdmin, async (req, res) => {
    try {
        db.prepare('DELETE FROM genieacs_servers WHERE id = ?').run(req.params.id);
        res.json({ success: true, message: 'ACS server deleted' });
    } catch (e) {
        res.status(500).json({ success: false, message: e.message });
    }
});

// DELETE /admin/acs/api/device/:deviceId
router.delete('/api/device/:deviceId', requireAdmin, async (req, res) => {
    try {
        const { acsId } = req.body;
        const servers = getACSServers(acsId);
        if (servers.length === 0) return res.json({ success: false, message: 'ACS not found' });
        
        const server = servers[0];
        const baseUrl = normalizeUrl(server.url);
        const deviceId = String(req.params.deviceId || '');
        
        await axios.delete(
            `${baseUrl}/devices/${encodeURIComponent(deviceId)}`,
            getAxiosConfig(server)
        );
        res.json({ success: true, message: 'Device deleted' });
    } catch (e) {
        res.json({ success: false, message: e.message });
    }
});

// POST /admin/acs/api/remote-enable/:deviceId
router.post('/api/remote-enable/:deviceId', requireAdmin, async (req, res) => {
    try {
        const { acsId } = req.body;
        const servers = getACSServers(acsId);
        if (servers.length === 0) return res.json({ success: false, message: 'ACS not found' });
        
        const server = servers[0];
        const baseUrl = normalizeUrl(server.url);
        const deviceId = String(req.params.deviceId || '');
        
        await axios.post(
            `${baseUrl}/devices/${encodeURIComponent(deviceId)}/tasks`,
            { 
                name: 'setParameterValues',
                parameterValues: [['InternetGatewayDevice.X_HW_Security.AclServices.HTTPWanEnable', true, 'xsd:boolean']]
            },
            { ...getAxiosConfig(server), timeout: 10000 }
        );
        res.json({ success: true, message: 'Remote WAN enabled' });
    } catch (e) {
        res.json({ success: false, message: e.message });
    }
});

// POST /admin/acs/api/reboot/:deviceId
router.post('/api/reboot/:deviceId', requireAdmin, async (req, res) => {
    try {
        const { acsId } = req.body;
        const servers = getACSServers(acsId);
        if (servers.length === 0) return res.json({ success: false, message: 'ACS not found' });
        
        const server = servers[0];
        const baseUrl = normalizeUrl(server.url);
        const deviceId = String(req.params.deviceId || '');
        
        await axios.post(
            `${baseUrl}/devices/${encodeURIComponent(deviceId)}/tasks`,
            { name: 'reboot' },
            { ...getAxiosConfig(server), timeout: 10000 }
        );
        res.json({ success: true, message: 'Reboot command sent' });
    } catch (e) {
        res.json({ success: false, message: e.message });
    }
});

// POST /admin/acs/api/refresh/:deviceId
router.post('/api/refresh/:deviceId', requireAdmin, async (req, res) => {
    try {
        const { acsId } = req.body;
        const servers = getACSServers(acsId);
        if (servers.length === 0) return res.json({ success: false, message: 'ACS not found' });
        
        const server = servers[0];
        const deviceId = String(req.params.deviceId || '');
        
        if (isBuiltinAcsEnabled() && (server.id === 'builtin' || server.url === 'local')) {
            // Built-in ACS: Clear bootstrapped tag and trigger connection request to force rebuild parameter database
            const device = db.prepare('SELECT tags FROM acs_devices WHERE id = ?').get(deviceId);
            if (device) {
                let tags = [];
                try { tags = JSON.parse(device.tags || '[]'); } catch (_) {}
                tags = tags.filter(t => t !== 'bootstrapped');
                
                const now = new Date().toISOString();
                db.prepare('UPDATE acs_devices SET tags = ?, updated_at = ? WHERE id = ?')
                  .run(JSON.stringify(tags), now, deviceId);
            }
            
            // Trigger connection request asynchronously
            const acsService = require('../services/acsServerService');
            acsService.triggerConnectionRequest(deviceId).catch(() => {});
            
            return res.json({ success: true, message: 'Sinkronisasi ulang dimulai (Bootstrap reset)' });
        }
        
        const baseUrl = normalizeUrl(server.url);
        await axios.post(
            `${baseUrl}/devices/${encodeURIComponent(deviceId)}/tasks`,
            { name: 'refreshObject', objectName: '' },
            { ...getAxiosConfig(server), timeout: 10000 }
        );
        res.json({ success: true, message: 'Refresh task queued' });
    } catch (e) {
        res.json({ success: false, message: e.message });
    }
});

// POST /admin/acs/api/sync/all
router.post('/api/sync/all', requireAdmin, async (req, res) => {
    try {
        const servers = getACSServers();
        if (servers.length === 0) return res.json({ success: true, message: 'No servers to sync' });
        
        let total = 0;
        for (const s of servers) {
            const result = await fetchDevicesFromACS(s, [], {});
            total += result.devices.length;
            db.prepare('UPDATE genieacs_servers SET device_count = ?, last_sync = (NOW_LOCAL()) WHERE id = ?').run(result.devices.length, s.id);
        }
        res.json({ success: true, message: `Sync complete. Total ${total} devices.` });
    } catch (e) {
        res.json({ success: false, message: e.message });
    }
});

// GET /api/clients/:deviceId
router.get('/api/clients/:deviceId', requireAdmin, async (req, res) => {
    try {
        const { deviceId } = req.params;
        const { acsId } = req.query;
        const servers = getACSServers(acsId);
        if (servers.length === 0) return res.json({ success: false });

        const hosts = await getLANHosts(String(deviceId || ''), servers[0]);
        res.json({ success: true, data: hosts });
    } catch (err) {
        res.json({ success: false, error: err.message });
    }
});

// GET /admin/acs/api/wifi-settings/:deviceId
router.get('/api/wifi-settings/:deviceId', requireAdmin, async (req, res) => {
    try {
        const { deviceId } = req.params;
        const { acsId } = req.query;
        const servers = getACSServers(acsId);
        if (servers.length === 0) return res.status(404).json({ success: false, message: 'ACS Server not found' });
        
        const server = servers[0];
        const baseUrl = normalizeUrl(server.url);
        
        const response = await axios.get(`${baseUrl}/devices`, {
            ...getAxiosConfig(server),
            params: {
                query: JSON.stringify({ _id: deviceId }),
                projection: 'InternetGatewayDevice.LANDevice.1.WLANConfiguration'
            }
        });
        
        const deviceData = Array.isArray(response.data) && response.data.length > 0 ? response.data[0] : null;
        if (!deviceData) return res.status(404).json({ success: false, message: 'Device not found' });
        
        const wlanConfig = deviceData.InternetGatewayDevice?.LANDevice?.['1']?.WLANConfiguration || {};
        const bands = [];
        
        // Return all SSID indices (1 to 8) that exist on the ONU
        for (let i = 1; i <= 8; i++) {
            if (wlanConfig[String(i)]) {
                bands.push({
                    index: String(i),
                    ssid: getNestedValue(wlanConfig[String(i)], 'SSID') || `SSID ${i}`,
                    name: i <= 4 ? `Wi-Fi 2.4GHz (SSID ${i})` : `Wi-Fi 5GHz (SSID ${i})`
                });
            }
        }
        
        res.json({ success: true, bands });
    } catch (err) {
        res.status(500).json({ success: false, error: err.message });
    }
});

// POST /admin/acs/api/add-wan/:deviceId
router.post('/api/add-wan/:deviceId', requireAdmin, async (req, res) => {
    try {
        const { deviceId } = req.params;
        const {
            acsId,
            mode,
            vlanId,
            pppoeUser,
            pppoePass,
            pppoeProfile,
            autoCreateMikrotik,
            lanPorts,
            wlanSsids,
            configureWifi,
            wifiSsid24,
            wifiPass24,
            wifiSsid5,
            wifiPass5,
            dhcp
        } = req.body;
        
        // 1. Validasi awal
        const parsedVlan = parseInt(vlanId);
        if (isNaN(parsedVlan) || parsedVlan < 1 || parsedVlan > 4094) {
            return res.json({ success: false, message: 'VLAN ID tidak valid (harus 1-4094)' });
        }
        
        if (mode === 'pppoe' && (!pppoeUser || !pppoePass)) {
            return res.json({ success: false, message: 'Username dan password PPPoE wajib diisi untuk mode PPPoE' });
        }
        
        const servers = getACSServers(acsId);
        if (servers.length === 0) return res.json({ success: false, message: 'ACS Server tidak ditemukan' });
        
        const server = servers[0];
        const baseUrl = normalizeUrl(server.url);
        const config = getAxiosConfig(server);
        
        // 2. Jika Auto-create MikroTik diaktifkan
        if (mode === 'pppoe' && (autoCreateMikrotik === true || autoCreateMikrotik === 'true')) {
            try {
                await mikrotikSvc.createPppoeSecret({
                    username: pppoeUser,
                    password: pppoePass,
                    profile: pppoeProfile || 'default'
                });
            } catch (mErr) {
                console.error('[AddWAN] Failed to create PPPoE Secret in MikroTik:', mErr.message);
                return res.json({ success: false, message: `Gagal membuat akun PPPoE di MikroTik: ${mErr.message}` });
            }
        }
        
        // 3. Ambil data instansi WANConnectionDevice saat ini untuk menghitung nextInstance
        const getDeviceRes = await axios.get(`${baseUrl}/devices`, {
            ...config,
            params: {
                query: JSON.stringify({ _id: deviceId }),
                projection: '_id,_deviceId.Manufacturer,_deviceId._Manufacturer,InternetGatewayDevice.WANDevice.1.WANConnectionDevice,InternetGatewayDevice.LANDevice.1.WLANConfiguration'
            }
        });
        
        const deviceData = Array.isArray(getDeviceRes.data) && getDeviceRes.data.length > 0 ? getDeviceRes.data[0] : null;
        if (!deviceData) return res.json({ success: false, message: 'CPE/Device tidak ditemukan di GenieACS' });
        
        const manufacturer = (deviceData._deviceId?._Manufacturer || deviceData._deviceId?.Manufacturer || '').toLowerCase();
        
        const wanConnObj = deviceData.InternetGatewayDevice?.WANDevice?.['1']?.WANConnectionDevice || {};
        const existingKeys = Object.keys(wanConnObj).map(Number).filter(n => !isNaN(n));
        const nextInstance = existingKeys.length > 0 ? Math.max(...existingKeys) + 1 : 2; // Default start from 2 to protect management interface at 1
        
        // 4. Buat Tugas GenieACS untuk WAN
        // Task 1: Add WANConnectionDevice
        await axios.post(`${baseUrl}/devices/${encodeURIComponent(deviceId)}/tasks`, {
            name: 'addObject',
            objectName: 'InternetGatewayDevice.WANDevice.1.WANConnectionDevice'
        }, config);
        
        // Task 2: Add specific connection (WANPPPConnection or WANIPConnection)
        const connectionType = mode === 'pppoe' ? 'WANPPPConnection' : 'WANIPConnection';
        await axios.post(`${baseUrl}/devices/${encodeURIComponent(deviceId)}/tasks`, {
            name: 'addObject',
            objectName: `InternetGatewayDevice.WANDevice.1.WANConnectionDevice.${nextInstance}.${connectionType}`
        }, config);
        
        // Task 3: Set Parameters
        const paramValues = [];
        const baseConnPath = `InternetGatewayDevice.WANDevice.1.WANConnectionDevice.${nextInstance}.${connectionType}.1`;
        
        paramValues.push([`${baseConnPath}.Enable`, true, 'xsd:boolean']);
        
        const isPppoe = mode === 'pppoe';
        if (isPppoe) {
            paramValues.push([`${baseConnPath}.ConnectionType`, 'IP_Routed', 'xsd:string']);
            paramValues.push([`${baseConnPath}.NATEnabled`, true, 'xsd:boolean']);
            paramValues.push([`${baseConnPath}.Username`, pppoeUser, 'xsd:string']);
            paramValues.push([`${baseConnPath}.Password`, pppoePass, 'xsd:string']);
        } else {
            paramValues.push([`${baseConnPath}.ConnectionType`, 'Bridged', 'xsd:string']);
        }
        
        // Queue LAN DHCP Server toggle as a separate task using standard TR-098 path so that if the ONU doesn't support it, WAN provisioning doesn't fail
        const dhcpParamValues = [];
        const isDhcpEnabled = dhcp === true || dhcp === 'true' || dhcp === 'on';
        dhcpParamValues.push([`InternetGatewayDevice.LANDevice.1.LANHostConfigManagement.DHCPServerEnable`, isDhcpEnabled, 'xsd:boolean']);
        axios.post(`${baseUrl}/devices/${encodeURIComponent(deviceId)}/tasks`, {
            name: 'setParameterValues',
            parameterValues: dhcpParamValues
        }, config).catch(() => {});
        
        // VLAN & Port Binding Parameter Mapping berdasarkan vendor
        const lanPortsArray = Array.isArray(lanPorts) ? lanPorts : (lanPorts ? [lanPorts] : []);
        const wlanSsidsArray = Array.isArray(wlanSsids) ? wlanSsids : (wlanSsids ? [wlanSsids] : []);
        
        if (manufacturer.includes('huawei')) {
            paramValues.push([`${baseConnPath}.X_HW_VLAN`, parsedVlan, 'xsd:unsignedInt']);
            paramValues.push([`${baseConnPath}.X_HW_VLANID`, parsedVlan, 'xsd:unsignedInt']);
            paramValues.push([`${baseConnPath}.X_HW_VLANMark`, true, 'xsd:boolean']);
            paramValues.push([`${baseConnPath}.X_HW_WANMode`, isPppoe ? 'WAN_PPPOE' : 'WAN_BRIDGE', 'xsd:string']);
            if (lanPortsArray.length > 0) {
                paramValues.push([`${baseConnPath}.X_HW_LANBind`, lanPortsArray.join(','), 'xsd:string']);
            }
            if (wlanSsidsArray.length > 0) {
                paramValues.push([`${baseConnPath}.X_HW_SSIDBind`, wlanSsidsArray.join(','), 'xsd:string']);
            }
        } else if (manufacturer.includes('zte')) {
            paramValues.push([`${baseConnPath}.VLANIDMark`, parsedVlan, 'xsd:unsignedInt']);
            paramValues.push([`${baseConnPath}.VLANID`, parsedVlan, 'xsd:unsignedInt']); // Standard VLAN ID path
            paramValues.push([`${baseConnPath}.X_ZTE_VLAN`, parsedVlan, 'xsd:unsignedInt']);
            paramValues.push([`${baseConnPath}.VLANMode`, 1, 'xsd:unsignedInt']); // 1 = Tag
            if (lanPortsArray.length > 0) {
                paramValues.push([`${baseConnPath}.X_ZTE_LANBind`, lanPortsArray.join(','), 'xsd:string']);
            }
            if (wlanSsidsArray.length > 0) {
                paramValues.push([`${baseConnPath}.X_ZTE_SSIDBind`, wlanSsidsArray.join(','), 'xsd:string']);
            }
        } else {
            // Fallback default
            paramValues.push([`${baseConnPath}.VLANIDMark`, parsedVlan, 'xsd:unsignedInt']);
            paramValues.push([`${baseConnPath}.VLANID`, parsedVlan, 'xsd:unsignedInt']); // Standard VLAN ID path
            paramValues.push([`${baseConnPath}.VLANMode`, 1, 'xsd:unsignedInt']);
        }
        
        await axios.post(`${baseUrl}/devices/${encodeURIComponent(deviceId)}/tasks`, {
            name: 'setParameterValues',
            parameterValues: paramValues
        }, config);
        
        // 5. Tambahan: Konfigurasi Wi-Fi (jika dicentang)
        if (configureWifi === true || configureWifi === 'true' || configureWifi === 'on') {
            const wifiParamValues = [];
            const wlanConfig = deviceData.InternetGatewayDevice?.LANDevice?.['1']?.WLANConfiguration || {};
            
            // 2.4GHz
            if (wlanConfig['1'] && wifiSsid24) {
                wifiParamValues.push([`InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID`, wifiSsid24, 'xsd:string']);
                if (wifiPass24) {
                    wifiParamValues.push([`InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.PreSharedKey.1.PreSharedKey`, wifiPass24, 'xsd:string']);
                    wifiParamValues.push([`InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.KeyPassphrase`, wifiPass24, 'xsd:string']);
                }
            }
            
            // 5GHz
            const fiveGIndex = wlanConfig['5'] ? '5' : (wlanConfig['2'] ? '2' : null);
            if (fiveGIndex && wifiSsid5) {
                wifiParamValues.push([`InternetGatewayDevice.LANDevice.1.WLANConfiguration.${fiveGIndex}.SSID`, wifiSsid5, 'xsd:string']);
                if (wifiPass5) {
                    wifiParamValues.push([`InternetGatewayDevice.LANDevice.1.WLANConfiguration.${fiveGIndex}.PreSharedKey.1.PreSharedKey`, wifiPass5, 'xsd:string']);
                    wifiParamValues.push([`InternetGatewayDevice.LANDevice.1.WLANConfiguration.${fiveGIndex}.KeyPassphrase`, wifiPass5, 'xsd:string']);
                }
            }
            
            if (wifiParamValues.length > 0) {
                await axios.post(`${baseUrl}/devices/${encodeURIComponent(deviceId)}/tasks`, {
                    name: 'setParameterValues',
                    parameterValues: wifiParamValues
                }, config);
            }
        }
        
        // Pemicu koneksi agar CPE langsung melakukan pembaruan (Connection Request)
        axios.post(`${baseUrl}/devices/${encodeURIComponent(deviceId)}/tasks`, {
            name: 'refreshObject',
            objectName: ''
        }, config).catch(() => {});
        
        res.json({ success: true, message: 'Semua antrean tugas Add WAN (dan Wi-Fi) berhasil dikirimkan ke GenieACS.' });
    } catch (err) {
        res.json({ success: false, message: err.message });
    }
});

// GET /admin/acs/search - Redirect to main page with query params
router.get('/search', requireAdminSession, async (req, res) => {
    const { q, acs } = req.query;
    const params = new URLSearchParams();
    if (q) params.append('q', q);
    if (acs) params.append('acs', acs);
    res.redirect(`/admin/acs?${params.toString()}`);
});

module.exports = router;
