/*!
 * reserved-ips-form.js — validation live + gouttière d'erreurs du textarea "IP réservées".
 * Réutilise la même règle de forme raccourcie que parseRange (subnet.php) et ReservedIps (PHP).
 * ES5. Init : ReservedIpsForm.init({ textarea, gutter, editor, status, tip, subnet }).
 */
window.ReservedIpsForm = (function () {
    'use strict';
    function toInt(part, networkInt) {
        if (!/^\d{1,3}(?:\.\d{1,3}){0,3}$/.test(part)) return null;
        var oct = part.split('.').map(Number);
        if (oct.length < 4) {
            var b = networkInt >>> 0;
            var base = [(b >>> 24) & 255, (b >>> 16) & 255, (b >>> 8) & 255, b & 255];
            oct = base.slice(0, 4 - oct.length).concat(oct);
        }
        if (oct.length !== 4) return null;
        for (var i = 0; i < 4; i++) { if (isNaN(oct[i]) || oct[i] < 0 || oct[i] > 255) return null; }
        return (oct[0] * 16777216 + oct[1] * 65536 + oct[2] * 256 + oct[3]) >>> 0;
    }
    function validateLine(raw, subnet) {
        var hash = raw.indexOf('#');
        var part = (hash >= 0 ? raw.slice(0, hash) : raw).trim();
        if (part === '') return null; // vide / commentaire pur
        var a, e;
        var dash = part.indexOf('-');
        if (dash >= 0) {
            // split sur le 1er '-' uniquement (miroir de explode('-', $part, 2) en PHP) :
            // "1-2-3" → end = "2-3" qui échoue la regex d'octets, comme côté serveur.
            a = toInt(part.slice(0, dash).trim(), subnet.networkInt);
            e = toInt(part.slice(dash + 1).trim(), subnet.networkInt);
        } else {
            a = toInt(part, subnet.networkInt); e = a;
        }
        if (a == null || e == null) return 'Format IP/plage invalide';
        if (a > e) { var t = a; a = e; e = t; }
        if (a < subnet.networkInt || e > subnet.broadcastInt) return 'Hors du subnet ' + subnet.cidr;
        var pools = [];
        if (subnet.dynStartInt != null && subnet.dynEndInt != null) pools.push([subnet.dynStartInt, subnet.dynEndInt, 'pool dynamique']);
        if (subnet.shortStartInt != null && subnet.shortEndInt != null) pools.push([subnet.shortStartInt, subnet.shortEndInt, 'pool short-lease']);
        for (var i = 0; i < pools.length; i++) {
            if (a <= pools[i][1] && pools[i][0] <= e) return 'Chevauche le ' + pools[i][2];
        }
        return null;
    }
    function init(cfg) {
        var ta = cfg.textarea, gutter = cfg.gutter, editor = cfg.editor,
            status = cfg.status, tip = cfg.tip, subnet = cfg.subnet;
        if (!ta) return;
        function lineHeightPx() {
            var lh = parseFloat(getComputedStyle(ta).lineHeight);
            return isNaN(lh) ? 19.5 : lh;
        }
        function refresh() {
            var lines = ta.value.split('\n');
            var lh = lineHeightPx();
            gutter.innerHTML = '';
            var nErr = 0;
            lines.forEach(function (ln) {
                var g = document.createElement('div');
                g.className = 'rip-g-line';
                g.style.height = lh + 'px';
                var err = validateLine(ln, subnet);
                if (err) {
                    nErr++;
                    g.textContent = '!';
                    g.addEventListener('mouseenter', function (ev) {
                        tip.textContent = err; tip.style.display = 'block';
                        tip.style.left = (ev.clientX + 12) + 'px'; tip.style.top = (ev.clientY + 12) + 'px';
                    });
                    g.addEventListener('mousemove', function (ev) {
                        tip.style.left = (ev.clientX + 12) + 'px'; tip.style.top = (ev.clientY + 12) + 'px';
                    });
                    g.addEventListener('mouseleave', function () { tip.style.display = 'none'; });
                }
                gutter.appendChild(g);
            });
            gutter.style.transform = 'translateY(' + (-ta.scrollTop) + 'px)';
            if (editor) editor.classList.toggle('rip-invalid', nErr > 0);
            if (status) {
                if (ta.value.trim() === '') { status.textContent = ''; status.className = 'rip-status'; }
                else if (nErr > 0) { status.textContent = '✗ ' + nErr + ' ligne(s) en erreur — enregistrement bloqué'; status.className = 'rip-status ko'; }
                else { status.textContent = '✓ Liste valide'; status.className = 'rip-status ok'; }
            }
        }
        ta.addEventListener('input', refresh);
        ta.addEventListener('scroll', function () { gutter.style.transform = 'translateY(' + (-ta.scrollTop) + 'px)'; });
        refresh();
    }
    return { init: init };
}());
