const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = false;

// -------------------------------------------------------------
// ZUGRIFFSSCHUTZ: nur eingeloggte Admins dürfen den Map-Editor nutzen
// -------------------------------------------------------------
const token = localStorage.getItem("token");
// Voll-Admin ODER die Berechtigung "manage_maps" reicht - der Server prüft
// das final ab, authFetch() fängt fehlende Rechte sauber ab
let isAdmin = localStorage.getItem("isAdmin") === "true";

if (!token) {
    alert("Bitte zuerst einloggen.");
    location.href = "/index.html";
}

async function authFetch(url, options = {}) {
    options.headers = { ...(options.headers || {}), "Authorization": "Bearer " + token };
    const res = await fetch(url, options);
    if (res.status === 401 || res.status === 403) {
        alert("Sitzung abgelaufen oder kein Admin-Zugriff. Bitte erneut einloggen.");
        location.href = "/index.html";
        throw new Error("Nicht autorisiert");
    }
    return res;
}

const mapNameInput = document.getElementById("mapName");
const mapSelect = document.getElementById("mapSelect");
const newMapBtn = document.getElementById("newMapBtn");
const saveMapBtn = document.getElementById("saveMapBtn");
const modeSelect = document.getElementById("modeSelect");

// -------------------------------------------------------------
// Icon-Werkzeugleiste (steuert weiterhin das versteckte modeSelect,
// damit der restliche Code unverändert "modeSelect.value" lesen kann)
// -------------------------------------------------------------
const modeButtons = document.querySelectorAll(".mode-btn");

function setToolbarActive(modeValue) {
    modeButtons.forEach(btn => {
        btn.classList.toggle("active", btn.dataset.mode === modeValue);
    });
}

modeButtons.forEach(btn => {
    btn.addEventListener("click", () => {
        modeSelect.value = btn.dataset.mode;
        setToolbarActive(btn.dataset.mode);
    });
});

setToolbarActive(modeSelect.value);

// -------------------------------------------------------------
// Ebenen-Sichtbarkeit
// -------------------------------------------------------------
const layerVisibility = {
    object: true, shop: true, atm: true, garage: true, jobcenter: true,
    gasstation: true, repairshop: true, house: true, jobpoint: true,
    taxistand: true, hospital: true, prison: true, zone: true, impound: true,
    firestation: true, drug_harvest: true, drug_process: true, drug_dealer: true,
    clothingshop: true, insuranceoffice: true, plateoffice: true, trailershop: true
};

document.querySelectorAll(".layer-toggle").forEach(cb => {
    cb.addEventListener("change", () => {
        layerVisibility[cb.dataset.layer] = cb.checked;
        render();
    });
});

const doorTargetMap = document.getElementById("doorTargetMap");
const doorTargetX = document.getElementById("doorTargetX");
const doorTargetY = document.getElementById("doorTargetY");

const mapWidthInput = document.getElementById("mapWidth");
const mapHeightInput = document.getElementById("mapHeight");
const resizeMapBtn = document.getElementById("resizeMapBtn");

const tilePalette = document.getElementById("tilePalette");
const objectPalette = document.getElementById("objectPalette");

// -------------------------------------------------------------
// KAMERA / SCROLLEN (NEU) - für große/"unendliche" Maps
// -------------------------------------------------------------
const editorCam = { x: 0, y: 0 };
const panKeys = {};
const PAN_SPEED = 14; // Pixel pro Frame

document.addEventListener("keydown", e => {
    if (["arrowup", "arrowdown", "arrowleft", "arrowright"].includes(e.key.toLowerCase())) {
        panKeys[e.key.toLowerCase()] = true;
        e.preventDefault();
    }
});
document.addEventListener("keyup", e => {
    panKeys[e.key.toLowerCase()] = false;
});

// Mittlere Maustaste (Mausrad gedrückt halten) zum Ziehen/Scrollen
let isDragging = false;
let dragStart = { x: 0, y: 0 };
let camStart = { x: 0, y: 0 };

canvas.addEventListener("mousedown", e => {
    if (e.button === 1) { // mittlere Maustaste
        isDragging = true;
        dragStart = { x: e.clientX, y: e.clientY };
        camStart = { x: editorCam.x, y: editorCam.y };
        e.preventDefault();
    }
});
document.addEventListener("mousemove", e => {
    if (!isDragging) return;
    editorCam.x = clampCamX(camStart.x - (e.clientX - dragStart.x));
    editorCam.y = clampCamY(camStart.y - (e.clientY - dragStart.y));
    render();
});
document.addEventListener("mouseup", e => {
    if (e.button === 1) isDragging = false;
});
canvas.addEventListener("auxclick", e => {
    if (e.button === 1) e.preventDefault(); // verhindert Auto-Scroll-Icon bei Mittelklick
});

function clampCamX(x) {
    const maxX = Math.max(0, cols * tileSize - canvas.width);
    return Math.min(Math.max(0, x), maxX);
}
function clampCamY(y) {
    const maxY = Math.max(0, rows * tileSize - canvas.height);
    return Math.min(Math.max(0, y), maxY);
}

function panLoop() {
    let moved = false;
    if (panKeys["arrowup"]) { editorCam.y -= PAN_SPEED; moved = true; }
    if (panKeys["arrowdown"]) { editorCam.y += PAN_SPEED; moved = true; }
    if (panKeys["arrowleft"]) { editorCam.x -= PAN_SPEED; moved = true; }
    if (panKeys["arrowright"]) { editorCam.x += PAN_SPEED; moved = true; }

    if (moved) {
        editorCam.x = clampCamX(editorCam.x);
        editorCam.y = clampCamY(editorCam.y);
        render();
        updateCamLabel();
    }
    requestAnimationFrame(panLoop);
}

function updateCamLabel() {
    const label = document.getElementById("camLabel");
    if (label) {
        label.textContent = `Kamera-Tile: (${Math.floor(editorCam.x / tileSize)}, ${Math.floor(editorCam.y / tileSize)})`;
    }
}

function goToTile(tx, ty) {
    editorCam.x = clampCamX(tx * tileSize - canvas.width / 2);
    editorCam.y = clampCamY(ty * tileSize - canvas.height / 2);
    render();
    updateCamLabel();
}

let objectConfig = {};
let selectedObjectType = null;
let objects = [];

let tileConfig = {};
let selectedTile = 1;
let brushSize = 1;
const brushSizeSelect = document.getElementById("brushSize");
brushSizeSelect.addEventListener("change", () => {
    brushSize = parseInt(brushSizeSelect.value);
});

function paintTileBrush(centerX, centerY, tileId) {
    const half = Math.floor(brushSize / 2);
    for (let dy = 0; dy < brushSize; dy++) {
        for (let dx = 0; dx < brushSize; dx++) {
            const x = centerX - half + dx;
            const y = centerY - half + dy;
            if (x < 0 || y < 0 || y >= tiles.length || x >= tiles[0].length) continue;
            tiles[y][x] = tileId;
        }
    }
}

let tileSize = 32;
let tiles = [];
let tileRot = []; // Drehwinkel je Kachel: 0, 90, 180, 270
let doors = [];
let spawn = { x: 32, y: 32 };

let cols = 20;
let rows = 20;

let shops = [];   // kommt jetzt aus der DB (admin API), nicht mehr aus der Map-Datei
let atms = [];
let garages = []; // kommt ebenfalls aus der DB
let jobcenters = []; // kommt ebenfalls aus der DB
let gasStations = []; // kommt ebenfalls aus der DB
let repairShops = []; // kommt ebenfalls aus der DB
let houses = []; // kommt ebenfalls aus der DB
let jobPoints = []; // kommt ebenfalls aus der DB
let taxiStands = []; // kommt ebenfalls aus der DB
let hospitals = []; // kommt ebenfalls aus der DB
let prisons = []; // kommt ebenfalls aus der DB
let impoundLots = []; // kommt ebenfalls aus der DB
let fireStations = []; // kommt ebenfalls aus der DB
let harvestSpots = []; // kommt ebenfalls aus der DB
let processSpots = []; // kommt ebenfalls aus der DB
let dealerSpots = []; // kommt ebenfalls aus der DB (Pool!)
let clothingShops = []; // kommt ebenfalls aus der DB
let insuranceOffices = []; // kommt ebenfalls aus der DB
let plateOffices = []; // kommt ebenfalls aus der DB
let trailerShops = []; // kommt ebenfalls aus der DB
let allDrugTypesForEditor = [];

fetch("/api/admin/drug_types", { headers: { "Authorization": "Bearer " + localStorage.getItem("token") } })
    .then(res => res.json())
    .then(data => { allDrugTypesForEditor = data.drugTypes || []; });

function pickDrugId() {
    if (allDrugTypesForEditor.length === 0) {
        alert("Keine Drogensorten angelegt. Erst in admin_drugs.html eine Sorte anlegen.");
        return null;
    }
    const list = allDrugTypesForEditor.map(d => `${d.id} (${d.name})`).join("\n");
    const id = prompt(`Welche Drogensorte?\n${list}`);
    if (!id) return null;
    const match = allDrugTypesForEditor.find(d => d.id === id.trim());
    if (!match) {
        alert("Unbekannte Sorten-ID.");
        return null;
    }
    return match.id;
}
let territoryZones = []; // kommt ebenfalls aus der DB
let allJobsForEditor = []; // für Job-Auswahl bei Job-Garagen/Job-Punkten

// -------------------------------------------------------------
// Tiles laden
// -------------------------------------------------------------
const tileImageCache = {};

fetch("/api/tile_config")
    .then(res => res.json())
    .then(data => {
        tileConfig = data;
        Object.entries(tileConfig).forEach(([id, tile]) => {
            if (tile.image) {
                const img = new Image();
                img.src = tile.image;
                tileImageCache[id] = img;
            }
        });
        buildTilePalette();
        loadMapList();
        newMap();
    });

fetch("/api/object_config")
    .then(res => res.json())
    .then(data => {
        objectConfig = data;
        buildObjectPalette();
    });

// -------------------------------------------------------------
// Tile-Palette bauen
// -------------------------------------------------------------
function buildTilePalette() {
    tilePalette.innerHTML = "";

    Object.entries(tileConfig).forEach(([id, tile]) => {
        const swatch = document.createElement("div");
        swatch.className = "tile-swatch" + (selectedTile === parseInt(id) ? " selected" : "");
        swatch.dataset.id = id;
        swatch.title = `#${id}: ${tile.name}${tile.collision ? " (blockiert)" : ""}`;

        const bgStyle = tile.image
            ? `background-image:url('${tile.image}'); background-size:cover; image-rendering:pixelated;`
            : `background:${tile.color};`;

        swatch.innerHTML = `
            <div class="color-box" style="${bgStyle}">
                ${tile.collision ? '<span class="collision-icon">🚫</span>' : ""}
            </div>
            <div class="tile-label">${tile.name}</div>
        `;

        swatch.onclick = () => {
            selectedTile = parseInt(id);
            tilePalette.querySelectorAll(".tile-swatch").forEach(el => el.classList.remove("selected"));
            swatch.classList.add("selected");
        };

        tilePalette.appendChild(swatch);
    });
}

// -------------------------------------------------------------
// Object-Palette bauen
// -------------------------------------------------------------
function buildObjectPalette() {
    objectPalette.innerHTML = "";

    Object.entries(objectConfig).forEach(([type, obj]) => {
        const div = document.createElement("div");
        div.style.width = "32px";
        div.style.height = "32px";
        div.style.background = obj.color;
        div.style.border = selectedObjectType === type ? "3px solid #f5d90a" : "2px solid #000";
        div.style.boxShadow = selectedObjectType === type ? "0 0 6px #f5d90a" : "none";
        div.style.display = "inline-block";
        div.style.margin = "4px";
        div.style.cursor = "pointer";
        div.title = `${type}: ${obj.name}`;
        div.dataset.objType = type;

        div.onclick = () => {
            selectedObjectType = type;
            objectPalette.querySelectorAll("div").forEach(el => {
                el.style.border = "2px solid #000";
                el.style.boxShadow = "none";
            });
            div.style.border = "3px solid #f5d90a";
            div.style.boxShadow = "0 0 6px #f5d90a";
        };

        objectPalette.appendChild(div);
    });

    // Falls noch nichts ausgewählt ist, direkt den ersten Typ vorauswählen
    if (!selectedObjectType) {
        const first = objectPalette.querySelector("div");
        if (first) first.click();
    }
}

// -------------------------------------------------------------
// Neue Map
// -------------------------------------------------------------
function newMap() {
    tiles = [];
    tileRot = [];
    for (let y = 0; y < rows; y++) {
        tiles[y] = [];
        tileRot[y] = [];
        for (let x = 0; x < cols; x++) {
            tiles[y][x] = 1;
            tileRot[y][x] = 0;
        }
    }

    doors = [];
    objects = [];
    atms = [];
    shops = []; // wird erst befüllt, sobald die Map einen gespeicherten Namen hat
    spawn = { x: 32, y: 32 };

    editorCam.x = 0;
    editorCam.y = 0;
    updateCamLabel();

    render();
}

newMapBtn.onclick = () => {
    if (!confirm("Neue, leere Map erstellen? Nicht gespeicherte Änderungen an der aktuellen Map gehen verloren.")) {
        return;
    }

    const name = prompt("Name für die neue Map (z.B. wald):");
    if (!name) return;

    mapNameInput.value = name.trim();
    mapSelect.value = "";
    newMap();

    alert(`Leere Map "${name.trim()}" ist bereit zum Bearbeiten. Nicht vergessen: oben auf "Speichern" klicken, damit sie wirklich angelegt wird!`);
};

// -------------------------------------------------------------
// Map-Liste laden
// -------------------------------------------------------------
function loadMapList() {
    fetch("/api/get_maps")
        .then(res => res.json())
        .then(data => {
            mapSelect.innerHTML = `<option value="">Map laden...</option>`;
            Object.keys(data.maps).forEach(name => {
                const opt = document.createElement("option");
                opt.value = name;
                opt.textContent = name;
                mapSelect.appendChild(opt);
            });
        });
}

// -------------------------------------------------------------
// Shops für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadShopsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        shops = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/shops");
    const data = await res.json();
    shops = (data.shops || []).filter(s => s.world === world);
    render();
}

// -------------------------------------------------------------
// Garagen für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadGaragesForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        garages = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/garages");
    const data = await res.json();
    garages = (data.garages || []).filter(g => g.world === world);
    render();
}

// -------------------------------------------------------------
// Jobcenter für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadJobcentersForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        jobcenters = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/jobcenters");
    const data = await res.json();
    jobcenters = (data.jobcenters || []).filter(j => j.world === world);
    render();
}

// -------------------------------------------------------------
// Tankstellen für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadGasStationsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        gasStations = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/gas_stations");
    const data = await res.json();
    gasStations = (data.gasStations || []).filter(g => g.world === world);
    render();
}

// -------------------------------------------------------------
// Werkstätten für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadRepairShopsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        repairShops = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/repair_shops");
    const data = await res.json();
    repairShops = (data.repairShops || []).filter(r => r.world === world);
    render();
}

// -------------------------------------------------------------
// Häuser für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadHousesForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        houses = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/houses");
    const data = await res.json();
    houses = (data.houses || []).filter(h => h.world === world);
    render();
}

// -------------------------------------------------------------
// Job-Punkte für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadJobPointsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        jobPoints = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/job_points");
    const data = await res.json();
    jobPoints = (data.jobPoints || []).filter(jp => jp.world === world);
    render();
}

// -------------------------------------------------------------
// Taxi-Stände für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadTaxiStandsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        taxiStands = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/taxi_stands");
    const data = await res.json();
    taxiStands = (data.taxiStands || []).filter(t => t.world === world);
    render();
}

// -------------------------------------------------------------
// Krankenhäuser für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadHospitalsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        hospitals = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/hospitals");
    const data = await res.json();
    hospitals = (data.hospitals || []).filter(h => h.world === world);
    render();
}

// -------------------------------------------------------------
// Gefängnisse für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadPrisonsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        prisons = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/prisons");
    const data = await res.json();
    prisons = (data.prisons || []).filter(p => p.world === world);
    render();
}

// -------------------------------------------------------------
// Abschlepphöfe für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadImpoundLotsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        impoundLots = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/impound_lots");
    const data = await res.json();
    impoundLots = (data.lots || []).filter(l => l.world === world);
    render();
}

// -------------------------------------------------------------
// Feuerwachen für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadFireStationsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        fireStations = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/fire_stations");
    const data = await res.json();
    fireStations = (data.stations || []).filter(s => s.world === world);
    render();
}

// -------------------------------------------------------------
// Drogen-Standorte für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadHarvestSpotsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) { harvestSpots = []; render(); return; }
    const res = await authFetch("/api/admin/drug_harvest_spots");
    const data = await res.json();
    harvestSpots = (data.spots || []).filter(s => s.world === world);
    render();
}

async function loadProcessSpotsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) { processSpots = []; render(); return; }
    const res = await authFetch("/api/admin/drug_process_spots");
    const data = await res.json();
    processSpots = (data.spots || []).filter(s => s.world === world);
    render();
}

async function loadDealerSpotsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) { dealerSpots = []; render(); return; }
    const res = await authFetch("/api/admin/drug_dealer_spots");
    const data = await res.json();
    dealerSpots = (data.spots || []).filter(s => s.world === world);
    render();
}

async function loadClothingShopsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) { clothingShops = []; render(); return; }
    const res = await authFetch("/api/admin/clothing_shops");
    const data = await res.json();
    clothingShops = (data.shops || []).filter(s => s.world === world);
    render();
}

async function loadInsuranceOfficesForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) { insuranceOffices = []; render(); return; }
    const res = await authFetch("/api/admin/insurance_offices");
    const data = await res.json();
    insuranceOffices = (data.offices || []).filter(s => s.world === world);
    render();
}

async function loadPlateOfficesForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) { plateOffices = []; render(); return; }
    const res = await authFetch("/api/admin/plate_offices");
    const data = await res.json();
    plateOffices = (data.offices || []).filter(s => s.world === world);
    render();
}

async function loadTrailerShopsForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) { trailerShops = []; render(); return; }
    const res = await authFetch("/api/admin/trailer_shops");
    const data = await res.json();
    trailerShops = (data.shops || []).filter(s => s.world === world);
    render();
}

// -------------------------------------------------------------
// Territoriums-Zonen für die aktuelle Map aus der DB laden (NEU)
// -------------------------------------------------------------
async function loadTerritoryZonesForCurrentMap() {
    const world = mapNameInput.value.trim();
    if (!world) {
        territoryZones = [];
        render();
        return;
    }

    const res = await authFetch("/api/admin/territory_zones");
    const data = await res.json();
    territoryZones = (data.zones || []).filter(z => z.world === world);
    render();
}

// Jobliste laden (für Auswahl bei Job-Garage/Job-Punkt platzieren)
async function loadJobsForEditor() {
    const res = await authFetch("/api/admin/jobs");
    const data = await res.json();
    allJobsForEditor = data.jobs || [];
}
loadJobsForEditor();

function pickJobId() {
    if (allJobsForEditor.length === 0) {
        alert("Keine Jobs angelegt. Erst in der Job-Verwaltung einen Job anlegen.");
        return null;
    }
    const list = allJobsForEditor.map(j => `${j.id} = ${j.name}`).join("\n");
    const idStr = prompt(`Welcher Job? (ID eingeben)\n\n${list}`);
    if (!idStr) return null;
    const id = Number(idStr);
    if (!allJobsForEditor.some(j => j.id === id)) {
        alert("Ungültige Job-ID.");
        return null;
    }
    return id;
}

// -------------------------------------------------------------
// Map laden
// -------------------------------------------------------------
mapSelect.onchange = () => {
    const name = mapSelect.value;
    if (!name) return;

    fetch("/api/get_maps")
        .then(res => res.json())
        .then(data => {
            const map = data.maps[name];

            mapNameInput.value = map.name;
            tiles = map.tiles;
            doors = map.doors || [];
            objects = map.objects || [];
            atms = map.atms || [];
            spawn = map.spawn;

            rows = tiles.length;
            cols = tiles[0].length;

            // tileRot: falls die Map noch keine Drehwinkel-Daten hat (ältere Karte), mit 0 auffüllen
            if (map.tileRot && map.tileRot.length === rows) {
                tileRot = map.tileRot;
            } else {
                tileRot = [];
                for (let y = 0; y < rows; y++) {
                    tileRot[y] = [];
                    for (let x = 0; x < cols; x++) tileRot[y][x] = 0;
                }
            }

            editorCam.x = 0;
            editorCam.y = 0;
            updateCamLabel();

            render();
            loadShopsForCurrentMap(); // Shops kommen aus der DB, nicht aus der Map-Datei
            loadGaragesForCurrentMap(); // Garagen ebenfalls aus der DB
            loadJobcentersForCurrentMap(); // Jobcenter ebenfalls aus der DB
            loadGasStationsForCurrentMap(); // Tankstellen ebenfalls aus der DB
            loadRepairShopsForCurrentMap(); // Werkstätten ebenfalls aus der DB
            loadHousesForCurrentMap();
            loadJobPointsForCurrentMap();
            loadTaxiStandsForCurrentMap();
            loadHospitalsForCurrentMap();
            loadPrisonsForCurrentMap();
            loadImpoundLotsForCurrentMap();
            loadTerritoryZonesForCurrentMap();
            loadFireStationsForCurrentMap();
            loadHarvestSpotsForCurrentMap();
            loadProcessSpotsForCurrentMap();
            loadDealerSpotsForCurrentMap();
            loadClothingShopsForCurrentMap();
            loadInsuranceOfficesForCurrentMap();
            loadPlateOfficesForCurrentMap();
            loadTrailerShopsForCurrentMap();
        });
};

// -------------------------------------------------------------
// Map speichern
// -------------------------------------------------------------
function buildMapData() {
    const name = mapNameInput.value.trim();
    return {
        name,
        spawn,
        tiles,
        tileRot,
        doors,
        objects,
        atms
        // shops NICHT mehr mitspeichern - die leben jetzt in der DB
    };
}

saveMapBtn.onclick = () => {
    const name = mapNameInput.value.trim();
    if (!name) return alert("Map-Name fehlt!");

    authFetch("/api/save_map", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name, data: buildMapData() })
    })
        .then(res => res.json())
        .then(data => {
            if (data.ok) {
                alert("Map gespeichert!");
                loadMapList();
                loadShopsForCurrentMap();
                loadGaragesForCurrentMap();
                loadJobcentersForCurrentMap();
                loadGasStationsForCurrentMap();
                loadRepairShopsForCurrentMap();
                loadHousesForCurrentMap();
                loadJobPointsForCurrentMap();
                loadTaxiStandsForCurrentMap();
                loadHospitalsForCurrentMap();
                loadPrisonsForCurrentMap();
                loadTerritoryZonesForCurrentMap();
                loadImpoundLotsForCurrentMap();
                loadFireStationsForCurrentMap();
                loadHarvestSpotsForCurrentMap();
                loadProcessSpotsForCurrentMap();
                loadDealerSpotsForCurrentMap();
                loadClothingShopsForCurrentMap();
                loadInsuranceOfficesForCurrentMap();
                loadPlateOfficesForCurrentMap();
                loadTrailerShopsForCurrentMap();
            } else {
                alert("Fehler: " + data.error);
            }
        });
};

function saveMap() {
    const name = mapNameInput.value.trim();
    if (!name) return alert("Map-Name fehlt!");

    authFetch("/api/save_map", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name, data: buildMapData() })
    })
        .then(res => res.json())
        .then(data => {
            if (data.ok) {
                alert("Map gespeichert!");
                loadMapList();
            } else {
                alert("Fehler: " + data.error);
            }
        });
}

// -------------------------------------------------------------
// Map-Größe ändern
// -------------------------------------------------------------
resizeMapBtn.onclick = () => {
    const newW = parseInt(mapWidthInput.value);
    const newH = parseInt(mapHeightInput.value);

    if (!newW || !newH) return;

    const newTiles = [];
    const newTileRot = [];

    for (let y = 0; y < newH; y++) {
        newTiles[y] = [];
        newTileRot[y] = [];
        for (let x = 0; x < newW; x++) {
            newTiles[y][x] = tiles[y]?.[x] ?? 1;
            newTileRot[y][x] = tileRot[y]?.[x] ?? 0;
        }
    }

    tiles = newTiles;
    tileRot = newTileRot;
    cols = newW;
    rows = newH;

    render();
};

// -------------------------------------------------------------
// Canvas Click
// -------------------------------------------------------------
canvas.addEventListener("contextmenu", e => e.preventDefault());

let isPaintDragging = false;
let paintDragButton = 0;

canvas.addEventListener("mousedown", e => {
    if (e.button === 1) return; // Mittelklick wird vom Dragging-Handler oben behandelt
    e.preventDefault();

    if (modeSelect.value === "tile") {
        isPaintDragging = true;
        paintDragButton = e.button;
    }

    handleCanvasClick(e);
});

canvas.addEventListener("mousemove", e => {
    if (!isPaintDragging || modeSelect.value !== "tile") return;

    const rect = canvas.getBoundingClientRect();
    const mx = e.clientX - rect.left + editorCam.x;
    const my = e.clientY - rect.top + editorCam.y;
    const tileX = Math.floor(mx / tileSize);
    const tileY = Math.floor(my / tileSize);
    if (tileX < 0 || tileY < 0 || tileX >= cols || tileY >= rows) return;

    paintTileBrush(tileX, tileY, paintDragButton === 0 ? selectedTile : 0);
    render();
});

document.addEventListener("mouseup", () => {
    isPaintDragging = false;
});

function handleCanvasClick(e) {

    const rect = canvas.getBoundingClientRect();
    const mx = e.clientX - rect.left + editorCam.x;
    const my = e.clientY - rect.top + editorCam.y;

    const tileX = Math.floor(mx / tileSize);
    const tileY = Math.floor(my / tileSize);

    if (tileX < 0 || tileY < 0 || tileX >= cols || tileY >= rows) return;

    const mode = modeSelect.value;

    // TILES
    if (mode === "tile") {
        paintTileBrush(tileX, tileY, e.button === 0 ? selectedTile : 0);
        render();
        return;
    }

    // DREHEN: zuerst prüfen, ob an dieser Stelle ein Objekt steht (das hat Vorrang),
    // sonst wird stattdessen die Tile darunter gedreht
    if (mode === "rotate") {
        const ox = tileX * tileSize;
        const oy = tileY * tileSize;
        const obj = objects.find(o => o.x === ox && o.y === oy);

        if (obj) {
            const current = obj.rot || 0;
            if (e.button === 0) obj.rot = (current + 90) % 360;
            else if (e.button === 2) obj.rot = (current + 270) % 360;
            render();
            return;
        }

        if (tileY < 0 || tileX < 0 || tileY >= tiles.length || tileX >= tiles[0].length) return;
        if (!tileRot[tileY]) tileRot[tileY] = [];

        const current = tileRot[tileY][tileX] || 0;
        if (e.button === 0) {
            tileRot[tileY][tileX] = (current + 90) % 360;
        } else if (e.button === 2) {
            tileRot[tileY][tileX] = (current + 270) % 360;
        }
        render();
        return;
    }

    // SPAWN
    if (mode === "spawn") {
        if (e.button === 0) {
            spawn.x = tileX * tileSize;
            spawn.y = tileY * tileSize;
            render();
        }
        return;
    }

    // DOORS
    if (mode === "door") {
        if (e.button === 0) {
            doors.push({
                x: tileX * tileSize,
                y: tileY * tileSize,
                targetMap: doorTargetMap.value,
                targetX: parseInt(doorTargetX.value),
                targetY: parseInt(doorTargetY.value)
            });
            render();
        }
        if (e.button === 2) {
            doors = doors.filter(d => !(d.x === tileX * tileSize && d.y === tileY * tileSize));
            render();
        }
        return;
    }

    // OBJECTS
    if (mode === "object") {
        const ox = tileX * tileSize;
        const oy = tileY * tileSize;

        if (e.button === 0) {
            if (!selectedObjectType) {
                alert("Bitte zuerst einen Objekt-Typ in der Palette unten auswählen.");
                return;
            }

            const newObj = { type: selectedObjectType, x: ox, y: oy };

            const cfg = objectConfig[selectedObjectType];
            if (cfg && cfg.action === "toggle_gate") {
                const side = prompt(
                    "Einbahn-Sperre für dieses Tor? Leer lassen = von beiden Seiten bedienbar.\n" +
                    "Gültige Werte: top, bottom, left, right\n" +
                    "(die gesperrte Seite kann das Tor NICHT öffnen/schließen)",
                    ""
                );
                const trimmed = (side || "").trim().toLowerCase();
                if (["top", "bottom", "left", "right"].includes(trimmed)) {
                    newObj.oneWaySide = trimmed;
                }
            }

            objects.push(newObj);
            render();
        }

        if (e.button === 2) {
            objects = objects.filter(o => !(o.x === ox && o.y === oy));
            render();
        }
        return;
    }

    // SHOPS (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "shop") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = shops.find(s => s.x === tileX && s.y === tileY);
            if (existing) {
                alert(`Hier steht schon Shop "#${existing.id}". Items verwaltest du im Admin-Panel.`);
                return;
            }

            const name = prompt("Shop-Name:");
            if (!name) return;

            authFetch("/api/admin/shops", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadShopsForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = shops.find(s => s.x === tileX && s.y === tileY);
            if (!existing) return;

            if (!confirm(`Shop "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/shops/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadShopsForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // GARAGEN (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "garage") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = garages.find(g => g.x === tileX && g.y === tileY);
            if (existing) return;

            const name = prompt("Garage-Name:");
            if (!name) return;

            const isJobGarage = confirm("Soll das eine JOB-Garage (Fuhrpark) sein?\nOK = Job-Garage, Abbrechen = normale private Garage");
            let jobId = null;
            if (isJobGarage) {
                jobId = pickJobId();
                if (jobId === null) return;
            }

            authFetch("/api/admin/garages", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY, jobId })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadGaragesForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = garages.find(g => g.x === tileX && g.y === tileY);
            if (!existing) return;

            if (!confirm(`Garage "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/garages/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadGaragesForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // HÄUSER (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "house") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = houses.find(h => h.x === tileX && h.y === tileY);
            if (existing) return;

            const name = prompt("Haus-Name:");
            if (!name) return;
            const priceStr = prompt("Kaufpreis ($):", "1000");
            const price = Number(priceStr);
            if (isNaN(price) || price <= 0) return;

            authFetch("/api/admin/houses", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY, price })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadHousesForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = houses.find(h => h.x === tileX && h.y === tileY);
            if (!existing) return;

            if (!confirm(`Haus "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/houses/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadHousesForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // JOB-PUNKTE (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "jobpoint") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = jobPoints.find(jp => jp.x === tileX && jp.y === tileY);
            if (existing) return;

            const jobId = pickJobId();
            if (jobId === null) return;

            const name = prompt("Name des Zielpunkts (z.B. 'Ladung abholen'):");
            if (!name) return;

            const itemId = prompt(
                "Item-ID, das hier abgeholt/abgeliefert wird (muss in der Item-Verwaltung existieren):",
                "package"
            );
            if (!itemId) return;

            const isDropoff = confirm("Ist das ein LIEFERPUNKT (Item abgeben)?\nOK = Lieferpunkt, Abbrechen = Abholpunkt");
            const kind = isDropoff ? "dropoff" : "pickup";

            let reward = 50;
            if (isDropoff) {
                const rewardStr = prompt("Belohnung pro Lieferung ($):", "50");
                reward = Number(rewardStr) || 50;
            }

            authFetch("/api/admin/job_points", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ jobId, name, world, x: tileX, y: tileY, kind, reward, itemId })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadJobPointsForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = jobPoints.find(jp => jp.x === tileX && jp.y === tileY);
            if (!existing) return;

            if (!confirm(`Job-Punkt "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/job_points/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadJobPointsForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // TERRITORIUMS-ZONEN (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "zone") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = territoryZones.find(z => z.x === tileX && z.y === tileY);
            if (existing) return;

            const name = prompt("Name der Zone (z.B. 'Hafenviertel'):");
            if (!name) return;

            authFetch("/api/admin/territory_zones", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadTerritoryZonesForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = territoryZones.find(z => z.x === tileX && z.y === tileY);
            if (!existing) return;

            if (!confirm(`Zone "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/territory_zones/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadTerritoryZonesForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // DROGEN-ANBAUSTELLEN (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "drug_harvest") {
        const world = mapNameInput.value.trim();
        if (!world) { alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern."); return; }

        if (e.button === 0) {
            const existing = harvestSpots.find(s => s.x === tileX && s.y === tileY);
            if (existing) return;

            const drugId = pickDrugId();
            if (!drugId) return;
            const name = prompt("Name der Anbaustelle:", "Anbaustelle");
            if (!name) return;

            authFetch("/api/admin/drug_harvest_spots", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ drugId, name, world, x: tileX, y: tileY })
            }).then(res => res.json()).then(data => {
                if (data.ok) loadHarvestSpotsForCurrentMap();
                else alert("Fehler: " + (data.error || "unbekannt"));
            });
        }

        if (e.button === 2) {
            const existing = harvestSpots.find(s => s.x === tileX && s.y === tileY);
            if (!existing) return;
            if (!confirm(`Anbaustelle "#${existing.id}" wirklich löschen?`)) return;

            authFetch("/api/admin/drug_harvest_spots/" + existing.id, { method: "DELETE" })
                .then(res => res.json()).then(data => {
                    if (data.ok) loadHarvestSpotsForCurrentMap();
                    else alert("Löschen fehlgeschlagen.");
                });
        }
        return;
    }

    // DROGEN-LABORE (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "drug_process") {
        const world = mapNameInput.value.trim();
        if (!world) { alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern."); return; }

        if (e.button === 0) {
            const existing = processSpots.find(s => s.x === tileX && s.y === tileY);
            if (existing) return;

            const drugId = pickDrugId();
            if (!drugId) return;
            const name = prompt("Name des Labors:", "Labor");
            if (!name) return;

            authFetch("/api/admin/drug_process_spots", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ drugId, name, world, x: tileX, y: tileY })
            }).then(res => res.json()).then(data => {
                if (data.ok) loadProcessSpotsForCurrentMap();
                else alert("Fehler: " + (data.error || "unbekannt"));
            });
        }

        if (e.button === 2) {
            const existing = processSpots.find(s => s.x === tileX && s.y === tileY);
            if (!existing) return;
            if (!confirm(`Labor "#${existing.id}" wirklich löschen?`)) return;

            authFetch("/api/admin/drug_process_spots/" + existing.id, { method: "DELETE" })
                .then(res => res.json()).then(data => {
                    if (data.ok) loadProcessSpotsForCurrentMap();
                    else alert("Löschen fehlgeschlagen.");
                });
        }
        return;
    }

    // DROGEN-VERKAUFSORTE-POOL (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "drug_dealer") {
        const world = mapNameInput.value.trim();
        if (!world) { alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern."); return; }

        if (e.button === 0) {
            const existing = dealerSpots.find(s => s.x === tileX && s.y === tileY);
            if (existing) return;

            const drugId = pickDrugId();
            if (!drugId) return;
            const name = prompt("Name des Verkaufsorts:", "Verkaufsstelle");
            if (!name) return;

            authFetch("/api/admin/drug_dealer_spots", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ drugId, name, world, x: tileX, y: tileY })
            }).then(res => res.json()).then(data => {
                if (data.ok) loadDealerSpotsForCurrentMap();
                else alert("Fehler: " + (data.error || "unbekannt"));
            });
        }

        if (e.button === 2) {
            const existing = dealerSpots.find(s => s.x === tileX && s.y === tileY);
            if (!existing) return;
            if (!confirm(`Verkaufsort "#${existing.id}" wirklich aus dem Pool löschen?`)) return;

            authFetch("/api/admin/drug_dealer_spots/" + existing.id, { method: "DELETE" })
                .then(res => res.json()).then(data => {
                    if (data.ok) loadDealerSpotsForCurrentMap();
                    else alert("Löschen fehlgeschlagen.");
                });
        }
        return;
    }

    // KLEIDUNGSLÄDEN (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)


    if (mode === "trailershop") {
        const world = mapNameInput.value.trim();
        if (!world) { alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern."); return; }

        if (e.button === 0) {
            const existing = trailerShops.find(s => s.x === tileX && s.y === tileY);
            if (existing) return;

            const name = prompt("Name der Anhänger-Shop:", "Anhänger-Shop");
            if (!name) return;

            authFetch("/api/admin/trailer_shops", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY })
            }).then(res => res.json()).then(data => {
                if (data.ok) loadTrailerShopsForCurrentMap();
                else alert("Fehler: " + (data.error || "unbekannt"));
            });
        }

        if (e.button === 2) {
            const existing = trailerShops.find(s => s.x === tileX && s.y === tileY);
            if (!existing) return;
            if (!confirm(`Anhänger-Shop "#${existing.id}" wirklich löschen?`)) return;

            authFetch("/api/admin/trailer_shops/" + existing.id, { method: "DELETE" })
                .then(res => res.json()).then(data => {
                    if (data.ok) loadTrailerShopsForCurrentMap();
                    else alert("Löschen fehlgeschlagen.");
                });
        }
        return;
    }
    if (mode === "insuranceoffice") {
        const world = mapNameInput.value.trim();
        if (!world) { alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern."); return; }

        if (e.button === 0) {
            const existing = insuranceOffices.find(s => s.x === tileX && s.y === tileY);
            if (existing) return;

            const name = prompt("Name der Versicherung:", "Versicherung");
            if (!name) return;

            authFetch("/api/admin/insurance_offices", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY })
            }).then(res => res.json()).then(data => {
                if (data.ok) loadInsuranceOfficesForCurrentMap();
                else alert("Fehler: " + (data.error || "unbekannt"));
            });
        }

        if (e.button === 2) {
            const existing = insuranceOffices.find(s => s.x === tileX && s.y === tileY);
            if (!existing) return;
            if (!confirm(`Versicherung "#${existing.id}" wirklich löschen?`)) return;

            authFetch("/api/admin/insurance_offices/" + existing.id, { method: "DELETE" })
                .then(res => res.json()).then(data => {
                    if (data.ok) loadInsuranceOfficesForCurrentMap();
                    else alert("Löschen fehlgeschlagen.");
                });
        }
        return;
    }

    if (mode === "plateoffice") {
        const world = mapNameInput.value.trim();
        if (!world) { alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern."); return; }

        if (e.button === 0) {
            const existing = plateOffices.find(s => s.x === tileX && s.y === tileY);
            if (existing) return;

            const name = prompt("Name der Zulassungsstelle:", "Kfz-Zulassungsstelle");
            if (!name) return;

            authFetch("/api/admin/plate_offices", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY })
            }).then(res => res.json()).then(data => {
                if (data.ok) loadPlateOfficesForCurrentMap();
                else alert("Fehler: " + (data.error || "unbekannt"));
            });
        }

        if (e.button === 2) {
            const existing = plateOffices.find(s => s.x === tileX && s.y === tileY);
            if (!existing) return;
            if (!confirm(`Zulassungsstelle "#${existing.id}" wirklich löschen?`)) return;

            authFetch("/api/admin/plate_offices/" + existing.id, { method: "DELETE" })
                .then(res => res.json()).then(data => {
                    if (data.ok) loadPlateOfficesForCurrentMap();
                    else alert("Löschen fehlgeschlagen.");
                });
        }
        return;
    }
    if (mode === "clothingshop") {
        const world = mapNameInput.value.trim();
        if (!world) { alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern."); return; }

        if (e.button === 0) {
            const existing = clothingShops.find(s => s.x === tileX && s.y === tileY);
            if (existing) return;

            const name = prompt("Name des Kleidungsladens:", "Kleidungsladen");
            if (!name) return;

            authFetch("/api/admin/clothing_shops", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY })
            }).then(res => res.json()).then(data => {
                if (data.ok) loadClothingShopsForCurrentMap();
                else alert("Fehler: " + (data.error || "unbekannt"));
            });
        }

        if (e.button === 2) {
            const existing = clothingShops.find(s => s.x === tileX && s.y === tileY);
            if (!existing) return;
            if (!confirm(`Kleidungsladen "#${existing.id}" wirklich löschen?`)) return;

            authFetch("/api/admin/clothing_shops/" + existing.id, { method: "DELETE" })
                .then(res => res.json()).then(data => {
                    if (data.ok) loadClothingShopsForCurrentMap();
                    else alert("Löschen fehlgeschlagen.");
                });
        }
        return;
    }

    // FEUERWACHEN (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "firestation") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = fireStations.find(s => s.x === tileX && s.y === tileY);
            if (existing) return;

            const name = prompt("Feuerwachen-Name:");
            if (!name) return;

            authFetch("/api/admin/fire_stations", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadFireStationsForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = fireStations.find(s => s.x === tileX && s.y === tileY);
            if (!existing) return;

            if (!confirm(`Feuerwache "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/fire_stations/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadFireStationsForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // ABSCHLEPPHÖFE (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "impound") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = impoundLots.find(l => l.x === tileX && l.y === tileY);
            if (existing) return;

            const name = prompt("Abschlepphof-Name:");
            if (!name) return;

            authFetch("/api/admin/impound_lots", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadImpoundLotsForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = impoundLots.find(l => l.x === tileX && l.y === tileY);
            if (!existing) return;

            if (!confirm(`Abschlepphof "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/impound_lots/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadImpoundLotsForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // GEFÄNGNISSE (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "prison") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = prisons.find(p => p.x === tileX && p.y === tileY);
            if (existing) return;

            const name = prompt("Gefängnis-Name:");
            if (!name) return;

            authFetch("/api/admin/prisons", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadPrisonsForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = prisons.find(p => p.x === tileX && p.y === tileY);
            if (!existing) return;

            if (!confirm(`Gefängnis "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/prisons/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadPrisonsForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // KRANKENHÄUSER (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "hospital") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = hospitals.find(h => h.x === tileX && h.y === tileY);
            if (existing) return;

            const name = prompt("Krankenhaus-Name:");
            if (!name) return;

            authFetch("/api/admin/hospitals", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadHospitalsForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = hospitals.find(h => h.x === tileX && h.y === tileY);
            if (!existing) return;

            if (!confirm(`Krankenhaus "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/hospitals/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadHospitalsForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // TAXI-STÄNDE (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "taxistand") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = taxiStands.find(t => t.x === tileX && t.y === tileY);
            if (existing) return;

            const name = prompt("Taxi-Stand-Name:");
            if (!name) return;

            authFetch("/api/admin/taxi_stands", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadTaxiStandsForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = taxiStands.find(t => t.x === tileX && t.y === tileY);
            if (!existing) return;

            if (!confirm(`Taxi-Stand "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/taxi_stands/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadTaxiStandsForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // JOBCENTER (DB-basiert: Linksklick = anlegen, Rechtsklick = löschen)
    if (mode === "jobcenter") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = jobcenters.find(j => j.x === tileX && j.y === tileY);
            if (existing) return;

            const name = prompt("Jobcenter-Name:");
            if (!name) return;

            authFetch("/api/admin/jobcenters", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadJobcentersForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = jobcenters.find(j => j.x === tileX && j.y === tileY);
            if (!existing) return;

            if (!confirm(`Jobcenter "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/jobcenters/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadJobcentersForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // TANKSTELLEN (DB-basiert: Linksklick = anlegen/Preis ändern, Rechtsklick = löschen)
    if (mode === "gasstation") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = gasStations.find(g => g.x === tileX && g.y === tileY);

            if (existing) {
                const priceStr = prompt("Neuer Preis pro Liter ($):", existing.price);
                if (priceStr === null) return;
                const price = Number(priceStr);
                if (isNaN(price) || price <= 0) return;

                authFetch("/api/admin/gas_stations", {
                    method: "POST",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ id: existing.id, price })
                })
                    .then(res => res.json())
                    .then(data => {
                        if (data.ok) loadGasStationsForCurrentMap();
                        else alert("Fehler beim Aktualisieren.");
                    });
                return;
            }

            const name = prompt("Tankstellen-Name:");
            if (!name) return;
            const priceStr = prompt("Preis pro Liter ($):", "2.00");
            const price = Number(priceStr);
            if (isNaN(price) || price <= 0) return;

            authFetch("/api/admin/gas_stations", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY, price })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadGasStationsForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = gasStations.find(g => g.x === tileX && g.y === tileY);
            if (!existing) return;

            if (!confirm(`Tankstelle "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/gas_stations/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadGasStationsForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // WERKSTÄTTEN (DB-basiert: Linksklick = anlegen/Preis ändern, Rechtsklick = löschen)
    if (mode === "repairshop") {
        const world = mapNameInput.value.trim();
        if (!world) {
            alert("Bitte zuerst einen Map-Namen eingeben und die Map speichern.");
            return;
        }

        if (e.button === 0) {
            const existing = repairShops.find(r => r.x === tileX && r.y === tileY);

            if (existing) {
                const priceStr = prompt("Neuer Preis pro Reparatur-Punkt ($):", existing.price_per_point);
                if (priceStr === null) return;
                const price = Number(priceStr);
                if (isNaN(price) || price <= 0) return;

                authFetch("/api/admin/repair_shops", {
                    method: "POST",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ id: existing.id, pricePerPoint: price })
                })
                    .then(res => res.json())
                    .then(data => {
                        if (data.ok) loadRepairShopsForCurrentMap();
                        else alert("Fehler beim Aktualisieren.");
                    });
                return;
            }

            const name = prompt("Werkstatt-Name:");
            if (!name) return;
            const priceStr = prompt("Preis pro Reparatur-Punkt ($):", "5.00");
            const price = Number(priceStr);
            if (isNaN(price) || price <= 0) return;

            authFetch("/api/admin/repair_shops", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name, world, x: tileX, y: tileY, pricePerPoint: price })
            })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadRepairShopsForCurrentMap();
                    } else {
                        alert("Fehler: " + (data.error || "unbekannt"));
                    }
                });
        }

        if (e.button === 2) {
            const existing = repairShops.find(r => r.x === tileX && r.y === tileY);
            if (!existing) return;

            if (!confirm(`Werkstatt "#${existing.id}" hier wirklich löschen?`)) return;

            authFetch("/api/admin/repair_shops/" + existing.id, { method: "DELETE" })
                .then(res => res.json())
                .then(data => {
                    if (data.ok) {
                        loadRepairShopsForCurrentMap();
                    } else {
                        alert("Löschen fehlgeschlagen.");
                    }
                });
        }
        return;
    }

    // ATMS (weiterhin in der Map-Datei gespeichert)
    if (mode === "atm") {
        if (e.button === 0) {
            const existing = atms.find(a => a.x === tileX && a.y === tileY);
            if (existing) return;

            atms.push({
                id: "atm_" + Date.now(),
                x: tileX,
                y: tileY
            });
            render();
        }

        if (e.button === 2) {
            atms = atms.filter(a => !(a.x === tileX && a.y === tileY));
            render();
        }
        return;
    }
}

// -------------------------------------------------------------
// Render Shops / ATMs
// -------------------------------------------------------------
function renderShops() {
    shops.forEach(s => {
        const px = s.x * tileSize - editorCam.x;
        const py = s.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "yellow";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);

        ctx.fillStyle = "black";
        ctx.font = "10px Arial";
        ctx.fillText("#" + s.id, px + 2, py + 12);
    });
}

function renderATMs() {
    atms.forEach(a => {
        const px = a.x * tileSize - editorCam.x;
        const py = a.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "blue";
        ctx.fillRect(px, py, tileSize, tileSize);
    });
}

function renderGarages() {
    garages.forEach(g => {
        const px = g.x * tileSize - editorCam.x;
        const py = g.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "green";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);

        ctx.fillStyle = "white";
        ctx.font = "10px Arial";
        ctx.fillText("#" + g.id, px + 2, py + 12);
    });
}

function renderJobcenters() {
    jobcenters.forEach(j => {
        const px = j.x * tileSize - editorCam.x;
        const py = j.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "purple";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);

        ctx.fillStyle = "white";
        ctx.font = "10px Arial";
        ctx.fillText("#" + j.id, px + 2, py + 12);
    });
}

function renderGasStations() {
    gasStations.forEach(g => {
        const px = g.x * tileSize - editorCam.x;
        const py = g.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#e67e22";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);

        ctx.fillStyle = "white";
        ctx.font = "9px Arial";
        ctx.fillText("#" + g.id, px + 2, py + 12);
        ctx.fillText(g.price.toFixed(2) + "$", px + 2, py + 22);
    });
}

function renderRepairShops() {
    repairShops.forEach(r => {
        const px = r.x * tileSize - editorCam.x;
        const py = r.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#7f8c8d";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);

        ctx.fillStyle = "white";
        ctx.font = "9px Arial";
        ctx.fillText("#" + r.id, px + 2, py + 12);
        ctx.fillText(r.price_per_point.toFixed(2) + "$", px + 2, py + 22);
    });
}

function renderHouses() {
    houses.forEach(h => {
        const px = h.x * tileSize - editorCam.x;
        const py = h.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = h.owner_id ? "#8e6b4a" : "#c9a876";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);

        ctx.fillStyle = "black";
        ctx.font = "9px Arial";
        ctx.fillText("#" + h.id, px + 2, py + 12);
        ctx.fillText(h.price + "$", px + 2, py + 22);
    });
}

function renderJobPoints() {
    jobPoints.forEach(jp => {
        const px = jp.x * tileSize - editorCam.x;
        const py = jp.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = jp.kind === "dropoff" ? "#3498db" : "#2ecc71";
        ctx.beginPath();
        ctx.arc(px + tileSize / 2, py + tileSize / 2, 12, 0, Math.PI * 2);
        ctx.fill();
        ctx.strokeStyle = "black";
        ctx.stroke();

        ctx.fillStyle = "black";
        ctx.font = "9px Arial";
        const label = jp.kind === "dropoff" ? `Job ${jp.job_id}: ${jp.name} (${jp.reward}$)` : `Job ${jp.job_id}: ${jp.name}`;
        ctx.fillText(label, px - 4, py + 34);
    });
}

function renderTaxiStands() {
    taxiStands.forEach(t => {
        const px = t.x * tileSize - editorCam.x;
        const py = t.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#f5d90a";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);

        ctx.fillStyle = "black";
        ctx.font = "9px Arial";
        ctx.fillText("#" + t.id + " " + t.name, px - 4, py + 44);
    });
}

function renderHospitals() {
    hospitals.forEach(h => {
        const px = h.x * tileSize - editorCam.x;
        const py = h.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#e74c3c";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);

        ctx.fillStyle = "black";
        ctx.font = "9px Arial";
        ctx.fillText("#" + h.id + " " + h.name, px - 4, py + 44);
    });
}

function renderPrisons() {
    prisons.forEach(p => {
        const px = p.x * tileSize - editorCam.x;
        const py = p.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#555555";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);

        ctx.fillStyle = "white";
        ctx.font = "9px Arial";
        ctx.fillText("#" + p.id + " " + p.name, px - 4, py + 44);
    });
}

function renderImpoundLots() {
    impoundLots.forEach(l => {
        const px = l.x * tileSize - editorCam.x;
        const py = l.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#b8860b";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);

        ctx.fillStyle = "white";
        ctx.font = "9px Arial";
        ctx.fillText("#" + l.id + " " + l.name, px - 4, py + 44);
    });
}

function renderFireStations() {
    fireStations.forEach(s => {
        const px = s.x * tileSize - editorCam.x;
        const py = s.y * tileSize - editorCam.y;

        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#c0392b";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);

        ctx.fillStyle = "white";
        ctx.font = "9px Arial";
        ctx.fillText("#" + s.id + " " + s.name, px - 4, py + 44);
    });
}

function renderHarvestSpots() {
    harvestSpots.forEach(s => {
        const px = s.x * tileSize - editorCam.x;
        const py = s.y * tileSize - editorCam.y;
        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#2ecc71";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);
        ctx.fillStyle = "black";
        ctx.font = "9px Arial";
        ctx.fillText(`#${s.id} ${s.name} (${s.drug_id})`, px - 4, py + 44);
    });
}

function renderProcessSpots() {
    processSpots.forEach(s => {
        const px = s.x * tileSize - editorCam.x;
        const py = s.y * tileSize - editorCam.y;
        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#8e44ad";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);
        ctx.fillStyle = "white";
        ctx.font = "9px Arial";
        ctx.fillText(`#${s.id} ${s.name} (${s.drug_id})`, px - 4, py + 44);
    });
}

function renderDealerSpots() {
    dealerSpots.forEach(s => {
        const px = s.x * tileSize - editorCam.x;
        const py = s.y * tileSize - editorCam.y;
        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#e67e22";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);
        ctx.fillStyle = "black";
        ctx.font = "9px Arial";
        ctx.fillText(`#${s.id} ${s.name} (${s.drug_id}) [Pool]`, px - 4, py + 44);
    });
}

function renderClothingShops() {
    clothingShops.forEach(s => {
        const px = s.x * tileSize - editorCam.x;
        const py = s.y * tileSize - editorCam.y;
        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#e84393";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);
        ctx.fillStyle = "white";
        ctx.font = "9px Arial";
        ctx.fillText(`#${s.id} ${s.name}`, px - 4, py + 44);
    });
}

function renderInsuranceOffices() {
    insuranceOffices.forEach(s => {
        const px = s.x * tileSize - editorCam.x;
        const py = s.y * tileSize - editorCam.y;
        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#0984e3";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);
        ctx.fillStyle = "white";
        ctx.font = "9px Arial";
        ctx.fillText(`#${s.id} ${s.name}`, px - 4, py + 44);
    });
}

function renderPlateOffices() {
    plateOffices.forEach(s => {
        const px = s.x * tileSize - editorCam.x;
        const py = s.y * tileSize - editorCam.y;
        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#636e72";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);
        ctx.fillStyle = "white";
        ctx.font = "9px Arial";
        ctx.fillText(`#${s.id} ${s.name}`, px - 4, py + 44);
    });
}

function renderTrailerShops() {
    trailerShops.forEach(s => {
        const px = s.x * tileSize - editorCam.x;
        const py = s.y * tileSize - editorCam.y;
        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;

        ctx.fillStyle = "#8e6a3d";
        ctx.fillRect(px, py, tileSize, tileSize);
        ctx.strokeStyle = "black";
        ctx.strokeRect(px, py, tileSize, tileSize);
        ctx.fillStyle = "white";
        ctx.font = "9px Arial";
        ctx.fillText(`#${s.id} ${s.name}`, px - 4, py + 44);
    });
}

function renderTerritoryZones() {
    territoryZones.forEach(z => {
        const cx = z.x * tileSize - editorCam.x + tileSize / 2;
        const cy = z.y * tileSize - editorCam.y + tileSize / 2;
        const radius = 150;

        if (cx < -radius || cy < -radius || cx > canvas.width + radius || cy > canvas.height + radius) return;

        ctx.strokeStyle = "#9b59b6";
        ctx.lineWidth = 2;
        ctx.setLineDash([8, 6]);
        ctx.beginPath();
        ctx.arc(cx, cy, radius, 0, Math.PI * 2);
        ctx.stroke();
        ctx.setLineDash([]);

        ctx.fillStyle = "#9b59b6";
        ctx.beginPath();
        ctx.arc(cx, cy, 6, 0, Math.PI * 2);
        ctx.fill();

        ctx.fillStyle = "white";
        ctx.font = "9px Arial";
        ctx.fillText("#" + z.id + " " + z.name, cx - 4, cy - radius - 4);
    });
}

// -------------------------------------------------------------
// Render (NEU: nur sichtbarer Ausschnitt, wichtig bei großen Maps)
// -------------------------------------------------------------
function render() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Nur die Tiles zeichnen, die aktuell im sichtbaren Bereich liegen
    const startCol = Math.max(0, Math.floor(editorCam.x / tileSize));
    const endCol = Math.min(cols, startCol + Math.ceil(canvas.width / tileSize) + 1);
    const startRow = Math.max(0, Math.floor(editorCam.y / tileSize));
    const endRow = Math.min(rows, startRow + Math.ceil(canvas.height / tileSize) + 1);

    for (let y = startRow; y < endRow; y++) {
        for (let x = startCol; x < endCol; x++) {
            const id = tiles[y][x];
            const tile = tileConfig[id];

            const px = x * tileSize - editorCam.x;
            const py = y * tileSize - editorCam.y;

            const img = tileImageCache[id];
            const rot = (tileRot[y] && tileRot[y][x]) || 0;

            if (img && img.complete && img.naturalWidth > 0) {
                if (rot !== 0) {
                    ctx.save();
                    ctx.translate(px + tileSize / 2, py + tileSize / 2);
                    ctx.rotate(rot * Math.PI / 180);
                    ctx.drawImage(img, -tileSize / 2, -tileSize / 2, tileSize, tileSize);
                    ctx.restore();
                } else {
                    ctx.drawImage(img, px, py, tileSize, tileSize);
                }
            } else {
                ctx.fillStyle = tile ? tile.color : "#000";
                ctx.fillRect(px, py, tileSize, tileSize);
            }

            // kleiner Pfeil zeigt die aktuelle Drehung an (nur wenn gedreht)
            if (rot !== 0) {
                ctx.save();
                ctx.translate(px + tileSize / 2, py + tileSize / 2);
                ctx.rotate(rot * Math.PI / 180);
                ctx.fillStyle = "rgba(255,255,0,0.8)";
                ctx.beginPath();
                ctx.moveTo(0, -tileSize / 2 + 3);
                ctx.lineTo(-3, -tileSize / 2 + 8);
                ctx.lineTo(3, -tileSize / 2 + 8);
                ctx.closePath();
                ctx.fill();
                ctx.restore();
            }

            // PvP-sichere Zone: kleines Schild-Symbol in der Ecke
            if (tile && tile.pvpSafe) {
                ctx.font = "10px Arial";
                ctx.textAlign = "left";
                ctx.fillText("🛡️", px + 1, py + 11);
            }

            ctx.strokeStyle = "#333";
            ctx.strokeRect(px, py, tileSize, tileSize);
        }
    }

    // Spawn
    ctx.fillStyle = "yellow";
    ctx.fillRect(spawn.x - editorCam.x, spawn.y - editorCam.y, tileSize, tileSize);

    // Doors
    ctx.fillStyle = "orange";
    doors.forEach(d => {
        const px = d.x - editorCam.x;
        const py = d.y - editorCam.y;
        if (px < -tileSize || py < -tileSize || px > canvas.width || py > canvas.height) return;
        ctx.fillRect(px, py, tileSize, tileSize);
    });

    // Objects
    if (layerVisibility.object) {
        objects.forEach(o => {
            const cfg = objectConfig[o.type];
            if (!cfg) return;

            const px = o.x - editorCam.x;
            const py = o.y - (cfg.height - tileSize) - editorCam.y;
            if (px < -cfg.width || py < -cfg.height || px > canvas.width || py > canvas.height) return;

            const rot = o.rot || 0;
            ctx.save();
            if (rot !== 0) {
                ctx.translate(px + cfg.width / 2, py + cfg.height / 2);
                ctx.rotate(rot * Math.PI / 180);
                ctx.translate(-cfg.width / 2, -cfg.height / 2);
            } else {
                ctx.translate(px, py);
            }

            ctx.fillStyle = cfg.color;
            ctx.fillRect(0, 0, cfg.width, cfg.height);
            ctx.strokeStyle = "#fff";
            ctx.lineWidth = 1;
            ctx.strokeRect(0, 0, cfg.width, cfg.height);

            // Einbahn-Sperre: roter Balken auf der gesperrten Seite (dreht sich mit)
            if (o.oneWaySide) {
                ctx.fillStyle = "rgba(255,0,0,0.8)";
                const barThickness = 4;
                if (o.oneWaySide === "top") ctx.fillRect(0, 0, cfg.width, barThickness);
                if (o.oneWaySide === "bottom") ctx.fillRect(0, cfg.height - barThickness, cfg.width, barThickness);
                if (o.oneWaySide === "left") ctx.fillRect(0, 0, barThickness, cfg.height);
                if (o.oneWaySide === "right") ctx.fillRect(cfg.width - barThickness, 0, barThickness, cfg.height);
            }

            // Kleiner Pfeil zeigt die Drehung an (nur wenn tatsächlich gedreht)
            if (rot !== 0) {
                ctx.fillStyle = "rgba(255,255,0,0.9)";
                ctx.beginPath();
                ctx.moveTo(cfg.width / 2, 4);
                ctx.lineTo(cfg.width / 2 - 4, 11);
                ctx.lineTo(cfg.width / 2 + 4, 11);
                ctx.closePath();
                ctx.fill();
            }

            ctx.restore();
        });
    }

    // Shops & ATMs & Garagen
    if (layerVisibility.shop) renderShops();
    if (layerVisibility.atm) renderATMs();
    if (layerVisibility.garage) renderGarages();
    if (layerVisibility.jobcenter) renderJobcenters();
    if (layerVisibility.gasstation) renderGasStations();
    if (layerVisibility.repairshop) renderRepairShops();
    if (layerVisibility.house) renderHouses();
    if (layerVisibility.jobpoint) renderJobPoints();
    if (layerVisibility.taxistand) renderTaxiStands();
    if (layerVisibility.hospital) renderHospitals();
    if (layerVisibility.prison) renderPrisons();
    if (layerVisibility.zone) renderTerritoryZones();
    if (layerVisibility.impound) renderImpoundLots();
    if (layerVisibility.firestation) renderFireStations();
    if (layerVisibility.drug_harvest) renderHarvestSpots();
    if (layerVisibility.drug_process) renderProcessSpots();
    if (layerVisibility.drug_dealer) renderDealerSpots();
    if (layerVisibility.clothingshop) renderClothingShops();
    if (layerVisibility.insuranceoffice) renderInsuranceOffices();
    if (layerVisibility.plateoffice) renderPlateOffices();
    if (layerVisibility.trailershop) renderTrailerShops();
}

panLoop();
updateCamLabel();