<?php
// Vue autonome (layout none) pour supervision live en mode PiP
$activeAssignedCity = trim((string)($assignedCity ?? ($currentUser['assigned_city'] ?? '')));
$base = '';
if (isset($_SERVER['SCRIPT_NAME'])) {
    $scriptDir = dirname($_SERVER['SCRIPT_NAME']);
    $base = ($scriptDir === '/' || $scriptDir === '\\') ? '' : rtrim($scriptDir, '/\\');

    // Si la vue est servie via un fichier physique (/public/cartography/supervision/index.php),
    // on doit remonter au basePath de l'app (/public) pour que les endpoints API soient corrects.
    $base = preg_replace('~/(cartography|cartographie)/supervision$~', '', $base);
}

$views = isset($_GET['views']) ? (int)$_GET['views'] : 4;
$views = in_array($views, [1, 4], true) ? $views : 4;
?><!doctype html>
<html lang="fr">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title><?= htmlspecialchars($title ?? 'Supervision Live', ENT_QUOTES, 'UTF-8') ?></title>

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">

    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
    <link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.css" />
    <link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.Default.css" />

    <style>
        :root { color-scheme: dark; }
        html, body { height: 100%; margin: 0; }
        body { background: #0b1220; }

        .topbar {
            backdrop-filter: blur(8px);
            background: rgba(17, 24, 39, 0.92);
            border-bottom: 1px solid rgba(255,255,255,0.08);
        }

        .content {
            height: calc(100% - 58px);
            padding: 10px;
            box-sizing: border-box;
        }

        .grid-1 {
            height: 100%;
            display: grid;
            grid-template-columns: 1fr;
            grid-template-rows: 1fr;
            gap: 10px;
        }

        .grid-4 {
            height: 100%;
            display: grid;
            grid-template-columns: 1fr 1fr;
            grid-template-rows: 1fr 1fr;
            gap: 10px;
        }

        .panel {
            position: relative;
            overflow: hidden;
            border-radius: 12px;
            border: 1px solid rgba(255,255,255,0.08);
            background: rgba(255,255,255,0.04);
        }

        .panel-header {
            position: absolute;
            top: 10px;
            left: 10px;
            z-index: 500;
            padding: 6px 10px;
            border-radius: 10px;
            background: rgba(17,24,39,0.72);
            border: 1px solid rgba(255,255,255,0.10);
            font-size: 12px;
            max-width: calc(100% - 20px);
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        /* Effets scintillants / live */
        .pulse-dot {
            width: 10px;
            height: 10px;
            border-radius: 999px;
            background: var(--bs-success);
            box-shadow: 0 0 0 0 rgba(25, 135, 84, 0.7);
            animation: pulse 1.6s infinite;
        }

        @keyframes pulse {
            0% { box-shadow: 0 0 0 0 rgba(25,135,84,0.65); }
            70% { box-shadow: 0 0 0 10px rgba(25,135,84,0); }
            100% { box-shadow: 0 0 0 0 rgba(25,135,84,0); }
        }

        .sparkle {
            position: relative;
            overflow: hidden;
        }

        .sparkle::after {
            content: '';
            position: absolute;
            top: -50%;
            left: -60%;
            width: 40%;
            height: 200%;
            transform: rotate(25deg);
            background: linear-gradient(90deg, transparent, rgba(255,255,255,0.18), transparent);
            animation: shimmer 2.2s infinite;
        }

        @keyframes shimmer {
            0% { left: -60%; }
            100% { left: 120%; }
        }

        /* Pins Leaflet (techniciens / incidents) */
        .pin {
            width: 26px;
            height: 26px;
            border-radius: 999px;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 2px solid rgba(255,255,255,0.95);
            box-shadow: 0 10px 22px rgba(0,0,0,0.35);
            font-weight: 800;
            font-size: 11px;
            color: rgba(255,255,255,0.95);
        }

        .pin.pin-tech { background: var(--bs-success); }
        .pin.pin-tech-approx { background: var(--bs-warning); color: #111827; }
        .pin.pin-tech-off { background: var(--bs-secondary); }
        .pin.pin-inc-open { background: var(--bs-danger); }
        .pin.pin-inc-progress { background: var(--bs-warning); color: #111827; }
        .pin.pin-inc-resolved { background: var(--bs-success); }

        .leaflet-popup-content { margin: 10px 12px; }
        .leaflet-popup-content-wrapper { border-radius: 12px; }
        .leaflet-container a { color: var(--bs-primary); }

        .map {
            width: 100%;
            height: 100%;
        }

        @media (max-width: 900px) {
            .grid-4 { grid-template-columns: 1fr; grid-template-rows: repeat(4, 1fr); }
            .content { height: calc(100% - 86px); }
        }
    </style>
</head>
<body>
    <div class="topbar px-2 py-2">
        <div class="d-flex align-items-center justify-content-between gap-2 flex-wrap">
            <div class="text-light">
                <div class="fw-bold">Supervision Live</div>
                <div class="small text-secondary" id="lastUpdate">Mise à jour: --:--</div>
                <?php if ($activeAssignedCity !== ''): ?>
                <div class="small text-info">Ville active: <?= htmlspecialchars($activeAssignedCity) ?></div>
                <?php endif; ?>
            </div>
            <div class="d-flex align-items-center gap-2 flex-wrap justify-content-end">
                <div class="d-inline-flex align-items-center gap-2 small text-light">
                    <span class="pulse-dot"></span>
                    <span id="statusText">En ligne</span>
                </div>
                <button type="button" id="btn1" class="btn btn-sm btn-outline-light" data-views="1">1 vue</button>
                <button type="button" id="btn4" class="btn btn-sm btn-outline-light" data-views="4">4 vues</button>
                <button type="button" id="btnClose" class="btn btn-sm btn-light">Fermer</button>
            </div>
        </div>
    </div>

    <div class="content">
        <div id="grid" class="<?= $views === 4 ? 'grid-4' : 'grid-1' ?>">
            <div class="panel" data-panel="1">
                <div class="panel-header" id="label1">Techniciens + Traçés (Aujourd’hui)</div>
                <div id="map1" class="map"></div>
            </div>
            <div class="panel" data-panel="2" <?= $views === 1 ? 'style="display:none"' : '' ?>>
                <div class="panel-header" id="label2">Incidents ouverts</div>
                <div id="map2" class="map"></div>
            </div>
            <div class="panel" data-panel="3" <?= $views === 1 ? 'style="display:none"' : '' ?>>
                <div class="panel-header" id="label3">Incidents en cours</div>
                <div id="map3" class="map"></div>
            </div>
            <div class="panel" data-panel="4" <?= $views === 1 ? 'style="display:none"' : '' ?>>
                <div class="panel-header" id="label4">Incidents résolus</div>
                <div id="map4" class="map"></div>
            </div>
        </div>
    </div>

    <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
    <script src="https://unpkg.com/leaflet.markercluster@1.5.3/dist/leaflet.markercluster.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>

    <script>
        const BASE = <?= json_encode($base) ?>;
        const DEFAULT_CENTER = [5.35, -4.02];
        const DEFAULT_ZOOM = 6;

        const REFRESH_TECH_MS = 15000;
        const REFRESH_INCIDENT_MS = 60000;
        const REFRESH_TRAJ_MS = 60000;
        const TRAJ_HOURS = 24;

        let modeViews = <?= (int)$views ?>; // 1 ou 4
        let maps = [];
        let refreshTimers = [];

        let cacheIncidents = [];
        let cacheTechnicians = [];
        let cacheTrajectories = [];

        let isSyncing = false;

        function nowLabel() {
            return new Date().toLocaleTimeString('fr-FR');
        }

        function setLastUpdate() {
            const el = document.getElementById('lastUpdate');
            if (el) el.textContent = `Mise à jour: ${nowLabel()}`;
        }

        function getIncidentBucket(incident) {
            const status = (incident?.status || '').toLowerCase();
            const isResolved = status.includes('clôtur') || status.includes('terminé') || status.includes('résolu') || status.includes('fermé');
            if (isResolved) return 'resolved';
            const isInProgress = status.includes('cours') || status.includes('attribué') || status.includes('traitement');
            if (isInProgress) return 'in_progress';
            return 'open';
        }

        function createTechIcon(tech) {
            const isActive = tech.is_active || (tech.age_seconds && tech.age_seconds < 300);
            const acc = (tech.accuracy !== null && tech.accuracy !== undefined) ? Number(tech.accuracy) : null;
            const isApprox = (acc !== null && !isNaN(acc) && acc > 30);

            const cls = !isActive ? 'pin pin-tech-off' : (isApprox ? 'pin pin-tech-approx sparkle' : 'pin pin-tech sparkle');
            const letter = (tech.name || 'T').trim().slice(0, 1).toUpperCase();

            return L.divIcon({
                html: `<div class="${cls}" title="${(tech.name || 'Technicien').replace(/"/g,'&quot;')}">${letter}</div>`,
                className: '',
                iconSize: [26, 26],
                iconAnchor: [13, 13]
            });
        }


        function createIncidentMarker(incident) {
            if (!incident.lat || !incident.lng) return null;

            const bucket = getIncidentBucket(incident);
            const cls = bucket === 'resolved' ? 'pin pin-inc-resolved sparkle' : (bucket === 'in_progress' ? 'pin pin-inc-progress sparkle' : 'pin pin-inc-open sparkle');

            const icon = L.divIcon({
                html: `<div class="${cls}">!</div>`,
                className: '',
                iconSize: [26, 26],
                iconAnchor: [13, 13]
            });

            const statusBadge = bucket === 'resolved'
                ? '<span class="badge rounded-pill text-bg-success">Résolu</span>'
                : (bucket === 'in_progress' ? '<span class="badge rounded-pill text-bg-warning">En cours</span>' : '<span class="badge rounded-pill text-bg-danger">Ouvert</span>');

            const priority = (incident.priority || '—');
            const priorityBadge = (String(priority).toLowerCase().includes('crit'))
                ? '<span class="badge text-bg-danger">Critique</span>'
                : (String(priority).toLowerCase().includes('haut') ? '<span class="badge text-bg-warning">Haute</span>' : '<span class="badge text-bg-secondary">' + priority + '</span>');

            return L.marker([incident.lat, incident.lng], { icon })
                .bindPopup(`
                    <div class="card border-0" style="min-width:260px">
                        <div class="card-body p-3">
                            <div class="d-flex align-items-start justify-content-between gap-2">
                                <div class="fw-bold">${incident.title || 'Incident'}</div>
                                <div class="d-flex gap-1">${statusBadge}${priorityBadge}</div>
                            </div>
                            <div class="small text-secondary mt-2">
                                <div><span class="fw-semibold text-dark">Statut:</span> ${incident.status || '—'}</div>
                                <div><span class="fw-semibold text-dark">Priorité:</span> ${priority}</div>
                                ${incident.location ? `<div><span class="fw-semibold text-dark">Lieu:</span> ${incident.location}</div>` : ''}
                            </div>
                        </div>
                    </div>
                `);
        }

        function buildBaseLayers() {
            return {
                "OpenStreetMap": L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                    maxZoom: 19,
                    attribution: '&copy; OpenStreetMap'
                }),
                "Satellite": L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
                    maxZoom: 19,
                    attribution: '&copy; Esri'
                })
            };
        }

        function createMapView(containerId, isPrimary) {
            const m = L.map(containerId, { zoomControl: true }).setView(DEFAULT_CENTER, DEFAULT_ZOOM);
            const base = buildBaseLayers();
            base["OpenStreetMap"].addTo(m);

            const incidentsLayer = L.layerGroup().addTo(m);
            const techsLayer = L.layerGroup().addTo(m);
            const trajectoriesLayer = L.layerGroup().addTo(m);

            L.control.layers(base, {
                'Incidents': incidentsLayer,
                'Techniciens': techsLayer,
                'Traçés': trajectoriesLayer,
            }, { position: 'topright', collapsed: true }).addTo(m);

            if (isPrimary) {
                m.on('moveend zoomend', () => {
                    if (isSyncing) return;
                    isSyncing = true;
                    const center = m.getCenter();
                    const zoom = m.getZoom();
                    maps.forEach(v => {
                        if (v.map !== m) v.map.setView(center, zoom, { animate: false });
                    });
                    setTimeout(() => { isSyncing = false; }, 0);
                });
            }

            return { map: m, incidentsLayer, techsLayer, trajectoriesLayer };
        }

        function clearLayers(view) {
            view.incidentsLayer.clearLayers();
            view.techsLayer.clearLayers();
            view.trajectoriesLayer.clearLayers();
        }

        function renderTechnicians(view) {
            cacheTechnicians.forEach(tech => {
                if (!tech.lat || !tech.lng) return;
                const icon = createTechIcon(tech);

                const acc = (tech.accuracy !== null && tech.accuracy !== undefined) ? Number(tech.accuracy) : null;
                const isApprox = (acc !== null && !isNaN(acc) && acc > 30);
                const isActive = tech.is_active || (tech.age_seconds && tech.age_seconds < 300);
                const stateBadge = !isActive
                    ? '<span class="badge rounded-pill text-bg-secondary">Hors-ligne</span>'
                    : (isApprox ? '<span class="badge rounded-pill text-bg-warning">Approx.</span>' : '<span class="badge rounded-pill text-bg-success">Actif</span>');

                const last = tech.updated_at ? new Date(tech.updated_at).toLocaleString('fr-FR') : '—';
                const ageMin = tech.age_seconds ? Math.round(tech.age_seconds / 60) : null;

                const marker = L.marker([tech.lat, tech.lng], { icon })
                    .bindTooltip(tech.name || 'Technicien')
                    .bindPopup(`
                        <div class="card border-0" style="min-width:260px">
                            <div class="card-body p-3">
                                <div class="d-flex align-items-start justify-content-between gap-2">
                                    <div class="fw-bold">${tech.name || 'Technicien'}</div>
                                    <div>${stateBadge}</div>
                                </div>
                                <div class="small text-secondary mt-2">
                                    <div><span class="fw-semibold text-dark">Dernière position:</span> ${last}</div>
                                    ${ageMin !== null ? `<div><span class="fw-semibold text-dark">Âge:</span> ${ageMin} min</div>` : ''}
                                    ${acc !== null && !isNaN(acc) ? `<div><span class="fw-semibold text-dark">Précision:</span> ±${Math.round(acc)} m</div>` : ''}
                                </div>
                                ${isApprox ? `<div class="alert alert-warning py-2 px-2 mt-2 mb-0"><div class="fw-semibold">Localisation approximative</div><div class="small mb-0">Activez “Position précise” + GPS pour améliorer.</div></div>` : ''}
                            </div>
                        </div>
                    `);
                view.techsLayer.addLayer(marker);

                if (acc !== null && !isNaN(acc) && acc > 0) {
                    const radius = Math.min(acc, 200);
                    view.techsLayer.addLayer(L.circle([tech.lat, tech.lng], {
                        radius,
                        color: isApprox ? '#f59e0b' : '#10b981',
                        weight: 1,
                        fillColor: isApprox ? '#f59e0b' : '#10b981',
                        fillOpacity: isApprox ? 0.06 : 0.10,
                        interactive: false,
                    }));
                }
            });
        }

        function renderIncidents(view, bucket) {
            cacheIncidents.forEach(incident => {
                if (!incident.lat || !incident.lng) return;
                if (bucket && bucket !== 'all') {
                    if (getIncidentBucket(incident) !== bucket) return;
                }
                const marker = createIncidentMarker(incident);
                if (marker) view.incidentsLayer.addLayer(marker);
            });
        }

        function renderTrajectories(view) {
            const colors = ['#3b82f6', '#ef4444', '#10b981', '#f59e0b', '#8b5cf6', '#ec4899'];
            cacheTrajectories.forEach((traj, idx) => {
                if (!traj.points || traj.points.length < 2) return;
                const color = colors[idx % colors.length];
                const latlngs = traj.points.map(p => [p.lat, p.lng]);
                L.polyline(latlngs, { color, weight: 4, opacity: 0.85 }).addTo(view.trajectoriesLayer);
            });
        }

        function renderAll() {
            maps.forEach((view, idx) => {
                clearLayers(view);

                // Toujours afficher les techniciens (supervision live)
                renderTechnicians(view);

                if (modeViews === 1) {
                    renderIncidents(view, 'all');
                    renderTrajectories(view);
                    return;
                }

                // Mode 4 vues: panel 1 = tech + trajectoires, 2/3/4 = incidents par statut
                if (idx === 0) {
                    renderTrajectories(view);
                } else if (idx === 1) {
                    renderIncidents(view, 'open');
                } else if (idx === 2) {
                    renderIncidents(view, 'in_progress');
                } else if (idx === 3) {
                    renderIncidents(view, 'resolved');
                }
            });

            setLastUpdate();
        }

        async function loadIncidents() {
            try {
                const res = await fetch(`${BASE}/cartography/data`, { credentials: 'include' });
                if (!res.ok) throw new Error(`HTTP ${res.status}`);
                const data = await res.json();
                cacheIncidents = Array.isArray(data) ? data : [];
            } catch (e) {
                cacheIncidents = [];
            }
        }

        async function loadTechnicians() {
            try {
                const res = await fetch(`${BASE}/cartography/technicians?max_age=1440`, { credentials: 'include' });
                if (!res.ok) throw new Error(`HTTP ${res.status}`);
                const data = await res.json();
                cacheTechnicians = Array.isArray(data) ? data : [];
            } catch (e) {
                cacheTechnicians = [];
            }
        }

        async function loadTrajectories() {
            try {
                const res = await fetch(`${BASE}/cartography/trajectories?hours=${TRAJ_HOURS}`, { credentials: 'include' });
                if (!res.ok) throw new Error(`HTTP ${res.status}`);
                const data = await res.json();
                cacheTrajectories = Array.isArray(data) ? data : [];
            } catch (e) {
                cacheTrajectories = [];
            }
        }

        function stopTimers() {
            refreshTimers.forEach(id => clearInterval(id));
            refreshTimers = [];
        }

        function startTimers() {
            stopTimers();

            refreshTimers.push(setInterval(async () => {
                await loadTechnicians();
                renderAll();
            }, REFRESH_TECH_MS));

            refreshTimers.push(setInterval(async () => {
                await loadIncidents();
                renderAll();
            }, REFRESH_INCIDENT_MS));

            refreshTimers.push(setInterval(async () => {
                // Trajectoires: toujours utiles en supervision (au moins pour la vue 1)
                await loadTrajectories();
                renderAll();
            }, REFRESH_TRAJ_MS));
        }

        function setModeViews(next) {
            modeViews = next;

            const grid = document.getElementById('grid');
            const btn1 = document.getElementById('btn1');
            const btn4 = document.getElementById('btn4');

            if (btn1) btn1.classList.toggle('active', modeViews === 1);
            if (btn4) btn4.classList.toggle('active', modeViews === 4);

            if (grid) {
                grid.className = modeViews === 4 ? 'grid-4' : 'grid-1';
            }

            document.querySelectorAll('.panel').forEach((p) => {
                const n = Number(p.getAttribute('data-panel'));
                if (modeViews === 1) {
                    p.style.display = (n === 1) ? '' : 'none';
                } else {
                    p.style.display = '';
                }
            });

            // Recréer les maps pour éviter les soucis de tailles/dimensions
            initializeMaps();
        }

        function destroyMaps() {
            maps.forEach(v => {
                try { v.map.remove(); } catch (e) {}
            });
            maps = [];
        }

        function initializeMaps() {
            destroyMaps();

            maps.push(createMapView('map1', true));
            if (modeViews === 4) {
                maps.push(createMapView('map2', false));
                maps.push(createMapView('map3', false));
                maps.push(createMapView('map4', false));
            }

            // Dimensionnement Leaflet
            setTimeout(() => {
                maps.forEach(v => v.map.invalidateSize(true));
            }, 250);

            renderAll();
        }

        async function bootstrap() {
            document.getElementById('btnClose')?.addEventListener('click', () => window.close());
            document.getElementById('btn1')?.addEventListener('click', () => setModeViews(1));
            document.getElementById('btn4')?.addEventListener('click', () => setModeViews(4));

            // état initial boutons
            document.getElementById('btn1')?.classList.toggle('active', modeViews === 1);
            document.getElementById('btn4')?.classList.toggle('active', modeViews === 4);

            initializeMaps();

            await Promise.all([loadIncidents(), loadTechnicians(), loadTrajectories()]);
            renderAll();

            startTimers();
        }

        window.addEventListener('beforeunload', () => {
            stopTimers();
            destroyMaps();
        });

        bootstrap();
    </script>
</body>
</html>
