<?php

require_once __DIR__ . '/../lib/init.php';
Auth::requireLogin();

$id = (int)($_GET['id'] ?? 0);
$subnet = Subnet::getById($id);
if (!$subnet) {
    header('Location: dashboard.php');
    exit;
}

$reservations = Reservation::getBySubnet($subnet['kea_subnet_id']);

require_once __DIR__ . '/../lib/sbg_helpers.php';
$sbgSubnet = buildBargraphSubnet($subnet);

$rows = [];
foreach ($reservations as $r) {
    $ip = ($r['ip_address'] !== '' && $r['ip_address'] !== '0.0.0.0') ? $r['ip_address'] : '';
    $rows[] = [
        'host_id'     => (int)$r['host_id'],
        'hostname'    => $r['hostname'],
        'ip'          => $ip,
        'ip_int'      => $ip === '' ? 0 : (int)ipToInt($ip),
        'mac'         => $r['mac'],
        'mac_hex'     => strtolower($r['mac_hex']),
        'description' => $r['description'] ?? '',
        'group_name'  => $r['group_name'] ?? '',
        'has_options' => (int)$r['has_options'],
        'has_ntp'     => (int)$r['has_ntp'],
        'short_lease' => (int)$r['short_lease'],
        'gateway'     => $r['gateway'] ?? '',
        'no_gateway'  => (int)($r['no_gateway'] ?? 0),
        'routes'      => $r['routes'] ?? [],
        'ntp_enabled' => (int)($r['ntp_enabled'] ?? 0),
        'modified'    => substr($r['updated_at'] ?? $r['created_at'] ?? '', 0, 16),
    ];
}
$canEdit = Auth::currentUserRole() !== 'viewer';
$relayMode    = Settings::get('relay_mode', '0') === '1';
$page_title   = h($subnet['name']) . ' — Réservations';
require_once APP_ROOT . '/lib/layout_header.php';
?>

<div class="d-flex justify-content-between align-items-center mb-3">
    <div>
        <h5 class="mb-0">
            <code><?= h($subnet['cidr']) ?></code>
            <?php if ($relayMode && $subnet['relay_address']): ?>
                <small class="text-muted ms-2">
                    <i class="bi bi-arrow-left-right"></i> Relay: <?= h($subnet['relay_address']) ?>
                </small>
            <?php elseif (!$relayMode && $subnet['interface']): ?>
                <small class="text-muted ms-2"><?= h($subnet['interface']) ?></small>
            <?php endif; ?>
        </h5>
        <?php if ($subnet['gateway']): ?>
        <small class="text-muted">
            GW : <?= h($subnet['gateway']) ?>
            <?php if ($subnet['dns_servers']): ?>
                &nbsp;· DNS : <?= h($subnet['dns_servers']) ?>
            <?php endif; ?>
        </small>
        <?php endif; ?>
    </div>
    <div class="d-flex gap-2 align-items-center">
        <?php if (Auth::currentUserRole() !== 'viewer'): ?>
        <a href="subnet_edit.php?id=<?= $subnet['id'] ?>" class="btn btn-outline-secondary" title="Modifier le subnet">
            <i class="bi bi-pencil"></i>
        </a>
        <a href="subnet_import.php?subnet_id=<?= $subnet['id'] ?>" class="btn btn-outline-secondary">
            <i class="bi bi-upload me-1"></i>Importer
        </a>
        <?php endif; ?>

        <div class="dropdown">
            <button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown">
                <i class="bi bi-download me-1"></i>Exporter
            </button>
            <ul class="dropdown-menu dropdown-menu-end">
                <li>
                    <a class="dropdown-item" href="subnet_export.php?subnet_id=<?= $subnet['id'] ?>">
                        <i class="bi bi-filetype-csv me-2"></i>Exporter les réservations
                    </a>
                </li>
                <li>
                    <a class="dropdown-item" href="subnet_export.php?subnet_id=<?= $subnet['id'] ?>&template=1">
                        <i class="bi bi-file-earmark-spreadsheet me-2"></i>Télécharger le modèle vide
                    </a>
                </li>
            </ul>
        </div>

        <?php if (Auth::currentUserRole() !== 'viewer'): ?>
        <a href="reservation_add.php?subnet_id=<?= $subnet['id'] ?>" class="btn btn-primary">
            <i class="bi bi-plus-lg"></i> Ajouter une réservation
        </a>
        <?php endif; ?>
    </div>
</div>

<?php
$flash = $_SESSION['flash'] ?? null;
unset($_SESSION['flash']);
if ($flash):
?>
<div class="alert alert-<?= h($flash['type']) ?> alert-dismissible fade show" role="alert">
    <?= h($flash['message']) ?>
    <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>

<div class="card">
    <div class="card-header py-3">
      <div class="d-flex justify-content-between align-items-center">
        <span>
            <i class="bi bi-hdd-network me-2"></i>
            <?= count($reservations) ?> réservation<?= count($reservations) > 1 ? 's' : '' ?>
            <small class="text-muted ms-2" id="subnet-bargraph-rate"></small>
        </span>
        <div class="d-flex flex-column gap-1 text-end">
        <?php if ($subnet['has_dynamic_pool'] && $subnet['range_start']): ?>
        <small class="text-muted">
            Pool dynamique : <?= h($subnet['range_start']) ?> – <?= h($subnet['range_end']) ?>
        </small>
        <?php endif; ?>
        <?php if (!empty($subnet['short_lease_pool_start'])): ?>
        <small class="text-muted">
            <i class="bi bi-hourglass-split text-warning me-1"></i>Pool short-lease : <?= h($subnet['short_lease_pool_start']) ?> – <?= h($subnet['short_lease_pool_end']) ?>
        </small>
        <?php endif; ?>
        </div>
      </div>
      <div id="subnet-bargraph"></div>
    </div>
    <div class="card-body p-0">
        <?php if ($rows): ?>
        <div class="reservation-toolbar d-flex flex-wrap gap-2 align-items-center px-3 py-2 border-bottom">
            <div class="btn-group btn-group-sm" role="group" aria-label="Mode d'affichage">
                <button type="button" class="btn btn-outline-secondary" id="mode-grouped">
                    <i class="bi bi-collection me-1"></i>Groupés
                </button>
                <button type="button" class="btn btn-outline-secondary" id="mode-flat">
                    <i class="bi bi-list-ul me-1"></i>Plat
                </button>
            </div>
            <div class="reservation-filter flex-grow-1 position-relative" style="max-width:340px">
                <input type="text" id="res-filter" class="form-control form-control-sm"
                       placeholder="Filtrer (hostname, IP, MAC, description, groupe)…" autocomplete="off">
                <button type="button" id="res-filter-clear" class="res-filter-clear" title="Effacer" hidden>&times;</button>
            </div>
            <small class="text-muted ms-auto" id="res-count"></small>
        </div>
        <div id="reservation-container"></div>
        <?php if ($canEdit): ?>
        <div id="selection-bar" class="selection-bar" hidden>
            <span id="selection-count">0 sélectionnée(s)</span>
            <button type="button" class="btn btn-sm btn-primary" id="btn-mass-edit">
                <i class="bi bi-pencil-square me-1"></i>Modifier les options
            </button>
            <button type="button" class="btn btn-sm btn-outline-secondary" id="btn-mass-export">
                <i class="bi bi-download me-1"></i>Exporter
            </button>
            <button type="button" class="btn btn-sm btn-outline-primary" id="btn-mass-copy">
                <i class="bi bi-files me-1"></i>Copier vers…
            </button>
            <button type="button" class="btn btn-sm btn-outline-danger" id="btn-mass-delete">
                <i class="bi bi-trash me-1"></i>Supprimer
            </button>
            <button type="button" class="btn btn-sm btn-outline-secondary" id="btn-clear-selection">
                Tout désélectionner
            </button>
        </div>
        <form id="mass-delete-form" method="post" action="reservation_mass_delete.php" class="d-none">
            <input type="hidden" name="subnet_id" value="<?= (int)$subnet['id'] ?>">
            <input type="hidden" name="host_ids" id="mass-delete-hostids">
        </form>
        <form id="mass-copy-form" method="post" action="subnet_copy.php" class="d-none">
            <input type="hidden" name="subnet_id" value="<?= (int)$subnet['id'] ?>">
            <input type="hidden" name="host_ids" id="mass-copy-hostids">
        </form>
        <?php endif; ?>
        <?php else: ?>
        <div class="p-5 text-center text-muted">
            <i class="bi bi-hdd-network fs-1"></i>
            <p class="mt-3 mb-1">Aucune réservation sur ce subnet.</p>
            <?php if ($canEdit): ?>
            <a href="reservation_add.php?subnet_id=<?= $subnet['id'] ?>" class="btn btn-primary mt-2">
                <i class="bi bi-plus-lg"></i> Ajouter la première réservation
            </a>
            <?php endif; ?>
        </div>
        <?php endif; ?>
    </div>
</div>

<?php if ($canEdit): ?>
<div class="modal fade" id="massEditModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-lg modal-dialog-centered">
    <div class="modal-content">
      <form method="post" action="reservation_bulk.php" id="mass-edit-form">
        <input type="hidden" name="subnet_id" value="<?= (int)$subnet['id'] ?>">
        <div id="mass-edit-hostids"></div>
        <div class="modal-header">
          <h5 class="modal-title"><i class="bi bi-pencil-square me-2"></i>Modifier <span id="mass-edit-count">0</span> réservation(s)</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
        </div>
        <div class="modal-body" id="mass-edit-body"></div>
        <div class="modal-footer">
          <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Annuler</button>
          <button type="submit" class="btn btn-primary" id="mass-edit-apply" disabled>Appliquer</button>
        </div>
      </form>
    </div>
  </div>
</div>
<?php endif; ?>

<?php require_once APP_ROOT . '/lib/layout_footer.php'; ?>
<script src="assets/js/subnet-bargraph.js"></script>
<script>
(function () {
    var ROWS     = <?= json_encode($rows, JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP) ?>;
    var SUBNET = <?= json_encode($sbgSubnet, JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP) ?>;
    var CAN_EDIT = <?= $canEdit ? 'true' : 'false' ?>;
    var selected = new Set();
    var selectionBar   = document.getElementById('selection-bar');
    var selectionCount = document.getElementById('selection-count');

    function updateSelectionBar() {
        if (!selectionBar) return;
        var n = selected.size;
        selectionBar.hidden = (n === 0);
        if (selectionCount) selectionCount.textContent = n + ' sélectionnée(s)';
    }
    var SUBNET_ID = <?= (int)$subnet['id'] ?>;
    var container = document.getElementById('reservation-container');
    if (!container) return;

    var MODE_KEY = 'dhcpman.subnet.viewmode';
    var mode = localStorage.getItem(MODE_KEY) === 'flat' ? 'flat' : 'grouped';
    var filterInput = document.getElementById('res-filter');
    var countEl     = document.getElementById('res-count');
    var btnGrouped  = document.getElementById('mode-grouped');
    var btnFlat     = document.getElementById('mode-flat');

    function norm(s) {
        return String(s).toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g, '');
    }
    // Détecte une requête "range IP" : "a.b.c.d-a.b.c.d" ou forme courte "10-20" (octets de fin,
    // complétés avec le préfixe réseau du subnet courant).
    // Retourne [loInt, hiInt] ou null.
    function parseRange(q) {
        var m = q.match(/^\s*(\d{1,3}(?:\.\d{1,3}){0,3})\s*-\s*(\d{1,3}(?:\.\d{1,3}){0,3})\s*$/);
        if (!m) return null;
        function toInt(part) {
            var octets = part.split('.');
            if (octets.length < 4) {
                var base = SUBNET.networkInt >>> 0;
                var baseOct = [(base>>>24)&255,(base>>>16)&255,(base>>>8)&255,base&255];
                var full = baseOct.slice(0, 4 - octets.length).concat(octets.map(Number));
                octets = full;
            } else {
                octets = octets.map(Number);
            }
            if (octets.length !== 4 || octets.some(function (o){ return isNaN(o) || o < 0 || o > 255; })) return null;
            return (octets[0] * 16777216 + octets[1] * 65536 + octets[2] * 256 + octets[3]) >>> 0;
        }
        var lo = toInt(m[1]), hi = toInt(m[2]);
        if (lo == null || hi == null) return null;
        return lo <= hi ? [lo, hi] : [hi, lo];
    }
    function matches(r, q) {
        if (q === '') return true;
        var range = parseRange(q);
        if (range) {
            return r.ip_int >= range[0] && r.ip_int <= range[1];
        }
        var macNoSep = r.mac_hex;
        var hay = norm(r.hostname) + ' ' + norm(r.ip) + ' ' + norm(r.mac) + ' '
                + macNoSep + ' ' + norm(r.description) + ' ' + norm(r.group_name);
        return hay.indexOf(q) !== -1;
    }
    function byIp(a, b) { return a.ip_int - b.ip_int; }

    function iconIndicators(r) {
        var span = document.createElement('span');
        function add(cls, color, title) {
            var i = document.createElement('i');
            i.className = 'bi ' + cls + ' ' + color + ' ms-1';
            i.style.fontSize = '.8em';
            i.setAttribute('data-bs-toggle', 'tooltip');
            i.setAttribute('title', title);
            span.appendChild(i);
        }
        if (r.has_options) add('bi-sliders', 'text-primary', 'Options DHCP spécifiques (gateway / routes)');
        if (r.has_ntp)     add('bi-clock', 'text-info', 'NTP activé (option 42)');
        if (r.short_lease) add('bi-hourglass-split', 'text-warning', 'Lease court (1h) — client class short-lease');
        return span;
    }
    function actionsCell(r) {
        var td = document.createElement('td');
        td.className = 'text-end';
        if (!CAN_EDIT) return td;
        var edit = document.createElement('a');
        edit.href = 'reservation_edit.php?id=' + r.host_id + '&subnet_id=' + SUBNET_ID;
        edit.className = 'btn btn-sm btn-outline-secondary me-1';
        edit.title = 'Modifier';
        edit.innerHTML = '<i class="bi bi-pencil"></i>';
        var del = document.createElement('a');
        del.href = 'reservation_delete.php?id=' + r.host_id + '&subnet_id=' + SUBNET_ID;
        del.className = 'btn btn-sm btn-outline-danger';
        del.title = 'Supprimer';
        del.innerHTML = '<i class="bi bi-trash"></i>';
        td.appendChild(edit);
        td.appendChild(del);
        return td;
    }
    function hostnameCell(r) {
        var td = document.createElement('td');
        td.className = 'fw-semibold';
        td.textContent = r.hostname;
        td.appendChild(iconIndicators(r));
        return td;
    }
    function ipCell(r) {
        var td = document.createElement('td');
        td.className = 'nowrap-col';
        if (r.ip) {
            var s = document.createElement('span');
            s.className = 'ip-address';
            s.textContent = r.ip;
            td.appendChild(s);
        } else {
            var e = document.createElement('span');
            e.className = 'text-muted fst-italic';
            e.textContent = 'dynamique';
            td.appendChild(e);
        }
        return td;
    }
    function simpleCell(text, nowrap) {
        var td = document.createElement('td');
        if (nowrap) td.className = 'nowrap-col';
        var s = document.createElement('small');
        s.className = 'text-muted';
        s.textContent = text || '';
        td.appendChild(s);
        return td;
    }
    function macCell(r) {
        var td = document.createElement('td');
        td.className = 'nowrap-col';
        var s = document.createElement('span');
        s.className = 'mac-address';
        s.textContent = r.mac;
        td.appendChild(s);
        return td;
    }
    function groupBadgeCell(r) {
        var td = document.createElement('td');
        if (r.group_name) {
            var b = document.createElement('span');
            b.className = 'group-badge';
            b.textContent = r.group_name;
            td.appendChild(b);
        } else {
            var m = document.createElement('span');
            m.className = 'text-muted';
            m.textContent = '—';
            td.appendChild(m);
        }
        return td;
    }
    function makeTable(withGroupCol) {
        var table = document.createElement('table');
        table.className = 'table table-hover mb-0 res-table' + (withGroupCol ? ' res-table-grouped-col' : '');
        var thead = document.createElement('thead');
        thead.className = 'table-light';
        var heads = [];
        if (CAN_EDIT) heads.push('__check__');
        heads.push('Hostname', 'Adresse IP', 'Adresse MAC');
        if (withGroupCol) heads.push('Groupe');
        heads.push('Description', 'Modifié le', '');
        // Largeurs fixes par colonne (table-layout:fixed) → colonnes alignées entre tous
        // les groupes. Seule la Description reste fluide (prend l'espace restant) ; les
        // colonnes à contenu de longueur constante (IP/MAC/date) sont dimensionnées au
        // plus juste + nowrap (voir CSS .res-table) pour ne jamais passer sur 2 lignes.
        var COL_WIDTH = {
            '__check__':    '34px',
            'Hostname':     '200px',
            'Adresse IP':   '130px',
            'Adresse MAC':  '170px',
            'Groupe':       '120px',
            'Modifié le':   '130px',
            '':             '90px'    // colonne d'actions (dernier th, libellé vide)
        };
        var tr = document.createElement('tr');
        heads.forEach(function (htext) {
            var th = document.createElement('th');
            if (COL_WIDTH[htext]) th.style.width = COL_WIDTH[htext];
            if (htext === '__check__') {
                var all = document.createElement('input');
                all.type = 'checkbox';
                all.className = 'form-check-input select-all';
                th.appendChild(all);
            } else {
                th.textContent = htext;
            }
            tr.appendChild(th);
        });
        thead.appendChild(tr);
        table.appendChild(thead);
        var tbody = document.createElement('tbody');
        table.appendChild(tbody);
        return { table: table, tbody: tbody };
    }
    function appendRow(tbody, r, withGroupCol) {
        var tr = document.createElement('tr');
        if (CAN_EDIT) {
            var tdc = document.createElement('td');
            var cb = document.createElement('input');
            cb.type = 'checkbox';
            cb.className = 'form-check-input row-check';
            cb.setAttribute('data-host-id', r.host_id);
            cb.checked = selected.has(r.host_id);
            cb.addEventListener('change', function () {
                if (cb.checked) selected.add(r.host_id); else selected.delete(r.host_id);
                updateSelectionBar();
                syncSelectAll();
            });
            tdc.appendChild(cb);
            tr.appendChild(tdc);
        }
        tr.appendChild(hostnameCell(r));
        tr.appendChild(ipCell(r));
        tr.appendChild(macCell(r));
        if (withGroupCol) tr.appendChild(groupBadgeCell(r));
        tr.appendChild(simpleCell(r.description));
        tr.appendChild(simpleCell(r.modified, true));
        tr.appendChild(actionsCell(r));
        tbody.appendChild(tr);
    }
    function renderFlat(data) {
        container.innerHTML = '';
        var t = makeTable(true);
        data.slice().sort(byIp).forEach(function (r) { appendRow(t.tbody, r, true); });
        container.appendChild(t.table);
    }
    function renderGrouped(data) {
        container.innerHTML = '';
        var groups = {};
        var order = [];
        data.forEach(function (r) {
            var key = r.group_name && r.group_name.trim() !== '' ? r.group_name : ' ';
            if (!groups[key]) { groups[key] = []; order.push(key); }
            groups[key].push(r);
        });
        order.sort(function (a, b) {
            if (a === ' ') return 1;
            if (b === ' ') return -1;
            return a.localeCompare(b);
        });
        order.forEach(function (key) {
            var list = groups[key].slice().sort(byIp);
            var wrap = document.createElement('div');
            var header = document.createElement('div');
            header.className = 'group-header' + (key === ' ' ? ' group-header-none' : '');
            var caret = document.createElement('span'); caret.textContent = '▾'; caret.className = 'group-caret';
            var name = document.createElement('span');
            name.className = 'group-name';
            name.textContent = key === ' ' ? '(sans groupe)' : key;
            var count = document.createElement('span');
            count.className = 'group-count';
            count.textContent = list.length;
            header.appendChild(caret); header.appendChild(name); header.appendChild(count);
            var body = document.createElement('div');
            var t = makeTable(false);
            list.forEach(function (r) { appendRow(t.tbody, r, false); });
            body.appendChild(t.table);
            header.addEventListener('click', function () {
                if (body.hasAttribute('hidden')) { body.removeAttribute('hidden'); caret.textContent = '▾'; }
                else { body.setAttribute('hidden', ''); caret.textContent = '▸'; }
            });
            wrap.appendChild(header);
            wrap.appendChild(body);
            container.appendChild(wrap);
        });
    }
    function syncSelectAll() {
        document.querySelectorAll('.select-all').forEach(function (all) {
            var scope = all.closest('table');
            var boxes = scope ? scope.querySelectorAll('.row-check') : [];
            var total = boxes.length, checked = 0;
            boxes.forEach(function (b) { if (b.checked) checked++; });
            all.checked = (total > 0 && checked === total);
            all.indeterminate = (checked > 0 && checked < total);
        });
    }
    function wireSelectAll() {
        document.querySelectorAll('.select-all').forEach(function (all) {
            all.addEventListener('change', function () {
                var scope = all.closest('table');
                var boxes = scope ? scope.querySelectorAll('.row-check') : [];
                boxes.forEach(function (b) {
                    b.checked = all.checked;
                    var id = parseInt(b.getAttribute('data-host-id'), 10);
                    if (all.checked) selected.add(id); else selected.delete(id);
                });
                updateSelectionBar();
            });
        });
    }
    function render() {
        var q = norm(filterInput.value.trim());
        var data = ROWS.filter(function (r) { return matches(r, q); });
        countEl.textContent = data.length + ' / ' + ROWS.length;
        if (mode === 'flat') renderFlat(data); else renderGrouped(data);
        btnGrouped.classList.toggle('active', mode === 'grouped');
        btnFlat.classList.toggle('active', mode === 'flat');
        container.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(function (el) {
            new bootstrap.Tooltip(el);
        });
        wireSelectAll();
        syncSelectAll();
        updateSelectionBar();
    }
    btnGrouped.addEventListener('click', function () { mode = 'grouped'; localStorage.setItem(MODE_KEY, mode); render(); });
    btnFlat.addEventListener('click',    function () { mode = 'flat';    localStorage.setItem(MODE_KEY, mode); render(); });
    filterInput.addEventListener('input', render);
    var filterClear = document.getElementById('res-filter-clear');
    if (filterClear) {
        filterInput.addEventListener('input', function () { filterClear.hidden = (filterInput.value === ''); });
        filterClear.addEventListener('click', function () {
            filterInput.value = '';
            filterClear.hidden = true;
            render();
            filterInput.focus();
        });
    }
    var btnClearSel = document.getElementById('btn-clear-selection');
    if (btnClearSel) {
        btnClearSel.addEventListener('click', function () {
            selected.clear();
            render();
        });
    }

    // ── Export de la sélection ─────────────────────────────────────────────────
    var btnMassExport = document.getElementById('btn-mass-export');
    if (btnMassExport) {
        btnMassExport.addEventListener('click', function () {
            if (selected.size === 0) return;
            var ids = Array.from(selected).join(',');
            window.location = 'subnet_export.php?subnet_id=' + SUBNET_ID + '&host_ids=' + encodeURIComponent(ids);
        });
    }

    // ── Suppression en masse (page de confirmation serveur) ────────────────────
    var btnMassDelete = document.getElementById('btn-mass-delete');
    if (btnMassDelete) {
        btnMassDelete.addEventListener('click', function () {
            if (selected.size === 0) return;
            document.getElementById('mass-delete-hostids').value = Array.from(selected).join(',');
            document.getElementById('mass-delete-form').submit();
        });
    }

    // ── Copie vers un autre subnet (page de choix cible) ───────────────────────
    var btnMassCopy = document.getElementById('btn-mass-copy');
    if (btnMassCopy) {
        btnMassCopy.addEventListener('click', function () {
            if (selected.size === 0) return;
            document.getElementById('mass-copy-hostids').value = Array.from(selected).join(',');
            document.getElementById('mass-copy-form').submit();
        });
    }

    // ── Popup de mass update ──────────────────────────────────────────────────
    var btnMassEdit = document.getElementById('btn-mass-edit');
    var massModalEl = document.getElementById('massEditModal');
    var massModal   = massModalEl ? new bootstrap.Modal(massModalEl) : null;

    function selectedRows() {
        return ROWS.filter(function (r) { return selected.has(r.host_id); });
    }
    function boolConsensus(rows, key) {
        var anyOn = false, anyOff = false;
        rows.forEach(function (r) { if (r[key]) anyOn = true; else anyOff = true; });
        if (anyOn && anyOff) return 'mixed';
        return anyOn ? 'on' : 'off';
    }
    function textConsensus(rows, key) {
        var first = rows.length ? (rows[0][key] || '') : '';
        for (var i = 1; i < rows.length; i++) { if ((rows[i][key] || '') !== first) return null; }
        return first;
    }
    function routesConsensus(rows) {
        var first = rows.length ? JSON.stringify(rows[0].routes || []) : '[]';
        for (var i = 1; i < rows.length; i++) { if (JSON.stringify(rows[i].routes || []) !== first) return null; }
        return JSON.parse(first);
    }

    function markChanged(row, field, isChanged) {
        var flag = row.querySelector('input[name="changed[' + field + ']"]');
        var reset = row.querySelector('.field-reset');
        flag.value = isChanged ? '1' : '';
        if (reset) reset.hidden = !isChanged;
        refreshApplyState();
    }
    function fieldRow(field, label) {
        var row = document.createElement('div');
        row.className = 'mass-field d-flex align-items-center gap-2 py-2 border-bottom';
        row.setAttribute('data-field', field);
        var lab = document.createElement('label');
        lab.className = 'fw-semibold';
        lab.style.width = '190px';
        lab.textContent = label;
        row.appendChild(lab);
        var flag = document.createElement('input');
        flag.type = 'hidden'; flag.name = 'changed[' + field + ']'; flag.value = '';
        row.appendChild(flag);
        return row;
    }
    function addReset(row, onReset) {
        var b = document.createElement('button');
        b.type = 'button'; b.className = 'field-reset btn btn-sm btn-link p-0 ms-1';
        b.title = 'Annuler ce changement'; b.hidden = true;
        b.innerHTML = '<i class="bi bi-arrow-counterclockwise"></i>';
        b.addEventListener('click', function () { onReset(); });
        row.appendChild(b);
        return b;
    }

    function buildTextField(field, label, initial) {
        var row = fieldRow(field, label);
        var mixed = (initial === null);
        var input = document.createElement('input');
        input.type = 'text'; input.name = field; input.className = 'form-control form-control-sm';
        input.style.maxWidth = '240px';
        input.value = mixed ? '' : initial;
        if (mixed) input.placeholder = 'valeurs mêlées';
        row.appendChild(input);
        addReset(row, function () { input.value = mixed ? '' : initial; markChanged(row, field, false); });
        input.addEventListener('input', function () {
            var changed = mixed ? (input.value !== '') : (input.value !== initial);
            markChanged(row, field, changed);
            if (field === 'gateway') applyExclusivity();
        });
        return row;
    }

    function buildTriField(field, label, initial) {
        var row = fieldRow(field, label);
        var box = document.createElement('input');
        box.type = 'checkbox'; box.className = 'form-check-input mass-tri';
        box.name = field; box.value = '1';
        var hint = document.createElement('span');
        hint.className = 'text-muted small';
        function setVisual(state) {
            if (state === 'mixed') { box.indeterminate = true; box.checked = false; hint.textContent = 'ne pas changer (valeurs mêlées)'; }
            else if (state === 'on') { box.indeterminate = false; box.checked = true; hint.textContent = ''; }
            else { box.indeterminate = false; box.checked = false; hint.textContent = ''; }
        }
        setVisual(initial);
        row.appendChild(box);
        row.appendChild(hint);
        addReset(row, function () { setVisual(initial); markChanged(row, field, false); });
        box.addEventListener('click', function () {
            box.indeterminate = false;
            var nowOn = box.checked;
            hint.textContent = '';
            var changed = (initial === 'mixed') ? true : (initial === 'on' ? !nowOn : nowOn);
            markChanged(row, field, changed);
            if (field === 'no_gateway') applyExclusivity();
        });
        return row;
    }

    function buildRoutesField(field, label, initial) {
        var row = fieldRow(field, label);
        var mixed = (initial === null);
        var wrap = document.createElement('div');
        wrap.className = 'flex-grow-1';
        var editor = document.createElement('div'); editor.className = 'routes-editor';
        var status = document.createElement('div'); status.className = 'text-muted small mb-1';
        var addBtn = document.createElement('button');
        addBtn.type = 'button'; addBtn.className = 'btn btn-sm btn-outline-secondary';
        addBtn.innerHTML = '<i class="bi bi-plus-lg"></i> Ajouter une route';

        function markIfChanged() {
            var cur = [];
            editor.querySelectorAll('.route-row').forEach(function (rr) {
                cur.push({ dest: rr.querySelector('input[name="routes_dest[]"]').value.trim(),
                           gw: rr.querySelector('input[name="routes_gw[]"]').value.trim() });
            });
            var changed;
            if (mixed) changed = true;
            else changed = JSON.stringify(cur) !== JSON.stringify(initial || []);
            markChanged(row, field, changed);
            applyExclusivity();
        }
        function addRouteRow(dest, gw) {
            var rr = document.createElement('div');
            rr.className = 'route-row d-flex gap-2 mb-1 align-items-center';
            rr.innerHTML =
                '<input type="text" name="routes_dest[]" class="form-control form-control-sm font-monospace" style="max-width:150px" placeholder="10.0.0.0/8">'
              + '<span class="text-muted">→</span>'
              + '<input type="text" name="routes_gw[]" class="form-control form-control-sm font-monospace" style="max-width:140px" placeholder="192.168.1.254">'
              + '<button type="button" class="btn btn-sm btn-outline-danger route-del"><i class="bi bi-x-lg"></i></button>';
            editor.appendChild(rr);
            rr.querySelector('input[name="routes_dest[]"]').value = dest || '';
            rr.querySelector('input[name="routes_gw[]"]').value = gw || '';
            rr.querySelector('.route-del').addEventListener('click', function () { rr.remove(); markIfChanged(); });
            rr.querySelectorAll('input').forEach(function (i) { i.addEventListener('input', markIfChanged); });
        }

        if (mixed) {
            status.textContent = 'routes divergentes';
            editor.hidden = true;
            var setBtn = document.createElement('button');
            setBtn.type = 'button'; setBtn.className = 'btn btn-sm btn-outline-primary';
            setBtn.textContent = 'Définir pour tous…';
            setBtn.addEventListener('click', function () {
                editor.hidden = false; setBtn.hidden = true; status.textContent = '';
                markIfChanged();
            });
            wrap.appendChild(status); wrap.appendChild(setBtn);
        } else {
            (initial || []).forEach(function (r) { addRouteRow(r.dest, r.gw); });
        }
        wrap.appendChild(editor);
        wrap.appendChild(addBtn);
        addBtn.addEventListener('click', function () { editor.hidden = false; addRouteRow('', ''); });
        row.appendChild(wrap);
        addReset(row, function () {
            editor.querySelectorAll('.route-row').forEach(function (n) { n.remove(); });
            if (!mixed) { (initial || []).forEach(function (r) { addRouteRow(r.dest, r.gw); }); }
            else { editor.hidden = true; status.textContent = 'routes divergentes'; }
            markChanged(row, field, false);
            applyExclusivity();
        });
        return row;
    }

    function fieldChanged(field) {
        var flag = document.querySelector('#mass-edit-body input[name="changed[' + field + ']"]');
        return flag && flag.value === '1';
    }
    function hasRoutesDefined() {
        var rows = document.querySelectorAll('#mass-edit-body .route-row');
        for (var i = 0; i < rows.length; i++) {
            var d = rows[i].querySelector('input[name="routes_dest[]"]').value.trim();
            var g = rows[i].querySelector('input[name="routes_gw[]"]').value.trim();
            if (d !== '' && g !== '') return true;
        }
        return false;
    }
    function setDisabled(field, disabled) {
        var frow = document.querySelector('#mass-edit-body .mass-field[data-field="' + field + '"]');
        if (!frow) return;
        frow.querySelectorAll('input:not([type=hidden]), button').forEach(function (el) {
            if (!el.classList.contains('field-reset')) el.disabled = disabled;
        });
        frow.style.opacity = disabled ? '.5' : '';
    }
    function applyExclusivity() {
        var routesActive = fieldChanged('routes') && hasRoutesDefined();
        var noGwBox = document.querySelector('#mass-edit-body .mass-field[data-field="no_gateway"] .mass-tri');
        var noGwActive = fieldChanged('no_gateway') && noGwBox && noGwBox.checked && !noGwBox.indeterminate;
        setDisabled('gateway', routesActive || noGwActive);
        setDisabled('no_gateway', routesActive);
        setDisabled('routes', noGwActive);
    }
    function refreshApplyState() {
        var apply = document.getElementById('mass-edit-apply');
        var any = ['group_name','short_lease','gateway','no_gateway','routes','ntp'].some(fieldChanged);
        apply.disabled = !any;
    }

    function buildMassEditBody() {
        var rows = selectedRows();
        var body = document.getElementById('mass-edit-body');
        body.innerHTML = '';
        document.getElementById('mass-edit-count').textContent = rows.length;
        var hidden = document.getElementById('mass-edit-hostids');
        hidden.innerHTML = '';
        rows.forEach(function (r) {
            var i = document.createElement('input');
            i.type = 'hidden'; i.name = 'host_ids[]'; i.value = r.host_id;
            hidden.appendChild(i);
        });
        var init = {
            group_name: textConsensus(rows, 'group_name'),
            short_lease: boolConsensus(rows, 'short_lease'),
            gateway: textConsensus(rows, 'gateway'),
            no_gateway: boolConsensus(rows, 'no_gateway'),
            ntp: boolConsensus(rows, 'ntp_enabled'),
            routes: routesConsensus(rows)
        };
        body.appendChild(buildTextField('group_name', 'Groupe', init.group_name));
        body.appendChild(buildTriField('short_lease', 'Lease court (1h)', init.short_lease));
        body.appendChild(buildTextField('gateway', 'Gateway spécifique', init.gateway));
        body.appendChild(buildTriField('no_gateway', 'Ne pas envoyer de gateway', init.no_gateway));
        body.appendChild(buildRoutesField('routes', 'Routes statiques', init.routes));
        body.appendChild(buildTriField('ntp', 'NTP', init.ntp));
        refreshApplyState();
        applyExclusivity();
    }

    if (btnMassEdit && massModal) {
        btnMassEdit.addEventListener('click', function () {
            if (selected.size === 0) return;
            buildMassEditBody();
            massModal.show();
        });
    }

    // ── Bargraph de remplissage ──
    if (window.SubnetBargraph) {
        SubnetBargraph.init({
            mount: document.getElementById('subnet-bargraph'),
            rateMount: document.getElementById('subnet-bargraph-rate'),
            rows: ROWS,
            subnet: SUBNET,
            canEdit: CAN_EDIT,
            onFilter: function (q) {
                filterInput.value = q;
                filterInput.dispatchEvent(new Event('input'));
                filterInput.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
            },
            onHoleClick: CAN_EDIT ? function (ip) {
                window.location.href = SUBNET.addUrl + '&ip=' + encodeURIComponent(ip);
            } : null
        });
    }

    render();
}());
</script>
