<?php
// engine.php
// World simulation client: connects to server, renders main map, syncs players/vehicles,
// and talks to uix.php (HUD/phone/minimap) via postMessage.

// You can pass auth/session info via PHP if needed:
$playerId = isset($_GET['pid']) ? htmlspecialchars($_GET['pid']) : 'guest_' . rand(1000, 9999);
$wsUrl    = 'wss://your-game-server.example.com/ws'; // TODO: replace with real WebSocket endpoint
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Engine</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!-- MapLibre GL -->
    <link href="https://unpkg.com/maplibre-gl@3.6.1/dist/maplibre-gl.css" rel="stylesheet" />
    <script src="https://unpkg.com/maplibre-gl@3.6.1/dist/maplibre-gl.js"></script>

    <style>
        html, body {
            margin: 0;
            padding: 0;
            overflow: hidden;
            width: 100%;
            height: 100%;
            background: #000;
            font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
        }

        #world-container {
            position: relative;
            width: 100%;
            height: 100%;
        }

        #world-map {
            position: absolute;
            inset: 0;
        }

        /* World map zoom controls (for main map, not minimap) */
        #world-zoom-controls {
            position: absolute;
            top: 10px;
            right: 10px;
            display: flex;
            flex-direction: column;
            gap: 6px;
            z-index: 10;
        }

        .zoom-btn {
            width: 32px;
            height: 32px;
            border-radius: 4px;
            border: none;
            background: rgba(0, 0, 0, 0.65);
            color: #fff;
            font-size: 18px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 0 4px rgba(0, 0, 0, 0.6);
        }

        .zoom-btn:hover {
            background: rgba(0, 0, 0, 0.85);
        }

        /* Simple player marker */
        .player-marker {
            width: 18px;
            height: 18px;
            border-radius: 50%;
            background: #00ff88;
            border: 2px solid #003322;
            box-shadow: 0 0 6px rgba(0, 255, 136, 0.8);
        }

        /* Other players */
        .other-player-marker {
            width: 14px;
            height: 14px;
            border-radius: 50%;
            background: #00aaff;
            border: 2px solid #003355;
            box-shadow: 0 0 4px rgba(0, 170, 255, 0.8);
        }

        /* Excluded mode indicator for other players (outline) */
        .excluded-outline {
            box-shadow: 0 0 8px rgba(200, 200, 200, 0.9);
            border-color: #cccccc !important;
        }

        /* Vehicle markers */
        .vehicle-marker {
            width: 16px;
            height: 16px;
            border-radius: 3px;
            background: #ffcc00;
            border: 2px solid #664400;
            box-shadow: 0 0 4px rgba(255, 204, 0, 0.8);
        }

        /* World markers (shops, garages, etc.) */
        .world-marker {
            width: 14px;
            height: 14px;
            border-radius: 50%;
            background: #ff3366;
            border: 2px solid #66001f;
            box-shadow: 0 0 4px rgba(255, 51, 102, 0.8);
        }

        /* Debug overlay (optional) */
        #debug-overlay {
            position: absolute;
            left: 10px;
            top: 10px;
            padding: 6px 8px;
            background: rgba(0, 0, 0, 0.55);
            color: #fff;
            font-size: 11px;
            border-radius: 4px;
            z-index: 10;
            max-width: 260px;
            pointer-events: none;
        }
    </style>
</head>
<body>
<div id="world-container">
    <div id="world-map"></div>

    <div id="world-zoom-controls">
        <button class="zoom-btn" id="zoom-in">+</button>
        <button class="zoom-btn" id="zoom-out">−</button>
    </div>

    <div id="debug-overlay">
        Engine: connected = <span id="dbg-conn">false</span><br>
        Player: <span id="dbg-player-id"><?php echo $playerId; ?></span><br>
        Pos: <span id="dbg-pos">N/A</span><br>
        Speed: <span id="dbg-speed">0 km/h</span><br>
        Vehicle: <span id="dbg-vehicle">none</span><br>
        State: <span id="dbg-state">loading</span>
    </div>
</div>

<script>
    // --- CONFIG ---
    const PLAYER_ID = "<?php echo $playerId; ?>";
    const WS_URL    = "<?php echo $wsUrl; ?>";

    // Initial map center (placeholder: Nelson-ish)
    const INITIAL_CENTER = [173.283, -41.270]; // [lng, lat]
    const INITIAL_ZOOM   = 14;

    // --- GLOBAL STATE ---
    let map;
    let socket = null;
    let isConnected = false;

    let playerState = {
        id: PLAYER_ID,
        x: INITIAL_CENTER[0],
        y: INITIAL_CENTER[1],
        heading: 0,
        speedKmh: 0,
        hp: 100,
        shield: 0,
        vehicleId: null,
        excluded: false
    };

    let playerMarker = null;
    let otherPlayers = {};   // id -> { marker, data }
    let vehicles     = {};   // id -> { marker, data }
    let worldMarkers = {};   // id -> { marker, data }

    // --- INIT MAP ---
    function initMap() {
        map = new maplibregl.Map({
            container: 'world-map',
            style: 'https://api.maptiler.com/maps/019d3452-4395-7ecd-bbf0-c64a3d5060cd/style.json?key=uHmPABwBFcVhiPJcdCzb',
            center: INITIAL_CENTER,
            zoom: INITIAL_ZOOM,
            pitch: 0,
            bearing: 0
        });

        map.addControl(new maplibregl.NavigationControl({ showCompass: true, showZoom: false }), 'top-left');

        map.on('load', () => {
            createPlayerMarker();
        });
    }

    function createPlayerMarker() {
        const el = document.createElement('div');
        el.className = 'player-marker';

        playerMarker = new maplibregl.Marker({
            element: el,
            rotationAlignment: 'map'
        })
            .setLngLat([playerState.x, playerState.y])
            .addTo(map);
    }

    function updatePlayerMarker() {
        if (!playerMarker) return;
        playerMarker.setLngLat([playerState.x, playerState.y]);
        playerMarker.setRotation(playerState.heading || 0);
    }

    // --- OTHER PLAYERS ---
    function upsertOtherPlayer(p) {
        if (p.id === PLAYER_ID) return;

        let entry = otherPlayers[p.id];
        if (!entry) {
            const el = document.createElement('div');
            el.className = 'other-player-marker';
            if (p.excluded) {
                el.classList.add('excluded-outline');
            }

            const marker = new maplibregl.Marker({
                element: el,
                rotationAlignment: 'map'
            })
                .setLngLat([p.x, p.y])
                .addTo(map);

            otherPlayers[p.id] = {
                marker: marker,
                data: p
            };
        } else {
            entry.data = p;
            entry.marker.setLngLat([p.x, p.y]);
            entry.marker.setRotation(p.heading || 0);

            const el = entry.marker.getElement();
            if (p.excluded) {
                el.classList.add('excluded-outline');
            } else {
                el.classList.remove('excluded-outline');
            }
        }
    }

    function removeOtherPlayer(id) {
        const entry = otherPlayers[id];
        if (!entry) return;
        entry.marker.remove();
        delete otherPlayers[id];
    }

    // --- VEHICLES ---
    function upsertVehicle(v) {
        let entry = vehicles[v.id];
        if (!entry) {
            const el = document.createElement('div');
            el.className = 'vehicle-marker';

            const marker = new maplibregl.Marker({
                element: el,
                rotationAlignment: 'map'
            })
                .setLngLat([v.x, v.y])
                .addTo(map);

            vehicles[v.id] = {
                marker: marker,
                data: v
            };
        } else {
            entry.data = v;
            entry.marker.setLngLat([v.x, v.y]);
            entry.marker.setRotation(v.heading || 0);
        }
    }

    function removeVehicle(id) {
        const entry = vehicles[id];
        if (!entry) return;
        entry.marker.remove();
        delete vehicles[id];
    }

    // --- WORLD MARKERS (shops, garages, quests, etc.) ---
    function upsertWorldMarker(m) {
        let entry = worldMarkers[m.id];
        if (!entry) {
            const el = document.createElement('div');
            el.className = 'world-marker';

            const marker = new maplibregl.Marker({
                element: el
            })
                .setLngLat([m.x, m.y])
                .addTo(map);

            worldMarkers[m.id] = {
                marker: marker,
                data: m
            };
        } else {
            entry.data = m;
            entry.marker.setLngLat([m.x, m.y]);
        }
    }

    function removeWorldMarker(id) {
        const entry = worldMarkers[id];
        if (!entry) return;
        entry.marker.remove();
        delete worldMarkers[id];
    }

    // --- WEBSOCKET ---
    function initWebSocket() {
        socket = new WebSocket(WS_URL);

        socket.addEventListener('open', () => {
            isConnected = true;
            updateDebugConnection();
            // Send join/auth message
            sendToServer({
                type: 'join',
                playerId: PLAYER_ID
            });
        });

        socket.addEventListener('message', (event) => {
            let msg;
            try {
                msg = JSON.parse(event.data);
            } catch (e) {
                console.warn('Invalid JSON from server:', event.data);
                return;
            }
            handleServerMessage(msg);
        });

        socket.addEventListener('close', () => {
            isConnected = false;
            updateDebugConnection();
            // Optional: auto-reconnect
            setTimeout(initWebSocket, 3000);
        });

        socket.addEventListener('error', () => {
            isConnected = false;
            updateDebugConnection();
        });
    }

    function sendToServer(payload) {
        if (!socket || socket.readyState !== WebSocket.OPEN) return;
        socket.send(JSON.stringify(payload));
    }

    // --- SERVER MESSAGE HANDLING ---
    function handleServerMessage(msg) {
        switch (msg.type) {
            case 'worldState':
                // Bulk update: players, vehicles, markers
                if (Array.isArray(msg.players)) {
                    msg.players.forEach(upsertOtherPlayer);
                }
                if (Array.isArray(msg.vehicles)) {
                    msg.vehicles.forEach(upsertVehicle);
                }
                if (Array.isArray(msg.markers)) {
                    msg.markers.forEach(upsertWorldMarker);
                }
                break;

            case 'playerUpdate':
                if (msg.player && msg.player.id === PLAYER_ID) {
                    // Authoritative player state (no prediction)
                    playerState = {
                        ...playerState,
                        ...msg.player
                    };
                    updatePlayerMarker();
                    updateDebugPlayer();
                    sendHudUpdate();
                } else if (msg.player) {
                    upsertOtherPlayer(msg.player);
                }
                break;

            case 'playerLeft':
                if (msg.id) {
                    removeOtherPlayer(msg.id);
                }
                break;

            case 'vehicleUpdate':
                if (msg.vehicle) {
                    upsertVehicle(msg.vehicle);
                }
                break;

            case 'vehicleRemoved':
                if (msg.id) {
                    removeVehicle(msg.id);
                }
                break;

            case 'markerUpdate':
                if (msg.marker) {
                    upsertWorldMarker(msg.marker);
                }
                break;

            case 'markerRemoved':
                if (msg.id) {
                    removeWorldMarker(msg.id);
                }
                break;

            case 'hudData':
                // Server can push HUD data directly if desired
                sendHudUpdate(msg.data || {});
                break;

            case 'respawn':
                // Server confirms respawn; update player state
                if (msg.player && msg.player.id === PLAYER_ID) {
                    playerState = {
                        ...playerState,
                        ...msg.player
                    };
                    updatePlayerMarker();
                    updateDebugPlayer();
                    sendHudUpdate();
                }
                break;

            default:
                console.warn('Unhandled server message type:', msg.type);
        }
    }

    // --- INPUT HANDLING (NO PREDICTION) ---
    const keys = {
        forward: false,
        backward: false,
        left: false,
        right: false,
        handbrake: false
    };

    function setupInput() {
        window.addEventListener('keydown', (e) => {
            switch (e.code) {
                case 'KeyW':
                case 'ArrowUp':
                    keys.forward = true;
                    break;
                case 'KeyS':
                case 'ArrowDown':
                    keys.backward = true;
                    break;
                case 'KeyA':
                case 'ArrowLeft':
                    keys.left = true;
                    break;
                case 'KeyD':
                case 'ArrowRight':
                    keys.right = true;
                    break;
                case 'Space':
                    keys.handbrake = true;
                    break;
                default:
                    return;
            }
            sendMovementInput();
        });

        window.addEventListener('keyup', (e) => {
            switch (e.code) {
                case 'KeyW':
                case 'ArrowUp':
                    keys.forward = false;
                    break;
                case 'KeyS':
                case 'ArrowDown':
                    keys.backward = false;
                    break;
                case 'KeyA':
                case 'ArrowLeft':
                    keys.left = false;
                    break;
                case 'KeyD':
                case 'ArrowRight':
                    keys.right = false;
                    break;
                case 'Space':
                    keys.handbrake = false;
                    break;
                default:
                    return;
            }
            sendMovementInput();
        });
    }

    function sendMovementInput() {
        // No prediction: just send input state to server
        sendToServer({
            type: 'input',
            playerId: PLAYER_ID,
            input: {
                forward: keys.forward,
                backward: keys.backward,
                left: keys.left,
                right: keys.right,
                handbrake: keys.handbrake
            }
        });
    }

    // --- WORLD MAP ZOOM BUTTONS ---
    function setupZoomButtons() {
        const zoomInBtn  = document.getElementById('zoom-in');
        const zoomOutBtn = document.getElementById('zoom-out');

        zoomInBtn.addEventListener('click', () => {
            if (!map) return;
            map.setZoom(map.getZoom() + 0.5);
            notifyHudZoom();
        });

        zoomOutBtn.addEventListener('click', () => {
            if (!map) return;
            map.setZoom(map.getZoom() - 0.5);
            notifyHudZoom();
        });
    }

    function notifyHudZoom() {
        // Inform uix.php of current zoom if needed
        postToHud({
            type: 'worldZoomChanged',
            zoom: map.getZoom()
        });
    }

    // --- MESSAGING TO/FROM UIX (HUD) ---
    function postToHud(payload) {
        // engine.php is expected to be inside an iframe in uix.php
        if (window.parent && window.parent !== window) {
            window.parent.postMessage({
                source: 'engine',
                payload: payload
            }, '*');
        }
    }

    function sendHudUpdate(extra = {}) {
        const hudData = {
            type: 'hudUpdate',
            playerId: PLAYER_ID,
            position: {
                x: playerState.x,
                y: playerState.y
            },
            heading: playerState.heading,
            speedKmh: playerState.speedKmh,
            hp: playerState.hp,
            shield: playerState.shield,
            vehicleId: playerState.vehicleId,
            excluded: playerState.excluded,
            ...extra
        };
        postToHud(hudData);
    }

    // Listen for messages from uix.php
    window.addEventListener('message', (event) => {
        const data = event.data;
        if (!data || data.source !== 'uix') return;

        const payload = data.payload || {};
        switch (payload.type) {
            case 'spawnStarterVehicle':
                // payload.vehicleType: 'moped' or 'sedan'
                sendToServer({
                    type: 'spawnStarterVehicle',
                    playerId: PLAYER_ID,
                    vehicleType: payload.vehicleType
                });
                break;

            case 'requestRespawn':
                // Random 500m respawn handled server-side
                sendToServer({
                    type: 'requestRespawn',
                    playerId: PLAYER_ID
                });
                break;

            case 'setWorldZoom':
                if (map && typeof payload.zoom === 'number') {
                    map.setZoom(payload.zoom);
                    notifyHudZoom();
                }
                break;

            case 'setWorldCenter':
                if (map && payload.center && typeof payload.center.lng === 'number' && typeof payload.center.lat === 'number') {
                    map.setCenter([payload.center.lng, payload.center.lat]);
                }
                break;

            default:
                console.warn('Unhandled message from uix:', payload.type);
        }
    });

    // --- DEBUG UI ---
    function updateDebugConnection() {
        document.getElementById('dbg-conn').textContent = isConnected ? 'true' : 'false';
    }

    function updateDebugPlayer() {
        document.getElementById('dbg-pos').textContent =
            playerState.y.toFixed(5) + ', ' + playerState.x.toFixed(5);
        document.getElementById('dbg-speed').textContent =
            Math.round(playerState.speedKmh) + ' km/h';
        document.getElementById('dbg-vehicle').textContent =
            playerState.vehicleId ? playerState.vehicleId : 'none';
        document.getElementById('dbg-state').textContent =
            playerState.excluded ? 'excluded' : 'active';
    }

    // --- INIT ---
    window.addEventListener('load', () => {
        initMap();
        initWebSocket();
        setupInput();
        setupZoomButtons();
    });
</script>
</body>
</html>