import express from "express";
import http from "http";
import { WebSocketServer } from "ws";
import mysql from "mysql2/promise";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import path from "path";
import fs from "fs";
import { fileURLToPath } from "url";

const JWT_SECRET = "SUPER_SECRET_KEY";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// -------------------------------------------------------------
// TILE CONFIG LADEN
// -------------------------------------------------------------
const tileConfig = JSON.parse(
    fs.readFileSync(path.join(__dirname, "tiles.json"), "utf8")
);

// -------------------------------------------------------------
// OBJECT CONFIG LADEN
// -------------------------------------------------------------
const objectConfig = JSON.parse(
    fs.readFileSync(path.join(__dirname, "objectConfig.json"), "utf8")
);


const carConfig = JSON.parse(
    fs.readFileSync(path.join(__dirname, "carConfig.json"), "utf8")
);

const cars = new Map(); // carId -> { id, ownerId, model, world, x, y, angle, speed, driverId, throttle, steer }


// -------------------------------------------------------------
// MAPS LADEN
// -------------------------------------------------------------
const maps = {};

function loadMaps() {
    const dir = path.join(__dirname, "maps");
    const files = fs.readdirSync(dir).filter(f => f.endsWith(".json"));

    for (const file of files) {
        const data = JSON.parse(fs.readFileSync(path.join(dir, file), "utf8"));
        maps[data.name] = data;
    }

    console.log("Maps geladen:", Object.keys(maps));
}

loadMaps();

// -------------------------------------------------------------
// MYSQL VERBINDUNG
// -------------------------------------------------------------
export const db = await mysql.createPool({
    host: "156.67.28.205",
    user: "game",
    password: "tito13101",
    database: "gamegta",
    port: "3406",
    connectionLimit: 10
});
// -------------------------------------------------------------
// EXPRESS SERVER
// -------------------------------------------------------------
const app = express();
app.use(express.json());
app.use(express.static(__dirname));
const server = http.createServer(app);
const wss = new WebSocketServer({ server });
const playersOnline = new Map();
// -------------------------------------------------------------
// REGISTER
// -------------------------------------------------------------
app.post("/api/register", async (req, res) => {
    const { username, password } = req.body;

    const hash = await bcrypt.hash(password, 10);

    try {
        await db.query(
            "INSERT INTO players (username, password_hash, world, x, y) VALUES (?, ?, 'stadt', 112, 144)",
            [username, hash]
        );
        res.json({ ok: true });
    } catch {
        res.json({ ok: false, error: "Username vergeben" });
    }
});
// -------------------------------------------------------------
// LOGIN
// -------------------------------------------------------------
app.post("/api/login", async (req, res) => {
    const { username, password } = req.body;

    const [rows] = await db.query(
        "SELECT * FROM players WHERE username = ?",
        [username]
    );

    if (rows.length === 0)
        return res.json({ ok: false, error: "User nicht gefunden" });

    const player = rows[0];

    if (!await bcrypt.compare(password, player.password_hash))
        return res.json({ ok: false, error: "Passwort falsch" });

    const token = jwt.sign(
        { id: player.id, username: player.username },
        JWT_SECRET
    );

    res.json({ ok: true, token });
});
// -------------------------------------------------------------
// MAP SPEICHERN (Editor)
// -------------------------------------------------------------
app.post("/api/save_map", (req, res) => {
    const { name, data } = req.body;

    if (!name || !data) {
        return res.json({ ok: false, error: "Name oder Daten fehlen" });
    }

    const filePath = path.join(__dirname, "maps", name + ".json");

    try {
        fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
        loadMaps();
        res.json({ ok: true });
    } catch {
        res.json({ ok: false, error: "Speichern fehlgeschlagen" });
    }
});

app.get("/api/get_maps", (req, res) => {
    res.json({ ok: true, maps });
});
// -------------------------------------------------------------
// COLLISION (Tiles + Objekte)
// -------------------------------------------------------------
async function loadCars() {
    const [rows] = await db.query("SELECT * FROM cars");
    for (const row of rows) {
        cars.set(row.id, {
            id: row.id,
            ownerId: row.owner_id,
            model: row.model,
            world: row.world,
            x: row.x,
            y: row.y,
            angle: row.angle,
            speed: 0,
            driverId: null,
            throttle: 0,
            steer: 0
        });
    }
    console.log("Autos geladen:", cars.size);
}
await loadCars();

function sendCarsToAll() {
    const list = [];
    for (const [id, c] of cars) {
        list.push({
            id: c.id, model: c.model, world: c.world,
            x: c.x, y: c.y, angle: c.angle,
            driverId: c.driverId
        });
    }
    const msg = JSON.stringify({ type: "cars", cars: list });
    for (const [, p] of playersOnline) p.ws.send(msg);
}


function canMove(player, nx, ny) {
    const map = maps[player.state.world];
    if (!map || !map.tiles) return true;

    const tileX = Math.floor(nx / 32);
    const tileY = Math.floor(ny / 32);

    // TILE COLLISION
    const tileId = map.tiles[tileY]?.[tileX];
    const tile = tileConfig[tileId];
    if (tile && tile.collision) return false;

    // OBJECT COLLISION
    if (map.objects) {
        for (const obj of map.objects) {
            const cfg = objectConfig[obj.type];
            if (!cfg || !cfg.collision) continue;

            const ox = obj.x;
            const oy = obj.y - (cfg.height - 32);
            const ow = cfg.width;
            const oh = cfg.height;

            const px = nx;
            const py = ny;
            const pw = 30;
            const ph = 30;

            const hit =
                px < ox + ow &&
                px + pw > ox &&
                py < oy + oh &&
                py + ph > oy;

            if (hit) return false;
        }
    }

    return true;
}

const shops = new Map(); // shopId -> { id, name, world, x, y, items: [{id, name, price, type, model, restore}] }

async function loadShops() {
    shops.clear();
    const [shopRows] = await db.query("SELECT * FROM shops");

    for (const s of shopRows) {
        shops.set(s.id, { id: s.id, name: s.name, world: s.world, x: s.x, y: s.y, items: [] });
    }

    const [itemRows] = await db.query(`
        SELECT si.shop_id, si.price, i.id AS item_id, i.name, i.type, i.model, i.restore
        FROM shop_items si
        JOIN items i ON i.id = si.item_id
    `);

    for (const row of itemRows) {
        const shop = shops.get(row.shop_id);
        if (!shop) continue;
        shop.items.push({
            id: row.item_id,
            name: row.name,
            price: row.price,
            type: row.type,
            model: row.model,
            restore: row.restore
        });
    }

    console.log("Shops geladen:", shops.size);
}
await loadShops();
// Hilfsfunktion: Spieler holen
function getPlayer(playerId) {
    return playersOnline.get(playerId);
}

// -------------------------------------------------------------
// STATE AN ALLE SENDEN
// -------------------------------------------------------------
function sendStateToAll() {
    const allPlayers = [];
    for (const [id, p] of playersOnline) {
        allPlayers.push({
            id: id,
            x: p.state.x,
            y: p.state.y,
            world: p.state.world,
            money: p.state.money,
            bank: p.state.bank,
            health: p.state.health,
            hunger: p.state.hunger,
            thirst: p.state.thirst,
            inventory: p.state.inventory
        });
    }
    const msg = JSON.stringify({
        type: "state",
        players: allPlayers
    });

    for (const [id, p] of playersOnline) {
        p.ws.send(msg);
    }
}
async function getItemData(itemId) {
    const [rows] = await db.query("SELECT * FROM items WHERE id=?", [itemId]);
    return rows[0] || null;
}
function round2(value) {
    return Math.round(value * 100) / 100;
}

async function useItem(p, itemId) {
    const invItem = p.state.inventory.find(i => i.id === itemId);
    if (!invItem) {
        return { msg: "Item nicht im Inventar gefunden." };
    }

    const [rows] = await db.query("SELECT * FROM items WHERE id=?", [itemId]);
    if (rows.length === 0) {
        return { msg: "Item existiert nicht in der Datenbank." };
    }

    const itemData = rows[0];

    // Werte normalisieren
    p.state.hunger = Number(p.state.hunger) || 0;
    p.state.thirst = Number(p.state.thirst) || 0;
    p.state.health = Number(p.state.health) || 100;

    // ADDIEREN statt voll auffüllen
    const restore = Number(itemData.restore) || 0;

    if (itemData.type === "food") {
        console.log(itemData.restore)
        console.log(p.state.hunger)
        p.state.hunger = round2(Math.min(100, p.state.hunger + restore));
        console.log(p.state.hunger)
    }

    if (itemData.type === "drink") {
        p.state.thirst = round2(Math.min(100, p.state.thirst + restore));
    }

    if (itemData.type === "heal") {
        p.state.health = round2(Math.min(100, p.state.health + restore));
    }


    // Inventar reduzieren
    invItem.amount--;
    if (invItem.amount <= 0) {
        p.state.inventory = p.state.inventory.filter(i => i.id !== itemId);
    }

    return {
        msg: `${itemData.name} benutzt.`,
        hunger: p.state.hunger,
        thirst: p.state.thirst,
        health: p.state.health,
        inventory: p.state.inventory
    };
}




/*
function handleInteraction(player, data) {
    const map = maps[player.state.world];
    if (!map) return;

    const px = player.state.x;
    const py = player.state.y;

    // 1. Türen prüfen
    if (map.doors) {
        const door = map.doors.find(d =>
            Math.abs(d.x - px) < 16 &&
            Math.abs(d.y - py) < 16
        );

        if (door) {
            if (!maps[door.targetMap]) return;

            player.state.world = door.targetMap;
            player.state.x = door.targetX * 32;
            player.state.y = door.targetY * 32;

            db.query(
                "UPDATE players SET world=?, x=?, y=? WHERE id=?",
                [player.state.world, player.state.x, player.state.y, player.id]
            );

            sendStateToAll();
            player.ws.send(JSON.stringify({
                type: "map_data",
                tiles: maps[player.state.world].tiles,
                doors: maps[player.state.world].doors,
                objects: maps[player.state.world].objects,
                shops: maps[player.state.world].shops,   // <-- WICHTIG
                
                spawn: maps[player.state.world].spawn
            }));

            return;
        }
    }

    // 2. NPCs prüfen
    if (map.npcs) {
        const npc = map.npcs.find(n =>
            Math.abs(n.x - px) < 32 &&
            Math.abs(n.y - py) < 32
        );

        if (npc) {
            player.ws.send(JSON.stringify({
                type: "npc_dialog",
                npcId: npc.id,
                text: npc.dialog
            }));
            return;
        }
    }
    // 3. Shops prüfen
    if (map.shops && Array.isArray(map.shops)) {

        const shop = map.shops.find(s =>
            Math.abs(s.x * 32 - player.state.x) < 32 &&
            Math.abs(s.y * 32 - player.state.y) < 32
        );

        if (shop) {
            player.ws.send(JSON.stringify({
                type: "shop_open",
                shopId: shop.id,
                items: shop.items
            }));
            return;
        }
    }








    // 4. Interaktive Objekte (z.B. Kisten)
    if (map.objects) {
        const obj = map.objects.find(o =>
            o.interactive &&
            Math.abs(o.x - px) < 32 &&
            Math.abs(o.y - py) < 32
        );

        if (obj) {
            player.ws.send(JSON.stringify({
                type: "object_interact",
                objectId: obj.id,
                action: obj.action
            }));
            return;
        }
    }
}*/

function handleInteraction(player, data) {
    const map = maps[player.state.world];
    if (!map) return;

    const px = player.state.x;
    const py = player.state.y;

    // 1. Türen prüfen (unverändert)
    if (map.doors) {
        const door = map.doors.find(d =>
            Math.abs(d.x - px) < 16 &&
            Math.abs(d.y - py) < 16
        );

        if (door) {
            if (!maps[door.targetMap]) return;

            player.state.world = door.targetMap;
            player.state.x = door.targetX * 32;
            player.state.y = door.targetY * 32;

            db.query(
                "UPDATE players SET world=?, x=?, y=? WHERE id=?",
                [player.state.world, player.state.x, player.state.y, player.id]
            );

            sendStateToAll();
            player.ws.send(JSON.stringify({
                type: "map_data",
                tiles: maps[player.state.world].tiles,
                doors: maps[player.state.world].doors,
                objects: maps[player.state.world].objects,
                shops: maps[player.state.world].shops,
                atms: maps[player.state.world].atms || [],   // <-- NEU
                spawn: maps[player.state.world].spawn
            }));

            return;
        }
    }

    // 2. NPCs prüfen (unverändert)
    if (map.npcs) {
        const npc = map.npcs.find(n =>
            Math.abs(n.x - px) < 32 &&
            Math.abs(n.y - py) < 32
        );

        if (npc) {
            player.ws.send(JSON.stringify({
                type: "npc_dialog",
                npcId: npc.id,
                text: npc.dialog
            }));
            return;
        }
    }

    // 3. Shops prüfen (unverändert)
    if (map.shops && Array.isArray(map.shops)) {
        const shop = map.shops.find(s =>
            Math.abs(s.x * 32 - player.state.x) < 32 &&
            Math.abs(s.y * 32 - player.state.y) < 32
        );

        if (shop) {
            player.ws.send(JSON.stringify({
                type: "shop_open",
                shopId: shop.id,
                items: shop.items
            }));
            return;
        }
    }

    // 3b. ATMs prüfen (GENAU wie Shop)
    if (map.atms && Array.isArray(map.atms)) {
        const atm = map.atms.find(a =>
            Math.abs(a.x * 32 - player.state.x) < 32 &&
            Math.abs(a.y * 32 - player.state.y) < 32
        );

        if (atm) {
            // sende atm_open an den Client (Server entscheidet, ob PIN nötig)
            player.ws.send(JSON.stringify({
                type: "atm_open",
                atmId: atm.id,
                money: player.state.money,
                bank: player.state.bank
            }));
            return;
        }
    }

    // 4. Interaktive Objekte (z.B. Kisten) (unverändert)
    if (map.objects) {
        const obj = map.objects.find(o =>
            o.interactive &&
            Math.abs(o.x - px) < 32 &&
            Math.abs(o.y - py) < 32
        );

        if (obj) {
            player.ws.send(JSON.stringify({
                type: "object_interact",
                objectId: obj.id,
                action: obj.action
            }));
            return;
        }
    }
}

 
// -------------------------------------------------------------
// WEBSOCKET MULTIPLAYER
// -------------------------------------------------------------
wss.on("connection", ws => {
    let playerId = null;

    ws.on("message", async msg => {
        let data;
        try {
            data = JSON.parse(msg);
        } catch {
            return;
        }
        // AUTH
        if (data.type === "auth") {
            try {
                const payload = jwt.verify(data.token, JWT_SECRET);
                playerId = payload.id;
                ws.playerId = playerId;


                const [rows] = await db.query(
                    "SELECT world, x, y, health, hunger, thirst, money,inventory FROM players WHERE id = ?",
                    [playerId]
                );

                const row = rows[0];

                playersOnline.set(playerId, {
                    ws,
                    state: {
                        world: row.world,
                        x: row.x,
                        y: row.y,
                        health: row.health,
                        hunger: row.hunger,
                        thirst: row.thirst,
                        inventory: JSON.parse(row.inventory || "[]"),
                        money: row.money ?? 0,
                        bank: row.bank ?? 0

                    }
                });

                ws.send(JSON.stringify({
                    type: "auth_ok",
                    id: playerId,
                    maps
                }));
                // Map-Daten direkt nach Login senden
                const currentMap = maps[row.world];

                ws.send(JSON.stringify({
                    type: "map_data",
                    tiles: currentMap.tiles,
                    doors: currentMap.doors,
                    objects: currentMap.objects,
                    shops: currentMap.shops,
                    atms: currentMap.atms,   // <-- NEU
                    spawn: currentMap.spawn
                }));

                sendStateToAll();
            } catch {
                ws.close();
            }
        }
        if (data.type === "bank_pin_check") {

            // Spieler korrekt holen
            const player = playersOnline.get(ws.playerId);
            console.log(playerId)
            if (!player) {
                console.log("Kein Spieler gefunden für ws.playerId:", playerId);
                return;
            }

            console.log("Player ID:", playerId);

            const [rows] = await db.query("SELECT pin FROM players WHERE id=?", [playerId]);

            console.log("DB Row:", rows[0]);
            console.log("Client PIN:", data.pin);

            if (rows.length && Number(rows[0].pin) === Number(data.pin)) {
                player.ws.send(JSON.stringify({ type: "bank_pin_ok" }));
            } else {
                player.ws.send(JSON.stringify({ type: "bank_pin_fail" }));
            }
        }
       if (data.type === "bank_open") {
            const player = playersOnline.get(ws.playerId);
            if (!player) return;

            player.ws.send(JSON.stringify({
                type: "bank_open",
                money: player.state.money,
                bank: player.state.bank
            }));
        }
        if (data.type === "bank_deposit") {
            const player = playersOnline.get(ws.playerId);   // <-- NEU hinzugefügt
            if (!player) return;

            const amount = Math.max(0, Number(data.amount));
            if (player.state.money >= amount) {
                player.state.money -= amount;
                player.state.bank += amount;

                await db.query("UPDATE players SET money=?, bank=? WHERE id=?",
                    [player.state.money, player.state.bank, playerId]);

                player.ws.send(JSON.stringify({
                    type: "bank_update",
                    money: player.state.money,
                    bank: player.state.bank
                }));
            }
        }
        if (data.type === "bank_withdraw") {
            const player = playersOnline.get(ws.playerId);   // <-- NEU hinzugefügt
            if (!player) return;

            const amount = Math.max(0, Number(data.amount));
            if (player.state.bank >= amount) {
                player.state.bank -= amount;
                player.state.money += amount;

                await db.query("UPDATE players SET money=?, bank=? WHERE id=?",
                    [player.state.money, player.state.bank, playerId]);

                player.ws.send(JSON.stringify({
                    type: "bank_update",
                    money: player.state.money,
                    bank: player.state.bank
                }));
            }
        }
        if (data.type === "bank_transfer") {
            const player = playersOnline.get(ws.playerId);   // <-- NEU hinzugefügt
            if (!player) return;

            const targetId = Number(data.targetId);
            const amount = Math.max(0, Number(data.amount));

            const target = playersOnline.get(targetId);
            if (target && player.state.bank >= amount) {
                player.state.bank -= amount;
                target.state.bank += amount;

                await db.query("UPDATE players SET bank=? WHERE id=?", [player.state.bank, playerId]);
                await db.query("UPDATE players SET bank=? WHERE id=?", [target.state.bank, targetId]);

                player.ws.send(JSON.stringify({
                    type: "bank_update",
                    money: player.state.money,
                    bank: player.state.bank
                }));

                target.ws.send(JSON.stringify({
                    type: "bank_update",
                    money: target.state.money,
                    bank: target.state.bank
                }));
            }
        }
        if (data.type === "car_enter") {
            const p = playersOnline.get(playerId);
            if (!p) return;

            let nearestCar = null;
            for (const [, c] of cars) {
                if (c.world !== p.state.world || c.driverId) continue;
                if (Math.abs(c.x - p.state.x) < 40 && Math.abs(c.y - p.state.y) < 40) {
                    nearestCar = c;
                    break;
                }
            }
            if (!nearestCar) return;

            nearestCar.driverId = playerId;
            p.drivingCarId = nearestCar.id;
            sendCarsToAll();
        }

        if (data.type === "car_exit") {
            const p = playersOnline.get(playerId);
            if (!p || !p.drivingCarId) return;

            const c = cars.get(p.drivingCarId);
            if (c) {
                c.driverId = null;
                c.throttle = 0;
                c.steer = 0;
                p.state.x = c.x;
                p.state.y = c.y + 30;
                db.query("UPDATE cars SET x=?, y=?, angle=?, world=? WHERE id=?",
                    [c.x, c.y, c.angle, c.world, c.id]);
            }
            p.drivingCarId = null;
            sendCarsToAll();
            sendStateToAll();
        }

        if (data.type === "car_control") {
            const p = playersOnline.get(playerId);
            if (!p || !p.drivingCarId) return;

            const c = cars.get(p.drivingCarId);
            if (!c) return;

            c.throttle = Math.max(-1, Math.min(1, Number(data.throttle) || 0));
            c.steer = Math.max(-1, Math.min(1, Number(data.steer) || 0));
        }



        if (msg.type === "shop_error") {
            alert(msg.msg);
        }
        if (data.type === "shop_buy") {
            const p = playersOnline.get(playerId);
            if (!p) return;

            const map = maps[p.state.world];
            if (!map || !map.shops) return;

            const shop = map.shops.find(s =>
                Math.abs(s.x * 32 - p.state.x) < 32 &&
                Math.abs(s.y * 32 - p.state.y) < 32
            );
            if (!shop) return;

            const item = shop.items.find(i => i.id === data.itemId);
            if (!item) return;

            if (p.state.money < item.price) {
                p.ws.send(JSON.stringify({ type: "shop_error", msg: "Zu wenig Geld!" }));
                return;
            }

            p.state.money -= item.price;

            if (item.type === "car") {
                const [result] = await db.query(
                    "INSERT INTO cars (owner_id, model, world, x, y, angle) VALUES (?, ?, ?, ?, ?, 0)",
                    [playerId, item.model || "sedan", p.state.world, p.state.x + 40, p.state.y]
                );
                cars.set(result.insertId, {
                    id: result.insertId,
                    ownerId: playerId,
                    model: item.model || "sedan",
                    world: p.state.world,
                    x: p.state.x + 40,
                    y: p.state.y,
                    angle: 0,
                    speed: 0,
                    driverId: null,
                    throttle: 0,
                    steer: 0
                });
                await db.query("UPDATE players SET money=? WHERE id=?", [p.state.money, playerId]);
                sendCarsToAll();
                p.ws.send(JSON.stringify({ type: "shop_info", msg: "Auto gekauft! Steht neben dir." }));
            } else {
                const invItem = p.state.inventory.find(i => i.id === item.id);
                if (invItem) invItem.amount++;
                else p.state.inventory.push({ id: item.id, amount: 1 });

                await db.query(
                    "UPDATE players SET money=?, inventory=? WHERE id=?",
                    [p.state.money, JSON.stringify(p.state.inventory), playerId]
                );
            }

            sendStateToAll();
        }
        if (data.type === "state") {
            const player = playersOnline.get(ws.playerId);
            if (!player) return;

            const me = data.players.find(p => p.id === ws.playerId);
            if (!me) return;

            // SERVERSEITIG IMMER player.state benutzen!
            player.state.x = me.x;
            player.state.y = me.y;
            player.state.world = me.world;

            player.state.money = me.money;
            player.state.bank = me.bank;

            player.state.health = me.health;
            player.state.hunger = me.hunger;
            player.state.thirst = me.thirst;

            player.state.inventory = me.inventory || [];

            // Andere Spieler aktualisieren
            player.otherPlayers = data.players.filter(p => p.id !== ws.playerId);

            // UI aktualisieren (Client)
            updateStatusWindow();
            renderInventoryWindow();
        }

        if (!playerId) return;
            const p = playersOnline.get(playerId);
        if (!p) return;
        // TÜR BENUTZEN
        if (data.type === "use_door") {
            const currentMap = maps[p.state.world];
            if (!currentMap || !currentMap.doors) return;

            const door = currentMap.doors.find(d =>
                Math.abs(d.x - data.x) < 10 &&
                Math.abs(d.y - data.y) < 10
            );

            if (!door) return;
            if (!maps[door.targetMap]) return;

            p.state.world = door.targetMap;
            p.state.x = door.targetX * 32;
            p.state.y = door.targetY * 32;

            await db.query(
                "UPDATE players SET world = ?, x = ?, y = ? WHERE id = ?",
                [p.state.world, p.state.x, p.state.y, playerId]
            );

            sendStateToAll();
        }
        if (data.type === "interact") {
            const p = playersOnline.get(playerId);
            if (!p) return;

            handleInteraction(p, data);
        }
        if (data.type === "use_item") {
            const p = playersOnline.get(playerId);
            if (!p) return;

            const result = await useItem(p, data.itemId);

            const hunger = Math.max(0, Number(p.state.hunger) || 0);
            const thirst = Math.max(0, Number(p.state.thirst) || 0);
            const health = Math.max(0, Number(p.state.health) || 100);

            await db.query(
                "UPDATE players SET inventory=?, hunger=?, thirst=?, health=? WHERE id=?",
                [
                    JSON.stringify(p.state.inventory),
                    round2(p.state.hunger),
                    round2(p.state.thirst),
                    round2(p.state.health),
                    playerId
                ]
            );



            p.ws.send(JSON.stringify({
                type: "item_used",
                msg: result.msg,
                hunger,
                thirst,
                health,
                inventory: p.state.inventory
            }));

            sendStateToAll();
        }



        if (msg.type === "item_used") {
           // player.hunger = msg.hunger;
            //player.thirst = msg.thirst;
            //player.inventory = msg.inventory;

            renderInventoryWindow();
            updateStatusUI();
        }

        // MOVEMENT MIT COLLISION
        if (data.type === "move") {
            const nx = data.x;
            const ny = data.y;

            const oldX = p.state.x;
            const oldY = p.state.y;

            if (canMove(p, nx, ny)) {
                p.state.x = nx;
                p.state.y = ny;

                // Nur Position speichern – KEINE Werte vom Client übernehmen!
                await db.query(
                    "UPDATE players SET x=?, y=? WHERE id=?",
                    [p.state.x, p.state.y, playerId]
                );

                if (oldX !== p.state.x || oldY !== p.state.y) {
                    sendStateToAll();
                }
            }
        }
        // MAP WECHSEL
        if (data.type === "change_map") {
            const mapName = data.map;
            if (!maps[mapName]) return;

            p.state.world = mapName;
            p.state.x = maps[mapName].spawn.x;
            p.state.y = maps[mapName].spawn.y;

            await db.query(
                "UPDATE players SET world = ?, x = ?, y = ? WHERE id = ?",
                [mapName, p.state.x, p.state.y, playerId]
            );

            sendStateToAll();
            player.ws.send(JSON.stringify({
                type: "map_data",
                tiles: maps[p.state.world].tiles,
                doors: maps[p.state.world].doors,
                objects: maps[p.state.world].objects,
                shops: maps[p.state.world].shops,   // <-- WICHTIG
                atms: maps[player.state.world].atms,   // <-- ATM wird jetzt gesendet
                spawn: maps[p.state.world].spawn
            }));

        }



    });

    ws.on("close", () => {
        if (playerId) {
            playersOnline.delete(playerId);
            sendStateToAll();
        }
    });
});
function updatePlayerNeeds(p) {
    // Werte IMMER in Zahlen umwandeln
    p.state.hunger = Number(p.state.hunger) || 0;
    p.state.thirst = Number(p.state.thirst) || 0;
    p.state.health = Number(p.state.health) || 100;

    // Hunger / Durst sinken langsam
    p.state.hunger = round2(p.state.hunger - 0.002);
    p.state.thirst = round2(p.state.thirst - 0.004);

    if (p.state.hunger < 0) p.state.hunger = 0;
    if (p.state.thirst < 0) p.state.thirst = 0;

    if (p.state.hunger === 0 || p.state.thirst === 0) {
        p.state.health = round2(p.state.health - 0.01);
        if (p.state.health < 0) p.state.health = 0;
    }


    // Werte erneut absichern (gegen NaN)
    p.state.hunger = Math.max(0, Number(p.state.hunger) || 0);
    p.state.thirst = Math.max(0, Number(p.state.thirst) || 0);
    p.state.health = Math.max(0, Number(p.state.health) || 100);
}


setInterval(async () => {
    for (const [playerId, p] of playersOnline) {

        updatePlayerNeeds(p);

        await db.query(
            "UPDATE players SET health=?, hunger=?, thirst=?, inventory=? WHERE id=?",
            [
                p.state.health,
                p.state.hunger,
                p.state.thirst,
                JSON.stringify(p.state.inventory),
                playerId
            ]
        );

        sendStateToAll();
    }
}, 1000); // alle 1 Sekunde

setInterval(() => {
    let changed = false;
    for (const [, c] of cars) {
        if (!c.driverId) continue;
        const cfg = carConfig[c.model] || carConfig.sedan;

        if (c.throttle > 0) c.speed += cfg.accel;
        else if (c.throttle < 0) c.speed -= cfg.brake;
        else c.speed *= (1 - cfg.friction);

        c.speed = Math.max(-cfg.maxSpeed / 2, Math.min(cfg.maxSpeed, c.speed));

        if (Math.abs(c.speed) > 0.05) {
            c.angle += c.steer * cfg.turnSpeed * (c.speed > 0 ? 1 : -1);
        }

        const nx = c.x + Math.cos(c.angle) * c.speed;
        const ny = c.y + Math.sin(c.angle) * c.speed;

        if (canMove({ state: { world: c.world } }, nx, ny)) {
            c.x = nx;
            c.y = ny;
        } else {
            c.speed = 0;
        }

        const driver = playersOnline.get(c.driverId);
        if (driver) {
            driver.state.x = c.x;
            driver.state.y = c.y;
        }
        changed = true;
    }
    if (changed) { sendCarsToAll(); sendStateToAll(); }
}, 50); // 20x pro Sekunde

// -------------------------------------------------------------
// SERVER STARTEN
// -------------------------------------------------------------
server.listen(5555, () => {
    console.log("Server läuft auf Port 5555");
});
