const https = require('https');
const { getDatabase } = require('../config/database');

// ─── HTTP helper ──────────────────────────────────────────────────────────────

function request(options, body) {
    return new Promise((resolve, reject) => {
        const req = https.request({ ...options, rejectUnauthorized: false }, res => {
            const setCookies = res.headers['set-cookie'];
            if (setCookies) {
                req._cookieJar = setCookies.map(c => c.split(';')[0]).join('; ');
                const csrf = setCookies.find(c => c.startsWith('csrf_token='));
                if (csrf) req._csrfToken = csrf.split('=')[1].split(';')[0];
            }
            let data = '';
            res.on('data', c => data += c);
            res.on('end', () => {
                try { resolve({ statusCode: res.statusCode, headers: res.headers, body: JSON.parse(data) }); }
                catch { resolve({ statusCode: res.statusCode, headers: res.headers, body: {} }); }
            });
        });
        req.on('error', reject);
        req.setTimeout(15000, () => { req.destroy(); reject(new Error('Timeout')); });
        if (body) req.write(JSON.stringify(body));
        req.end();
    });
}

// ─── Unifi API Client ─────────────────────────────────────────────────────────

class UnifiClient {
    constructor(baseUrl, username, password, site = 'default') {
        this.baseUrl = baseUrl.replace(/\/$/, '');
        this.username = username;
        this.password = password;
        this.site = site;
        this.cookies = '';
        this.csrfToken = '';
    }

    _parseUrl(path) {
        const url = new URL(this.baseUrl + path);
        return { hostname: url.hostname, port: parseInt(url.port) || 443, path: url.pathname + url.search };
    }

    async _req(method, path, body) {
        const { hostname, port, path: reqPath } = this._parseUrl(path);
        const headers = { 'Content-Type': 'application/json' };
        if (this.cookies) headers['Cookie'] = this.cookies;
        if (this.csrfToken) headers['X-Csrf-Token'] = this.csrfToken;
        const res = await request({ method, hostname, port, path: reqPath, headers }, body);
        if (res.headers['set-cookie']) {
            this.cookies = res.headers['set-cookie'].map(c => c.split(';')[0]).join('; ');
            const csrf = res.headers['set-cookie'].find(c => c.startsWith('csrf_token='));
            if (csrf) this.csrfToken = csrf.split('=')[1].split(';')[0];
        }
        return res;
    }

    async login() {
        const res = await this._req('POST', '/api/login', { username: this.username, password: this.password, remember: false });
        if (res.body?.meta?.rc !== 'ok') throw new Error('Login fehlgeschlagen');
        return true;
    }

    async getDevices() {
        const res = await this._req('GET', `/api/s/${this.site}/stat/device`);
        if (res.body?.meta?.rc !== 'ok') throw new Error('Geräte konnten nicht abgerufen werden');
        return res.body.data || [];
    }

    async getClients() {
        const res = await this._req('GET', `/api/s/${this.site}/stat/sta`);
        if (res.body?.meta?.rc !== 'ok') return [];
        return res.body.data || [];
    }
}

// ─── DB helpers ───────────────────────────────────────────────────────────────

function getConfig() {
    const db = getDatabase();
    return db.prepare('SELECT * FROM unifi_config WHERE id = 1').get();
}

function saveConfig(cfg) {
    const db = getDatabase();
    db.prepare(`UPDATE unifi_config SET controller_url=@controller_url, username=@username, password=@password, site=@site, poll_interval_min=@poll_interval_min, enabled=@enabled WHERE id=1`).run(cfg);
    return getConfig();
}

function upsertDevices(devices) {
    const db = getDatabase();
    const stmt = db.prepare(`INSERT INTO unifi_devices (unifi_id, mac, name, ip, type, model, version, state, uptime, num_sta, cpu_pct, ram_pct, ports_json, radio_json, last_seen)
        VALUES (@unifi_id, @mac, @name, @ip, @type, @model, @version, @state, @uptime, @num_sta, @cpu_pct, @ram_pct, @ports_json, @radio_json, datetime('now'))
        ON CONFLICT(unifi_id) DO UPDATE SET
            name=excluded.name, ip=excluded.ip, type=excluded.type, model=excluded.model,
            version=excluded.version, state=excluded.state, uptime=excluded.uptime,
            num_sta=excluded.num_sta, cpu_pct=excluded.cpu_pct, ram_pct=excluded.ram_pct,
            ports_json=excluded.ports_json, radio_json=excluded.radio_json, last_seen=excluded.last_seen`);
    const tx = db.transaction(devs => { for (const d of devs) stmt.run(d); });
    tx(devices);
}

function getAllDevices() {
    const db = getDatabase();
    return db.prepare('SELECT * FROM unifi_devices ORDER BY type, name').all();
}

// ─── Transform Unifi API device → DB row ─────────────────────────────────────

function transformDevice(d) {
    const ports = (d.port_table || []).map(p => ({
        name: p.name, idx: p.port_idx, enabled: p.enable, up: p.up,
        speed: p.speed, poe_enable: p.poe_enable, poe_power: p.poe_power,
    }));
    const radios = (d.radio_table_stats || d.vap_table || []).map(r => ({
        name: r.name || r.radio, channel: r.channel, satisfaction: r.satisfaction,
        tx_power: r.tx_power, num_sta: r.num_sta,
    }));
    return {
        unifi_id: d._id,
        mac: d.mac,
        name: d.name || d.hostname || d.mac,
        ip: d.ip || null,
        type: d.type || 'unknown',
        model: d.model || null,
        version: d.version || null,
        state: d.state ?? 0,
        uptime: d.uptime ?? 0,
        num_sta: d.num_sta ?? 0,
        cpu_pct: d['system-stats']?.cpu != null ? parseFloat(d['system-stats'].cpu) : null,
        ram_pct: d['system-stats']?.mem != null ? parseFloat(d['system-stats'].mem) : null,
        ports_json: JSON.stringify(ports),
        radio_json: JSON.stringify(radios),
    };
}

// ─── Sync ─────────────────────────────────────────────────────────────────────

async function syncUnifi() {
    const cfg = getConfig();
    if (!cfg?.enabled || !cfg?.controller_url) return { synced: 0, error: 'Nicht konfiguriert' };
    const client = new UnifiClient(cfg.controller_url, cfg.username, cfg.password, cfg.site || 'default');
    await client.login();
    const raw = await client.getDevices();
    const rows = raw.map(transformDevice);
    upsertDevices(rows);
    return { synced: rows.length };
}

// ─── Auto-poll ────────────────────────────────────────────────────────────────

let pollTimer = null;

function startUnifiPoller() {
    if (pollTimer) return;
    const cfg = getConfig();
    if (!cfg?.enabled) return;
    const intervalMs = (cfg.poll_interval_min || 5) * 60 * 1000;
    syncUnifi().catch(e => console.warn('Unifi sync:', e.message));
    pollTimer = setInterval(() => syncUnifi().catch(e => console.warn('Unifi sync:', e.message)), intervalMs);
    console.log(`📡 Unifi-Polling gestartet (alle ${cfg.poll_interval_min} Min)`);
}

function stopUnifiPoller() {
    if (pollTimer) { clearInterval(pollTimer); pollTimer = null; }
}

function restartUnifiPoller() {
    stopUnifiPoller();
    startUnifiPoller();
}

module.exports = { getConfig, saveConfig, syncUnifi, getAllDevices, startUnifiPoller, stopUnifiPoller, restartUnifiPoller };
