<?php

require_once __DIR__ . '/../lib/init.php';
Auth::requireLogin();
Auth::requireRole('admin', 'tech');
require_once __DIR__ . '/../lib/ReservationImportAnalyzer.php';
require_once __DIR__ . '/../lib/SubnetRemap.php';
require_once __DIR__ . '/../lib/ReservedIps.php';
require_once __DIR__ . '/../lib/sbg_helpers.php';

/** Résumé lisible des options d'une ligne pour la colonne "Options". */
function copyOptionsSummary(array $row): string {
    $bits = [];
    if ((int)($row['no_gateway'] ?? 0))          $bits[] = 'no-gateway';
    elseif (trim((string)($row['gateway'] ?? '')) !== '') $bits[] = 'gw ' . $row['gateway'];
    if (trim((string)($row['routes_raw'] ?? '')) !== '')  $bits[] = 'routes';
    if ((int)($row['short_lease'] ?? 0))         $bits[] = 'short-lease';
    return $bits ? implode(' · ', $bits) : '—';
}

// ── Subnet source + host_ids (POST depuis la barre de sélection) ──────────────
$sourceId     = (int)($_POST['subnet_id'] ?? 0);
$sourceSubnet = Subnet::getById($sourceId);
if (!$sourceSubnet) { header('Location: dashboard.php'); exit; }

$rawIds  = array_filter(array_map('intval', explode(',', (string)($_POST['host_ids'] ?? ''))));
$hostIds = [];
foreach (array_unique($rawIds) as $hid) {
    if ($hid <= 0) continue;
    $r = Reservation::getById($hid);
    if ($r && (int)$r['dhcp4_subnet_id'] === (int)$sourceSubnet['kea_subnet_id']) {
        $hostIds[] = $hid;
    }
}
if (!$hostIds) {
    $_SESSION['flash'] = ['type'=>'danger','message'=>'Aucune réservation valide sélectionnée.'];
    header('Location: subnet.php?id=' . $sourceId); exit;
}

$step = (string)($_POST['step'] ?? '0');
$allSubnets = Subnet::getAll();
$targets = array_filter($allSubnets, fn($s) => (int)$s['id'] !== $sourceId);

// ═══════════════════════════════════════════════════════════════════════════
// STEP 2 — Application
// ═══════════════════════════════════════════════════════════════════════════
if ($step === '2') {
    $dstId     = (int)($_POST['dst_subnet_id'] ?? 0);
    $dstSubnet = Subnet::getById($dstId);
    if (!$dstSubnet || $dstId === $sourceId || (int)($dstSubnet['is_active'] ?? 1) !== 1) {
        $_SESSION['flash'] = ['type'=>'danger','message'=>'Subnet de destination invalide.'];
        header('Location: subnet.php?id=' . $sourceId); exit;
    }
    $dstKeaId    = (int)$dstSubnet['kea_subnet_id'];
    $dstCidr     = $dstSubnet['cidr'];
    $dstReserved = $dstSubnet['reserved_ips'] ?? '';
    $rNet        = ReservedIps::networkIntFromCidr($dstCidr);

    $existingIps = [];
    foreach (Reservation::getBySubnet($dstKeaId) as $er) {
        if ($er['ip_address'] !== '') $existingIps[$er['ip_address']] = true;
    }
    $batchIps = [];

    $rows    = $_POST['r'] ?? [];
    $applied = 0; $skipped = 0; $errMessages = [];

    foreach ($rows as $row) {
        if (empty($row['do'])) { $skipped++; continue; }
        $status = $row['status'] ?? '';
        if (in_array($status, ['skip','pool','invalid'], true)) { $skipped++; continue; }

        // ── Conflit MAC : la MAC existe déjà dans le subnet cible ──────────────
        if ($status === 'mac_conflict') {
            $macAction = $row['mac_action'] ?? 'keep';
            if ($macAction !== 'update') { $skipped++; continue; }   // keep = skip
            $macHostId = (int)($row['mac_host_id'] ?? 0);
            if ($macHostId <= 0) { $errMessages[] = 'Réservation MAC existante introuvable.'; $skipped++; continue; }
            // On met à jour la réservation existante du subnet cible avec les données copiées.
            // L'IP est l'IP transposée ($row['ip']); re-valider comme les autres.
            $ip = trim((string)($row['ip'] ?? ''));
            if ($ip === '' || !isValidIp($ip) || !ipInCidr($ip, $dstCidr)
                || ReservationImportAnalyzer::inPool($ip, $dstSubnet)
                || ($rNet !== null && $dstReserved !== '' && ReservedIps::contains($dstReserved, $rNet, $ip) !== null)) {
                $errMessages[] = "MAJ MAC : IP « $ip » invalide/bloquée."; $skipped++; continue;
            }
            // doublon IP : autorisé si c'est la même résa (celle qu'on met à jour). Sinon bloquer.
            // Comme on met à jour $macHostId, une collision d'IP avec une AUTRE résa dst est possible → bloquer.
            if ((isset($existingIps[$ip]) || isset($batchIps[$ip]))) {
                // Vérifier que l'IP n'appartient pas à une autre réservation que celle mise à jour.
                // Simplification sûre : si l'IP transposée est déjà prise, on bloque (l'utilisateur peut d'abord régler le conflit IP).
                $errMessages[] = "MAJ MAC : IP « $ip » déjà utilisée par une autre réservation."; $skipped++; continue;
            }
            $routes = [];
            foreach (explode(',', (string)($row['routes_raw'] ?? '')) as $part) {
                $part = trim($part);
                if ($part === '') continue;
                $pieces = strpos($part, ' - ') !== false ? explode(' - ', $part, 2) : preg_split('/\s+/', $part, 2);
                if (count($pieces) === 2) $routes[] = ['dest'=>trim($pieces[0]),'gw'=>trim($pieces[1])];
            }
            $data = [
                'mac'         => (string)($row['mac'] ?? ''),
                'ip'          => $ip,
                'hostname'    => (string)($row['hostname'] ?? ''),
                'description' => (string)($row['description'] ?? ''),
                'group_name'  => (string)($row['group_name'] ?? ''),
                'gateway'     => (int)($row['no_gateway'] ?? 0) ? '' : (string)($row['gateway'] ?? ''),
                'no_gateway'  => (int)($row['no_gateway'] ?? 0),
                'routes'      => $routes,
                'short_lease' => (int)($row['short_lease'] ?? 0),
            ];
            try {
                Reservation::update($macHostId, $data);
                $batchIps[$ip] = true;
                $applied++;
            } catch (Throwable $e) {
                $errMessages[] = 'Erreur MAJ : ' . $e->getMessage();
            }
            continue;
        }

        $ip = trim((string)($row['ip'] ?? ''));
        if ($ip === '')                 { $errMessages[] = 'Une ligne sans IP a été ignorée.'; $skipped++; continue; }
        if (!isValidIp($ip))            { $errMessages[] = "IP « $ip » invalide."; $skipped++; continue; }
        if (!ipInCidr($ip, $dstCidr))   { $errMessages[] = "IP « $ip » hors subnet."; $skipped++; continue; }
        if (ReservationImportAnalyzer::inPool($ip, $dstSubnet)) { $errMessages[] = "IP « $ip » dans le pool dynamique."; $skipped++; continue; }
        if ($rNet !== null && $dstReserved !== '' && ReservedIps::contains($dstReserved, $rNet, $ip) !== null) {
            $errMessages[] = "IP « $ip » réservée (hors DHCP)."; $skipped++; continue;
        }
        if (isset($existingIps[$ip]) || isset($batchIps[$ip])) { $errMessages[] = "IP « $ip » déjà utilisée."; $skipped++; continue; }

        // routes_raw "dest - gw, dest - gw" → [{dest,gw}]
        $routes = [];
        foreach (explode(',', (string)($row['routes_raw'] ?? '')) as $part) {
            $part = trim($part);
            if ($part === '') continue;
            $pieces = strpos($part, ' - ') !== false ? explode(' - ', $part, 2) : preg_split('/\s+/', $part, 2);
            if (count($pieces) === 2) $routes[] = ['dest'=>trim($pieces[0]),'gw'=>trim($pieces[1])];
        }

        $data = [
            'mac'         => (string)($row['mac'] ?? ''),
            'ip'          => $ip,
            'hostname'    => (string)($row['hostname'] ?? ''),
            'description' => (string)($row['description'] ?? ''),
            'group_name'  => (string)($row['group_name'] ?? ''),
            'gateway'     => (int)($row['no_gateway'] ?? 0) ? '' : (string)($row['gateway'] ?? ''),
            'no_gateway'  => (int)($row['no_gateway'] ?? 0),
            'routes'      => $routes,
            'short_lease' => (int)($row['short_lease'] ?? 0),
        ];
        try {
            Reservation::add($dstKeaId, $data);
            $batchIps[$ip] = true;
            $applied++;
        } catch (Throwable $e) {
            $errMessages[] = 'Erreur : ' . $e->getMessage();
        }
    }

    $sync = SyncService::sync();
    AuditLog::log('reservation.copy', 'subnet', (int)$dstSubnet['id'],
        "$applied copiée(s) de « {$sourceSubnet['name']} » vers « {$dstSubnet['name']} »"
        . ($skipped ? " ($skipped ignorée(s))" : ''));

    $msg = "$applied réservation(s) copiée(s) vers « {$dstSubnet['name']} »"
         . ($skipped ? ", $skipped ignorée(s)" : '') . '.';
    if ($errMessages) $msg .= ' ' . implode(' ', array_slice($errMessages, 0, 5));
    $_SESSION['flash'] = ['type'=> $sync['success'] ? 'success' : 'warning',
        'message'=> $sync['success'] ? $msg : ($msg . ' ⚠ ' . $sync['message'])];
    header('Location: subnet.php?id=' . (int)$dstSubnet['id']); exit;
}

// ═══════════════════════════════════════════════════════════════════════════
// STEP 1 — Prévisualisation
// ═══════════════════════════════════════════════════════════════════════════
if ($step === '1') {
    $dstId     = (int)($_POST['dst_subnet_id'] ?? 0);
    $dstSubnet = Subnet::getById($dstId);
    if (!$dstSubnet || $dstId === $sourceId || (int)($dstSubnet['is_active'] ?? 1) !== 1) {
        $_SESSION['flash'] = ['type'=>'danger','message'=>'Subnet de destination invalide.'];
        header('Location: subnet.php?id=' . $sourceId); exit;
    }

    // Bornes réseau source & cible (préfixe source, réseau+préfixe cible) pour remapIp
    [, $srcBits]           = array_pad(explode('/', $sourceSubnet['cidr']), 2, '32');
    [$dstNetStr, $dstBits] = array_pad(explode('/', $dstSubnet['cidr']), 2, '32');
    $dstNet    = (int)sprintf('%u', ip2long($dstNetStr));
    $srcPrefix = (int)$srcBits;
    $dstPrefix = (int)$dstBits;

    $srcRes  = Reservation::getBySubnet($sourceSubnet['kea_subnet_id']);
    $srcById = [];
    foreach ($srcRes as $r) $srcById[(int)$r['host_id']] = $r;

    $rawRows = [];
    $overflowLines = [];
    $line = 1;
    foreach ($hostIds as $hid) {
        $r = $srcById[$hid] ?? null;
        if (!$r) continue;
        $line++;

        // Remap IP réservation
        $newIp = '';
        $overflow = false;
        if ($r['ip_address'] !== '' && $r['ip_address'] !== '0.0.0.0') {
            $mapped = SubnetRemap::remapIp($r['ip_address'], $srcPrefix, $dstNet, $dstPrefix);
            if ($mapped === null) $overflow = true;
            else $newIp = $mapped;
        }

        // Remap gateway si interne au réseau source
        $gw = $r['gateway'] ?? '';
        if ($gw !== '' && ipInCidr($gw, $sourceSubnet['cidr'])) {
            $mgw = SubnetRemap::remapIp($gw, $srcPrefix, $dstNet, $dstPrefix);
            if ($mgw !== null) $gw = $mgw;
        }

        // Remap gw de chaque route (dest inchangé, gw interne uniquement) → "dest - gw"
        $routesStr = [];
        foreach (($r['routes'] ?? []) as $rt) {
            $rgw = $rt['gw'];
            if ($rgw !== '' && ipInCidr($rgw, $sourceSubnet['cidr'])) {
                $m = SubnetRemap::remapIp($rgw, $srcPrefix, $dstNet, $dstPrefix);
                if ($m !== null) $rgw = $m;
            }
            $routesStr[] = $rt['dest'] . ' - ' . $rgw;
        }

        $rawRows[] = [
            'line'        => $line,
            'mac_raw'     => $r['mac'],
            'ip'          => $newIp,
            'hostname'    => $r['hostname'],
            'description' => $r['description'] ?? '',
            'subnet_name' => '',
            'gateway'     => $gw,
            'routes_raw'  => implode(', ', $routesStr),
            'short_lease' => (int)($r['short_lease'] ?? 0),
            'no_gateway'  => (int)($r['no_gateway'] ?? 0),
            'group_name'  => $r['group_name'] ?? '',
            'src_ip'      => $r['ip_address'],
        ];
        if ($overflow) $overflowLines[$line] = true;
    }

    $analyzed = ReservationImportAnalyzer::analyzeRows($rawRows, $dstSubnet, [], false);

    // Réinjecter src_ip (perdu par analyzeRows) + forcer statut overflow
    $srcIpByLine = [];
    foreach ($rawRows as $rr) $srcIpByLine[$rr['line']] = $rr['src_ip'];
    foreach ($analyzed as &$a) {
        $a['src_ip'] = $srcIpByLine[$a['line']] ?? '';
        if (!empty($overflowLines[$a['line']])) {
            $a['status'] = 'overflow';
            $a['note']   = 'Hôte hors du masque cible — saisir une IP';
        }
    }
    unset($a);

    $cClean    = count(array_filter($analyzed, fn($r) => $r['status'] === 'clean'));
    $cConflict = count(array_filter($analyzed, fn($r) => in_array($r['status'], ['ip_conflict','mac_conflict','reserved','overflow'])));
    $cIgnored  = count(array_filter($analyzed, fn($r) => in_array($r['status'], ['skip','pool','invalid'])));

    $dstKeaId  = (int)$dstSubnet['kea_subnet_id'];
    $sbgSubnet = buildBargraphSubnet($dstSubnet);
    $dstRes    = Reservation::getBySubnet($dstKeaId);

    $page_title = 'Copier vers ' . $dstSubnet['name'];
    require_once APP_ROOT . '/lib/layout_header.php';
    ?>

<div class="mb-3">
    <a href="subnet.php?id=<?= $sourceId ?>" class="text-muted text-decoration-none">
        <i class="bi bi-arrow-left"></i> <?= h($sourceSubnet['name']) ?>
    </a>
</div>

<div class="card">
    <div class="card-header py-3">
        <div class="d-flex justify-content-between align-items-center flex-wrap gap-2">
            <span>
                <i class="bi bi-files me-2"></i>
                Copier vers <?= h($dstSubnet['name']) ?> · <code><?= h($dstSubnet['cidr']) ?></code>
            </span>
            <span>
                <span class="text-success"><?= $cClean ?> prête(s)</span>
                &nbsp;·&nbsp;
                <span class="text-warning"><?= $cConflict ?> à corriger</span>
                &nbsp;·&nbsp;
                <span class="text-secondary"><?= $cIgnored ?> ignorée(s)</span>
            </span>
        </div>
    </div>
    <div class="card-body">

        <div id="subnet-bargraph" class="mb-3"></div>

        <form method="post" action="subnet_copy.php" id="copy-apply-form">
            <input type="hidden" name="step" value="2">
            <input type="hidden" name="subnet_id" value="<?= $sourceId ?>">
            <input type="hidden" name="dst_subnet_id" value="<?= (int)$dstSubnet['id'] ?>">
            <input type="hidden" name="host_ids" value="<?= h(implode(',', $hostIds)) ?>">

            <div class="table-responsive">
                <table class="table table-sm align-middle res-copy-table">
                    <thead class="table-light">
                        <tr>
                            <th style="width:32px"></th>
                            <th>Hostname</th>
                            <th>MAC</th>
                            <th>IP source → cible</th>
                            <th>Options</th>
                            <th>Statut</th>
                        </tr>
                    </thead>
                    <tbody>
                    <?php foreach ($analyzed as $i => $row):
                        $editable = in_array($row['status'], ['ip_conflict','reserved','overflow'], true);
                        $ignored  = in_array($row['status'], ['skip','pool','invalid'], true);
                        $checked  = !$ignored;
                    ?>
                        <tr class="copy-row status-<?= h($row['status']) ?>">
                            <td>
                                <input type="checkbox" class="form-check-input" name="r[<?= $i ?>][do]" value="1"
                                    <?= $checked ? 'checked' : '' ?> <?= $ignored ? 'disabled' : '' ?>>
                                <input type="hidden" name="r[<?= $i ?>][status]" value="<?= h($row['status']) ?>">
                            </td>
                            <td>
                                <?= h($row['hostname']) ?>
                                <input type="hidden" name="r[<?= $i ?>][hostname]" value="<?= h($row['hostname']) ?>">
                                <input type="hidden" name="r[<?= $i ?>][description]" value="<?= h($row['description']) ?>">
                                <input type="hidden" name="r[<?= $i ?>][group_name]" value="<?= h($row['group_name']) ?>">
                            </td>
                            <td class="font-monospace small">
                                <?= h($row['mac']) ?>
                                <input type="hidden" name="r[<?= $i ?>][mac]" value="<?= h($row['mac']) ?>">
                                <input type="hidden" name="r[<?= $i ?>][mac_host_id]" value="<?= (int)($row['mac_host_id'] ?? 0) ?>">
                            </td>
                            <td>
                                <span class="text-muted"><?= h($row['src_ip']) ?></span> →
                                <?php if ($editable): ?>
                                    <input type="text" name="r[<?= $i ?>][ip]" value="<?= h($row['ip']) ?>"
                                        class="form-control form-control-sm d-inline-block ip-field" style="width:130px" placeholder="IP cible">
                                <?php else: ?>
                                    <input type="hidden" name="r[<?= $i ?>][ip]" value="<?= h($row['ip']) ?>">
                                    <span class="<?= $ignored ? 'text-decoration-line-through text-muted' : 'text-success' ?>"><?= h($row['ip']) ?></span>
                                <?php endif; ?>
                            </td>
                            <td class="small">
                                <?= h(copyOptionsSummary($row)) ?>
                                <input type="hidden" name="r[<?= $i ?>][gateway]" value="<?= h($row['gateway']) ?>">
                                <input type="hidden" name="r[<?= $i ?>][routes_raw]" value="<?= h($row['routes_raw']) ?>">
                                <input type="hidden" name="r[<?= $i ?>][short_lease]" value="<?= h($row['short_lease']) ?>">
                                <input type="hidden" name="r[<?= $i ?>][no_gateway]" value="<?= h($row['no_gateway']) ?>">
                            </td>
                            <td class="small">
                                <?php if ($row['status'] === 'mac_conflict'): ?>
                                    <div class="small text-muted mb-1"><?= h($row['note']) ?></div>
                                    <select name="r[<?= $i ?>][mac_action]" class="form-select form-select-sm" style="width:220px">
                                        <option value="keep">Conserver l'existant (ignorer)</option>
                                        <option value="update">Mettre à jour → <?= h($row['ip']) ?></option>
                                    </select>
                                <?php else: ?>
                                    <?= h($row['note']) ?>
                                <?php endif; ?>
                            </td>
                        </tr>
                    <?php endforeach; ?>
                    </tbody>
                </table>
            </div>

            <div class="d-flex gap-2 mt-3">
                <button type="submit" class="btn btn-primary">
                    <i class="bi bi-files"></i> Copier les réservations cochées
                </button>
                <a href="subnet.php?id=<?= $sourceId ?>" class="btn btn-outline-secondary">Annuler</a>
            </div>
        </form>
    </div>
</div>

<script>
var SUBNET = <?= json_encode($sbgSubnet, JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP) ?>;
var EXISTING_ROWS = <?= json_encode(array_map(function($r){
    return ['ip_int'=>($r['ip_address']!==''&&$r['ip_address']!=='0.0.0.0')?(int)ipToInt($r['ip_address']):0,
            'hostname'=>$r['hostname'],'host_id'=>(int)$r['host_id'],'group_name'=>$r['group_name']??'','short_lease'=>(int)($r['short_lease']??0)];
}, $dstRes), JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP) ?>;
</script>
<script src="assets/js/subnet-bargraph.js"></script>
<script src="assets/js/subnet-copy.js"></script>

<?php
    require_once APP_ROOT . '/lib/layout_footer.php';
    exit;
}

// ═══════════════════════════════════════════════════════════════════════════
// STEP 0 — Choix du subnet cible (défaut)
// ═══════════════════════════════════════════════════════════════════════════
$page_title = 'Copier des réservations';
require_once APP_ROOT . '/lib/layout_header.php';
?>

<div class="row justify-content-center">
<div class="col-lg-6">

<div class="mb-3">
    <a href="subnet.php?id=<?= $sourceId ?>" class="text-muted text-decoration-none">
        <i class="bi bi-arrow-left"></i> <?= h($sourceSubnet['name']) ?>
    </a>
</div>

<div class="card">
    <div class="card-header py-3">
        <i class="bi bi-files me-2"></i>Copier des réservations
    </div>
    <div class="card-body">
        <p><?= count($hostIds) ?> réservation(s) depuis <?= h($sourceSubnet['name']) ?> (<code><?= h($sourceSubnet['cidr']) ?></code>)</p>

        <form method="post" action="subnet_copy.php">
            <input type="hidden" name="step" value="1">
            <input type="hidden" name="subnet_id" value="<?= $sourceId ?>">
            <input type="hidden" name="host_ids" value="<?= h(implode(',', $hostIds)) ?>">

            <div class="mb-3">
                <label class="form-label">Subnet de destination</label>
                <select name="dst_subnet_id" class="form-select" required>
                    <option value="">— choisir —</option>
                    <?php foreach ($targets as $t): ?>
                        <option value="<?= (int)$t['id'] ?>"><?= h($t['name']) ?> (<?= h($t['cidr']) ?>)</option>
                    <?php endforeach; ?>
                </select>
            </div>

            <div class="d-flex gap-2">
                <button type="submit" class="btn btn-primary">
                    <i class="bi bi-arrow-right"></i> Prévisualiser
                </button>
                <a href="subnet.php?id=<?= $sourceId ?>" class="btn btn-outline-secondary">Annuler</a>
            </div>
        </form>
    </div>
</div>

</div>
</div>

<?php require_once APP_ROOT . '/lib/layout_footer.php'; ?>
