/**
 * MapSection.js — نقشه هوشمند ثمن
 * Leaflet.js + OpenStreetMap
 * سه لایه: مناطق (polygon) | محلات (polygon) | پارسل‌ها (marker)
 * کلیک → پانل جزئیات | دکمه افزودن → click-to-place
 */
import SectionBase from "../../accounting/SectionBase.js";

/* پالت رنگ بلوک‌ها */
const BLOCK_PALETTE = [
    '#3b82f6','#10b981','#f59e0b','#ef4444',
    '#8b5cf6','#ec4899','#06b6d4','#84cc16',
    '#f97316','#6366f1',
];

/* استخراج کد بلوک از کد نوسازی: "10-2-162-7-0-0-0" → "10-2-162" */
function extractBlock(code) {
    if (!code) return null;
    const parts = code.split('-');
    return parts.length >= 3 ? parts.slice(0,3).join('-') : null;
}

/* رنگ‌بندی وضعیت پارسل */
const STATUS_COLOR = {
    prospect:           '#f59e0b',
    under_review:       '#f97316',
    purchased:          '#3b82f6',
    permitted:          '#8b5cf6',
    under_construction: '#ef4444',
    completed:          '#10b981',
    sold:               '#6b7280',
    archived:           '#d1d5db',
};

const STATUS_LABEL = {
    prospect:           'در کشف',
    under_review:       'در بررسی',
    purchased:          'خریداری‌شده',
    permitted:          'مجوزگرفته',
    under_construction: 'در ساخت',
    completed:          'تکمیل‌شده',
    sold:               'فروخته‌شده',
};

const ISSUE_LABEL = {
    mortgage:'در رهن بانک', court_seizure:'توقیف دادگاه', tax_seizure:'توقیف مالیاتی',
    legal_dispute:'دعوای حقوقی', inheritance_dispute:'اختلاف وراثتی',
    road_plan:'در طرح معبر', national_land:'اراضی ملی', endowment:'وقف',
    utility_debt:'بدهی آب/برق/گاز', municipality_debt:'بدهی شهرداری',
    easement:'حق ارتفاق', other:'سایر',
};

const VIOLATION_LABEL = {
    use_change:'تغییر کاربری', extra_build:'اضافه بنا', no_permit:'بدون مجوز',
    setback_violation:'تجاوز به حریم', floor_excess:'اضافه طبقه', other:'سایر',
};

/* ── کلید preference در سرور برای بلوک‌های انتخابی ── */
const PREF_KEY_BLOCKS = 'gis_selected_blocks';

export default class MapSection extends SectionBase {

    constructor(props = {}) {
        super(props);
        this.gisView       = props.gisView ?? null;
        this._map          = null;
        this._layers       = { districts: null, neighborhoods: null, parcels: null };
        this._mapData      = { districts: [], neighborhoods: [], parcels: [] };
        this._selected     = null;
        this._panelOpen    = false;
        this._addMode      = false;
        this._activeFilter = 'all';
        this._layerVis     = { districts: true, neighborhoods: true, parcels: true };
        // ── انتخاب بلوک ───────────────────────────────────────
        this._blockMode      = false;           // حالت انتخاب بلوک
        this._selectedBlocks = new Map();       // blockCode → { color, layerGroup, parcels }
        this._blockColorIdx  = 0;
        this._activeLayerId  = null;             // فیلتر LayerID فعال
    }

    async template() {
        return `
        <div class="gis-wrap" data-ref="wrap">

            <!-- Toolbar — ردیف اول: همه در یک خط (بدون class قدیمی) -->
            <div data-ref="primaryToolbar"
                 style="display:flex;flex-direction:row;flex-wrap:nowrap;gap:6px;align-items:center;padding:6px 8px;background:#f8fafc;border-radius:8px;overflow-x:auto;white-space:nowrap;">

                <!-- 4 دکمه ناوبری بخش‌های GIS -->
                <div style="display:inline-flex;gap:2px;background:#fff;border:1.5px solid #cbd5e1;border-radius:6px;padding:2px;flex-shrink:0;">
                    <button data-section-nav="map" type="button"
                            style="padding:5px 10px;border:none;background:#3b82f6;color:#fff;border-radius:4px;font-size:12px;font-weight:700;cursor:pointer;">
                        🗺️ نقشه
                    </button>
                    <button data-section-nav="parcels" type="button"
                            style="padding:5px 10px;border:none;background:transparent;color:#475569;border-radius:4px;font-size:12px;font-weight:600;cursor:pointer;">
                        📁 پرونده‌ها
                    </button>
                    <button data-section-nav="layers" type="button"
                            style="padding:5px 10px;border:none;background:transparent;color:#475569;border-radius:4px;font-size:12px;font-weight:600;cursor:pointer;">
                        🏙️ لایه‌ها
                    </button>
                    <button data-section-nav="universal" type="button"
                            style="padding:5px 10px;border:none;background:transparent;color:#475569;border-radius:4px;font-size:12px;font-weight:600;cursor:pointer;">
                        🌐 نقشه عمومی
                    </button>
                </div>

                <!-- جستجوی کد نوسازی -->
                <div style="position:relative;display:inline-flex;align-items:center;flex-shrink:0;">
                    <input type="text" data-ref="codeSearch"
                           placeholder="🔍 کد نوسازی..."
                           dir="ltr"
                           style="padding:6px 30px 6px 8px;border:1.5px solid #cbd5e1;border-radius:6px;font-size:12px;width:170px;text-align:center;background:#fff;">
                    <button data-ref="codeSearchBtn" type="button"
                            style="position:absolute;left:2px;padding:2px 6px;border:none;background:transparent;cursor:pointer;font-size:13px;"
                            title="جستجو">🔍</button>
                    <div data-ref="codeSearchResults" style="display:none;position:absolute;top:36px;right:0;left:0;background:#fff;border:1px solid #cbd5e1;border-radius:8px;max-height:240px;overflow-y:auto;box-shadow:0 4px 12px rgba(0,0,0,.1);z-index:9999;white-space:normal;"></div>
                </div>

                <!-- انتخاب بلوک -->
                <button data-ref="blockModeBtn" type="button"
                        title="کلیک روی پارسل → نمایش همه پارسل‌های آن بلوک"
                        style="padding:6px 12px;font-weight:700;font-size:12px;border:1.5px solid #cbd5e1;border-radius:6px;background:#fff;cursor:pointer;flex-shrink:0;">
                    📦 انتخاب بلوک
                </button>

                <!-- انتخاب لایه -->
                <select data-ref="layerFilter"
                        style="padding:6px 8px;font-size:12px;background:#fff;border:1.5px solid #cbd5e1;border-radius:6px;flex-shrink:0;max-width:160px;"
                        title="فیلتر لایه">
                    <option value="">📚 همه لایه‌ها</option>
                </select>

                <!-- دکمه نمایش/مخفی drawer -->
                <button data-ref="toolsBtn" type="button"
                        style="margin-right:auto;padding:6px 12px;background:#eff6ff;border:1.5px solid #93c5fd;color:#1e40af;font-weight:700;font-size:12px;border-radius:6px;cursor:pointer;flex-shrink:0;"
                        title="نمایش بقیه ابزارها">
                    ⚙️ ابزارها
                </button>
            </div>

            <!-- Toolbar — بقیه ابزارها (آکاردیون قابل باز/بسته) -->
            <div data-ref="toolsPanel" style="display:none;background:#fff;border:1px solid #e2e8f0;border-radius:8px;margin-top:6px;overflow:hidden;">

                <!-- آکاردیون: افزودن و عملیات -->
                <details style="border-bottom:1px solid #f1f5f9;" open>
                    <summary style="padding:10px 14px;cursor:pointer;font-weight:700;font-size:13px;background:#f8fafc;">
                        ➕ افزودن / عملیات پارسل
                    </summary>
                    <div style="padding:10px;display:flex;flex-wrap:wrap;gap:6px;">
                        <button class="gis-btn gis-btn--add" data-ref="addBtn" data-perm="gis.parcels.create">
                            ➕ افزودن پارسل
                        </button>
                        <button class="gis-btn gis-btn--add-mode" data-ref="cancelAddBtn" style="display:none;">
                            ✕ لغو افزودن
                        </button>
                        <span class="gis-add-hint" data-ref="addHint" style="display:none;color:#3b82f6;font-size:12px;padding:6px;">
                            📍 روی نقشه کلیک کنید تا پارسل ثبت شود
                        </span>
                        <button class="gis-btn gis-btn--refresh" data-ref="refreshBtn">🔄 رفرش</button>
                        <button class="gis-btn" data-ref="rebuildBtn"
                                title="بازسازی index بلوک‌ها (بعد از import)" data-perm="gis.parcels.create"
                                style="background:#fef3c7;color:#92400e;">
                            🔧 بازسازی index
                        </button>
                    </div>
                </details>

                <!-- آکاردیون: فیلتر وضعیت -->
                <details style="border-bottom:1px solid #f1f5f9;">
                    <summary style="padding:10px 14px;cursor:pointer;font-weight:700;font-size:13px;background:#f8fafc;">
                        🎨 فیلتر وضعیت پارسل
                    </summary>
                    <div style="padding:10px;display:flex;flex-wrap:wrap;gap:6px;">
                        <button class="gis-filter-btn gis-filter-btn--active" data-filter="all">همه</button>
                        ${Object.entries(STATUS_LABEL).map(([k,v]) =>
                            `<button class="gis-filter-btn" data-filter="${k}"
                                style="--fc:${STATUS_COLOR[k]}">${v}</button>`
                        ).join('')}
                    </div>
                </details>

                <!-- آکاردیون: لایه‌های نقشه -->
                <details style="border-bottom:1px solid #f1f5f9;">
                    <summary style="padding:10px 14px;cursor:pointer;font-weight:700;font-size:13px;background:#f8fafc;">
                        🏙️ لایه‌های نمایش
                    </summary>
                    <div style="padding:10px;display:flex;flex-wrap:wrap;gap:14px;">
                        <label class="gis-layer-toggle"><input type="checkbox" data-layer="districts" checked> مناطق</label>
                        <label class="gis-layer-toggle"><input type="checkbox" data-layer="neighborhoods" checked> محلات</label>
                        <label class="gis-layer-toggle"><input type="checkbox" data-layer="parcels" checked> پارسل‌ها</label>
                    </div>
                </details>

                <!-- آکاردیون: نوع نقشه پایه -->
                <details style="border-bottom:1px solid #f1f5f9;">
                    <summary style="padding:10px 14px;cursor:pointer;font-weight:700;font-size:13px;background:#f8fafc;">
                        🗺️ نوع نقشه پایه
                    </summary>
                    <div style="padding:10px;display:flex;flex-wrap:wrap;gap:6px;">
                        <button class="gis-tile-btn gis-tile-btn--active" data-ref="tileEsri">🗺 Esri</button>
                        <button class="gis-tile-btn" data-ref="tileVoyager">🎨 Voyager</button>
                        <button class="gis-tile-btn" data-ref="tileCarto">⬜ Carto</button>
                    </div>
                </details>

                <!-- آکاردیون: آفلاین -->
                <details>
                    <summary style="padding:10px 14px;cursor:pointer;font-weight:700;font-size:13px;background:#f8fafc;">
                        📥 نقشه آفلاین
                    </summary>
                    <div style="padding:10px;">
                        <button class="gis-btn" data-ref="offlineBtn"
                                style="background:#f0fdf4;border:1.5px solid #86efac;color:#166534;">
                            📥 دانلود کاشی‌های آفلاین
                        </button>
                    </div>
                </details>
            </div>

            <!-- نوار بلوک‌های انتخابی -->
            <div class="gis-block-bar" data-ref="blockBar" style="display:none;">
                <span style="font-size:11px;color:#64748b;white-space:nowrap;">📦 بلوک‌ها:</span>
                <div class="gis-block-chips" data-ref="blockChips"></div>
                <button class="gis-btn" data-ref="clearBlocksBtn"
                    style="font-size:11px;padding:3px 10px;margin-right:auto;color:#ef4444;border-color:#fca5a5;">
                    🗑 پاک کردن همه
                </button>
            </div>

            <!-- Body: نقشه + پانل جزئیات -->
            <div class="gis-body" data-ref="body">
                <div class="gis-map-container" data-ref="mapContainer">
                    <div id="gis-leaflet-map" data-ref="mapEl"></div>
                    <div class="gis-map-loading" data-ref="mapLoading">
                        <div class="acc-spinner"></div> در حال بارگذاری نقشه...
                    </div>
                </div>
                <div class="gis-detail-panel" data-ref="detailPanel">
                    <div class="gis-detail-panel__inner" data-ref="panelInner"></div>
                </div>
            </div>

            <!-- نوار وضعیت پایین -->
            <div class="gis-statusbar">
                <span data-ref="coordsLbl">📍 مختصات: —</span>
                <span data-ref="countLbl"></span>
            </div>
        </div>`;
    }

    async afterRender() {
        this._bindToolbar();
        await this._loadLeaflet();
        this._initMap();
        await this._loadMapData();
        await this._restoreSelectedBlocks();
        await this._focusPendingBlock();   // اگر از داشبورد املاک بلوکی ارسال شده
    }

    /* ── باز کردن بلوکِ ارسالی از داشبورد املاک + رنگ‌آمیزی دو-رنگه ── */
    async _focusPendingBlock() {
        let payload;
        try {
            const raw = sessionStorage.getItem('acc_gis_focus_block');
            if (!raw) return;
            sessionStorage.removeItem('acc_gis_focus_block');
            payload = JSON.parse(raw);
        } catch { return; }
        if (!payload?.block) return;

        const f = payload.filters || {};
        const params = { block: payload.block };
        if (f.layer_id)            params.layer_id = f.layer_id;
        if (f.land_use)            params.land_use = f.land_use;
        if (f.area_min != null)    params.area_min = f.area_min;
        if (f.area_max != null)    params.area_max = f.area_max;
        if (f.statuses?.length)    params.statuses = f.statuses.join(',');
        if (f.def_building >= 0)   params.def_building = f.def_building;
        if (f.def_units    >= 0)   params.def_units    = f.def_units;
        if (f.def_shops    >= 0)   params.def_shops    = f.def_shops;

        // layer را با toolbar هماهنگ نگه دار
        this._activeLayerId = f.layer_id || this._activeLayerId;

        try {
            const res = await this.api.get('/gis/block-parcels', params);
            this._renderFilteredBlock(payload.block, res?.data ?? [], !!res?.filtered);
        } catch {
            this._toast('❌ خطا در بارگذاری بلوک', '#ef4444');
        }
    }

    /* رندر بلوک با دو رنگ: مطابق فیلتر = برجسته (قرمز)، بقیه = کم‌رنگ */
    _renderFilteredBlock(blockCode, parcels, filtered) {
        const L = window.L;
        if (!L || !this._map) return;

        // اگر قبلاً نمایش داده شده، اول حذف تا دوباره رنگ شود
        if (this._selectedBlocks.has(blockCode)) this._removeBlock(blockCode);

        const MATCH = '#ef4444';   // برجسته
        const MUTE  = '#94a3b8';   // زمینه‌ی کم‌رنگ
        const PLAIN = '#3b82f6';   // وقتی فیلتری اعمال نشده

        const layerGroup = L.layerGroup().addTo(this._map);
        this._selectedBlocks.set(blockCode, { color: filtered ? MATCH : PLAIN, layerGroup, parcels });

        let matchCount = 0;
        parcels.forEach(p => {
            if (!p.lat || !p.lng) return;
            const isMatch = parseInt(p.is_match) === 1;
            if (isMatch) matchCount++;

            const hot   = filtered && isMatch;
            const color = !filtered ? PLAIN : (isMatch ? MATCH : MUTE);
            const op    = !filtered ? 0.85  : (isMatch ? 0.95 : 0.30);

            if (p.geometry) {
                try {
                    const geo = typeof p.geometry === 'string' ? JSON.parse(p.geometry) : p.geometry;
                    L.geoJSON(geo, {
                        style: { color, weight: hot ? 2.5 : 1, fillColor: color, fillOpacity: op * 0.3 }
                    }).addTo(layerGroup);
                } catch {}
            }

            const m = L.circleMarker([parseFloat(p.lat), parseFloat(p.lng)], {
                radius: hot ? 9 : 6, fillColor: color, color: '#fff',
                weight: hot ? 2.5 : 1.5, fillOpacity: op,
            });
            m.bindTooltip(
                `<b>${p.code || '—'}</b><br>بلوک: ${blockCode}` +
                (filtered ? (isMatch ? '<br>✅ مطابق فیلتر' : '<br>— خارج از فیلتر') : ''),
                { direction: 'top', offset: [0, -8] }
            );
            m.on('click', () => this._openParcelPanel(p));
            m.addTo(layerGroup);
        });

        this._updateBlockBar();
        this._saveSelectedBlocks();

        // zoom به محدوده بلوک
        const lats = parcels.map(p => parseFloat(p.lat)).filter(v => !isNaN(v));
        const lngs = parcels.map(p => parseFloat(p.lng)).filter(v => !isNaN(v));
        if (lats.length) {
            this._map.fitBounds(
                L.latLngBounds([Math.min(...lats), Math.min(...lngs)],
                               [Math.max(...lats), Math.max(...lngs)]),
                { padding: [40, 40], maxZoom: 18 }
            );
        }

        this._toast(
            filtered ? `✅ بلوک ${blockCode}: ${matchCount} مطابق از ${parcels.length}` : `📦 بلوک ${blockCode}: ${parcels.length} پارسل`,
            filtered ? MATCH : PLAIN
        );
    }

    /* ── بازیابی بلوک‌های انتخابی از سرور ────────────────────── */
    async _restoreSelectedBlocks() {
        try {
            const res = await this.api.get(`/user/prefs/${PREF_KEY_BLOCKS}`);
            const codes = Array.isArray(res?.data) ? res.data : [];
            if (!codes.length) return;

            this._toast(`🔄 بازیابی ${codes.length} بلوک قبلی...`, '#6366f1');
            for (const code of codes) {
                try {
                    const params = { block: code, per_page: 500 };
                    if (this._activeLayerId) params.layer_id = this._activeLayerId;
                    const r = await this.api.get('/gis/parcels', params);
                    const parcels = r?.data ?? [];
                    if (parcels.length) {
                        this._renderBlockData(code, parcels, /* skipSave */ true);
                    }
                } catch { /* skip invalid block */ }
            }
        } catch { /* user has no saved blocks yet */ }
    }

    /* ── ذخیره لیست بلوک‌های انتخابی روی سرور ────────────────── */
    async _saveSelectedBlocks() {
        try {
            const codes = [...this._selectedBlocks.keys()];
            await this.api.put(`/user/prefs/${PREF_KEY_BLOCKS}`, { value: codes });
        } catch (e) {
            console.warn('saveSelectedBlocks failed', e);
        }
    }

    /* ── بارگذاری Leaflet (local-first, بدون CDN) ────────────── */
    async _loadLeaflet() {
        // اگر WordPress قبلاً لود کرده (wp_enqueue_script)
        if (window.L) return;

        const addStyle = href => {
            if (document.querySelector(`link[href*="leaflet"]`)) return;
            const l = document.createElement('link');
            l.rel = 'stylesheet'; l.href = href;
            document.head.appendChild(l);
        };
        const addScript = src => new Promise((res, rej) => {
            const s = document.createElement('script');
            s.src = src; s.onload = res; s.onerror = rej;
            document.head.appendChild(s);
        });

        // مسیر local از ACC_CONFIG.pluginUrl یا auto-detect
        const base = (window.ACC_CONFIG?.pluginUrl ?? '')
            .replace(/\/+$/, '');
        const localBase = base
            ? `${base}/assets/vendor/leaflet`
            : '/wp-content/plugins/acc-engine/assets/vendor/leaflet';

        addStyle(`${localBase}/leaflet.css`);
        await addScript(`${localBase}/leaflet.js`);
    }

    /* ── راه‌اندازی نقشه ──────────────────────────────────────── */
    _initMap() {
        const L = window.L;
        const el = this.ref('mapEl');
        if (!el || !L) return;

        this.ref('mapLoading').style.display = 'none';

        // شیراز، استان فارس
        this._map = L.map(el, { zoomControl: true, attributionControl: true, maxZoom: 19 })
                     .setView([29.5926, 52.5836], 13);

        // کاشی‌های local — کاملاً آفلاین
        const pluginUrl = (window.ACC_CONFIG?.pluginUrl ?? '')
            .replace(/\/+$/, '');
        const base = pluginUrl || '/wp-content/plugins/acc-engine';

        const blank = `${base}/assets/vendor/leaflet/tiles/blank.png`;
        this._tileLayers = {
            esri:  L.tileLayer(`${base}/assets/vendor/leaflet/tiles_esri/{z}/{x}/{y}.png`, {
                attribution: '© Esri',
                minZoom: 10, maxZoom: 19, maxNativeZoom: 16,
                errorTileUrl: blank,
            }),
            voyager: L.tileLayer(`${base}/assets/vendor/leaflet/tiles_osm/{z}/{x}/{y}.png`, {
                attribution: '© CartoDB Voyager',
                minZoom: 10, maxZoom: 19, maxNativeZoom: 16,
                errorTileUrl: blank,
            }),
            carto: L.tileLayer(`${base}/assets/vendor/leaflet/tiles/{z}/{x}/{y}.png`, {
                attribution: '© CartoDB',
                minZoom: 10, maxZoom: 19, maxNativeZoom: 16,
                errorTileUrl: blank,
            }),
        };

        // پیش‌فرض: Esri Street
        this._activeTileKey = 'esri';
        this._tileLayers.esri.addTo(this._map);

        // لایه‌گروه‌ها
        this._layers.districts     = L.layerGroup().addTo(this._map);
        this._layers.neighborhoods = L.layerGroup().addTo(this._map);
        this._layers.parcels       = L.layerGroup().addTo(this._map);

        // نمایش مختصات در نوار پایین
        this._map.on('mousemove', e => {
            const lbl = this.ref('coordsLbl');
            if (lbl) lbl.textContent = `📍 ${e.latlng.lat.toFixed(5)} , ${e.latlng.lng.toFixed(5)}`;
        });

        // کلیک روی نقشه
        this._map.on('click', e => {
            if (this._addMode) {
                this._openAddParcelModal(e.latlng.lat, e.latlng.lng);
            } else if (this._blockMode) {
                this._loadBlockByClick(e.latlng.lat, e.latlng.lng);
            }
        });
    }

    /* ── بارگذاری داده نقشه ──────────────────────────────────── */
    async _loadMapData() {
        try {
            const res = await this.api.get('/gis/map-data');
            this._mapData = res ?? { districts: [], neighborhoods: [], parcels: [] };
            this._renderAll();
            this._updateCountLabel();
        } catch {
            this._toast('خطا در بارگذاری نقشه', '#ef4444');
        }
    }

    _renderAll() {
        this._renderDistricts();
        this._renderNeighborhoods();
        this._renderParcels();
    }

    /* ── رندر مناطق ──────────────────────────────────────────── */
    _renderDistricts() {
        const L = window.L;
        if (!L || !this._layers.districts) return;
        this._layers.districts.clearLayers();

        this._mapData.districts.forEach(d => {
            if (d.geometry) {
                try {
                    const geo = typeof d.geometry === 'string' ? JSON.parse(d.geometry) : d.geometry;
                    L.geoJSON(geo, {
                        style: { color: d.color || '#3b82f6', weight: 2.5, fillOpacity: 0.06, fillColor: d.color || '#3b82f6' },
                    }).bindTooltip(`<b>${d.name}</b>${d.assigned_user_name ? '<br>'+d.assigned_user_name : ''}`, { sticky: true })
                    .addTo(this._layers.districts);
                } catch(e) { /* invalid geojson */ }
            }
        });
    }

    /* ── رندر محلات ──────────────────────────────────────────── */
    _renderNeighborhoods() {
        const L = window.L;
        if (!L || !this._layers.neighborhoods) return;
        this._layers.neighborhoods.clearLayers();

        this._mapData.neighborhoods.forEach(n => {
            if (n.geometry) {
                try {
                    const geo = typeof n.geometry === 'string' ? JSON.parse(n.geometry) : n.geometry;
                    const clr = n.development_trend === 'growing' ? '#10b981'
                              : n.development_trend === 'declining' ? '#ef4444' : '#6b7280';
                    L.geoJSON(geo, {
                        style: { color: clr, weight: 1.5, fillOpacity: 0.04, dashArray: '4 4' },
                    }).bindTooltip(`<b>${n.name}</b>${n.assigned_user_name ? '<br>'+n.assigned_user_name : ''}`, { sticky: true })
                    .addTo(this._layers.neighborhoods);
                } catch(e) { /* invalid */ }
            }
        });
    }

    /* ── رندر پارسل‌ها ───────────────────────────────────────── */
    _renderParcels() {
        const L = window.L;
        if (!L || !this._layers.parcels) return;
        this._layers.parcels.clearLayers();

        const filtered = this._activeFilter === 'all'
            ? this._mapData.parcels
            : this._mapData.parcels.filter(p => p.status === this._activeFilter);

        filtered.forEach(p => {
            if (!p.lat || !p.lng) return;

            const color  = STATUS_COLOR[p.status] || '#94a3b8';
            const hasCritical = parseInt(p.critical_issues) > 0;

            const marker = L.circleMarker([parseFloat(p.lat), parseFloat(p.lng)], {
                radius:      hasCritical ? 10 : 8,
                fillColor:   color,
                color:       hasCritical ? '#dc2626' : '#fff',
                weight:      hasCritical ? 3 : 1.5,
                opacity:     1,
                fillOpacity: 0.85,
            });

            marker.bindTooltip(this._parcelTooltip(p), { direction: 'top', offset: [0, -8] });
            marker.on('click', () => {
                if (this._blockMode) {
                    this._selectBlock(extractBlock(p.code), p);
                } else {
                    this._openParcelPanel(p);
                }
            });

            // رنگ خاص برای پارسل قفل‌شده
            if (p.locked_by_name) {
                marker.setStyle({ dashArray: '4 4', color: '#f59e0b', weight: 2.5 });
            }

            marker.addTo(this._layers.parcels);
        });

        this._updateCountLabel();
    }

    _parcelTooltip(p) {
        const issues = parseInt(p.total_issues) || 0;
        const critical = parseInt(p.critical_issues) || 0;
        return `
            <div style="min-width:160px;font-family:inherit;direction:rtl;">
                <div style="font-weight:700;font-size:13px;color:#1e293b;margin-bottom:4px;">
                    ${p.code ? `پلاک ${p.code}` : 'پارسل #' + p.id}
                </div>
                ${p.district_name ? `<div style="font-size:11px;color:#64748b;">${p.district_name} — ${p.neighborhood_name||''}</div>` : ''}
                <div style="margin-top:4px;">
                    <span style="background:${STATUS_COLOR[p.status]};color:#fff;border-radius:5px;padding:1px 7px;font-size:11px;font-weight:600;">
                        ${STATUS_LABEL[p.status] || p.status}
                    </span>
                </div>
                ${critical > 0 ? `<div style="color:#dc2626;font-size:11px;margin-top:3px;">⚠️ ${critical} مشکل بحرانی</div>` : ''}
                ${p.locked_by_name ? `<div style="color:#d97706;font-size:11px;margin-top:2px;">🔒 در دست ${p.locked_by_name}</div>` : ''}
            </div>`;
    }

    /* ── پانل جزئیات پارسل (راست) ───────────────────────────── */
    async _openParcelPanel(pSummary) {
        this._selected = { type: 'parcel', data: pSummary };
        this._showPanelLoading();

        try {
            const res = await this.api.get(`/gis/parcels/${pSummary.id}`);
            const p   = res?.data;
            if (!p) return;
            this._selected.data = p;
            this._renderParcelPanel(p);
        } catch {
            this._toast('خطا در بارگذاری پرونده', '#ef4444');
        }
    }

    _showPanelLoading() {
        const panel = this.ref('detailPanel');
        const inner = this.ref('panelInner');
        if (!this._panelOpen) {
            panel.classList.add('gis-detail-panel--open');
            this._panelOpen = true;
            setTimeout(() => this._map?.invalidateSize(), 320);
        }
        inner.innerHTML = `<div class="gis-panel-loading"><div class="acc-spinner"></div></div>`;
    }

    _closePanel() {
        this.ref('detailPanel').classList.remove('gis-detail-panel--open');
        this._panelOpen = false;
        this._selected  = null;
        setTimeout(() => this._map?.invalidateSize(), 320);
    }

    _renderParcelPanel(p) {
        const score = p.score || { score: 0, level: 'risky', warnings: [] };
        const scoreColor = { good: '#10b981', moderate: '#f59e0b', risky: '#ef4444' }[score.level] || '#6b7280';
        const land = p.land || {};
        const bld  = p.building || {};
        const use  = p.use || {};
        const issues = p.issues || [];
        const comms  = p.commissions || [];
        const owners = p.owners || [];
        const hist   = p.history || [];

        const activeIssues   = issues.filter(i => i.status === 'active');
        const criticalCount  = activeIssues.filter(i => i.severity === 'critical').length;
        const warrantyCount  = activeIssues.filter(i => i.severity === 'warning').length;

        this.ref('panelInner').innerHTML = `
            <!-- هدر پانل -->
            <div class="gis-panel-header">
                <div class="gis-panel-header__info">
                    <div class="gis-panel-title">
                        ${p.code ? `پلاک ${this.escape(p.code)}/${this.escape(p.sub_code||'')}` : `پارسل #${p.id}`}
                    </div>
                    <div class="gis-panel-sub">
                        ${p.district_name||''} ${p.neighborhood_name ? '← '+p.neighborhood_name : ''}
                    </div>
                </div>
                <div style="display:flex;gap:6px;align-items:center;">
                    <div class="gis-score-badge" style="background:${scoreColor}">
                        ${score.score}<span style="font-size:10px;">/۱۰۰</span>
                    </div>
                    <button class="gis-panel-close" data-ref="panelCloseBtn">✕</button>
                </div>
            </div>

            <!-- وضعیت -->
            <div class="gis-panel-status-row">
                <span class="gis-status-dot" style="background:${STATUS_COLOR[p.status]||'#94a3b8'}"></span>
                <span style="font-weight:700;font-size:13px;">${STATUS_LABEL[p.status]||p.status}</span>
                ${p.locked_by_name ? `<span class="gis-lock-badge">🔒 ${this.escape(p.locked_by_name)}</span>` : ''}
                ${criticalCount > 0 ? `<span class="gis-issue-badge gis-issue-badge--critical">⚠️ ${criticalCount} بحرانی</span>` : ''}
                ${warrantyCount > 0 ? `<span class="gis-issue-badge gis-issue-badge--warning">⚡ ${warrantyCount} هشدار</span>` : ''}
            </div>

            <!-- تب‌ها -->
            <div class="gis-panel-tabs" data-ref="panelTabs">
                <button class="gis-panel-tab gis-panel-tab--active" data-tab="land">📍 زمین</button>
                <button class="gis-panel-tab" data-tab="building">🏛️ ساختمان</button>
                <button class="gis-panel-tab" data-tab="ownership">👤 مالکیت</button>
                <button class="gis-panel-tab" data-tab="use">🏷️ کاربری</button>
                <button class="gis-panel-tab" data-tab="issues">⚠️ مشکلات${criticalCount+warrantyCount > 0 ? ` (${criticalCount+warrantyCount})` : ''}</button>
                <button class="gis-panel-tab" data-tab="score">📊 کارنامه</button>
            </div>

            <!-- محتوای تب‌ها -->
            <div class="gis-panel-body" data-ref="panelBody">
                ${this._renderTabLand(land, p)}
            </div>

            <!-- اکشن‌ها -->
            <div class="gis-panel-actions">
                <button class="gis-btn gis-btn--primary" data-ref="editParcelBtn">✏️ ویرایش</button>
                <button class="gis-btn gis-btn--secondary" data-ref="lockBtn">
                    ${p.locked_by_name ? '🔓 آزاد کردن' : '🔒 رزرو'}
                </button>
                <button class="gis-btn" data-ref="commissionBtn" style="background:#fef3c7;color:#92400e;border:1.5px solid #fcd34d;">
                    🔨 کمیسیون ۱۰۰
                </button>
                <button class="gis-btn gis-btn--success" data-ref="createProjectBtn">🏗️ ایجاد پروژه</button>
                ${this.can('melk.cases.create') ? `<button class="gis-btn" data-ref="melkCaseBtn" style="background:#312e81;color:#fff;border:none;">🏛️ پرونده ملک</button>` : ''}
            </div>
        `;

        // bind refs داخل پانل
        this.ref('panelInner').querySelectorAll('[data-ref]').forEach(el => {
            this.refs[el.dataset.ref] = el;
        });

        // بستن پانل
        this.on(this.ref('panelCloseBtn'), 'click', () => this._closePanel());

        // تب‌ها
        this.ref('panelTabs').querySelectorAll('.gis-panel-tab').forEach(btn => {
            btn.addEventListener('click', () => {
                this.ref('panelTabs').querySelectorAll('.gis-panel-tab')
                    .forEach(b => b.classList.remove('gis-panel-tab--active'));
                btn.classList.add('gis-panel-tab--active');
                this.ref('panelBody').innerHTML = this._renderTabContent(btn.dataset.tab, p);
                this._bindTabActions(btn.dataset.tab, p);
            });
        });

        // دکمه ویرایش
        this.on(this.ref('editParcelBtn'), 'click', () => this._openEditParcelModal(p));

        // دکمه قفل
        this.on(this.ref('lockBtn'), 'click', () => this._toggleLock(p));

        // دکمه ایجاد پروژه CPM
        this.on(this.ref('createProjectBtn'), 'click', () => this._openCreateProjectModal(p));

        if (this.ref('melkCaseBtn')) {
            this.on(this.ref('melkCaseBtn'), 'click', () => {
                const base = '/acc-engine/';
                sessionStorage.setItem('acc_melk_create_parcel', JSON.stringify({
                    parcel_id: p.id, code: p.code,
                    district_id: p.district_id, neighborhood_id: p.neighborhood_id, block_code: p.block_code,
                }));
                window.location.href = base + 'melk.php';
            });
        }

        // دکمه کمیسیون ماده ۱۰۰
        this.on(this.ref('commissionBtn'), 'click', () => {
            const code = p.code;
            if (!code) { this._toast('این پارسل کد نوسازی ندارد', '#f59e0b'); return; }
            // ذخیره کد در sessionStorage تا تب commission آن را بخواند
            sessionStorage.setItem('acc_commission_pending_code', code);
            this.eventBus?.emit('tab:open', { key: 'commission', params: { code } });
        });

        // bind اکشن‌های تب اولیه (زمین)
        this._bindTabActions('land', p);
    }

    _renderTabContent(tab, p) {
        switch(tab) {
            case 'land':      return this._renderTabLand(p.land||{}, p);
            case 'building':  return this._renderTabBuilding(p.building||{});
            case 'ownership': return this._renderTabOwnership(p.owners||[], p.history||[]);
            case 'use':       return this._renderTabUse(p.use||{}, p);
            case 'issues':    return this._renderTabIssues(p.issues||[], p.commissions||[]);
            case 'score':     return this._renderTabScore(p.score||{});
            default:          return '';
        }
    }

    _bindTabActions(tab, p) {
        if (tab === 'land') {
            this.ref('panelBody').querySelector('[data-action="edit-land"]')
                ?.addEventListener('click', () => this._openLandModal(p.id, p.land || {}));
        }
        if (tab === 'building') {
            this.ref('panelBody').querySelector('[data-action="edit-building"]')
                ?.addEventListener('click', () => this._openBuildingModal(p.id, p.building || {}));
        }
        if (tab === 'use') {
            this.ref('panelBody').querySelector('[data-action="edit-use"]')
                ?.addEventListener('click', () => this._openUseModal(p.id, p.use || {}));
        }
        if (tab === 'ownership') {
            this.ref('panelBody').querySelector('[data-action="add-owner"]')
                ?.addEventListener('click', () => this._openOwnerModal(p.id));
            this.ref('panelBody').querySelector('[data-action="add-history"]')
                ?.addEventListener('click', () => this._openHistoryModal(p.id));
            // ویرایش مالک
            this.ref('panelBody').querySelectorAll('[data-edit-owner]').forEach(btn => {
                const owner = (p.owners||[]).find(o => String(o.id) === btn.dataset.editOwner);
                if (owner) btn.addEventListener('click', () => this._openOwnerModal(p.id, owner));
            });
            // حذف مالک
            this.ref('panelBody').querySelectorAll('[data-del-owner]').forEach(btn => {
                btn.addEventListener('click', async () => {
                    if (!confirm('آیا از حذف این مالک مطمئن هستید؟')) return;
                    try {
                        await this.api.delete(`/gis/parcels/${p.id}/owners/${btn.dataset.delOwner}`);
                        this._toast('🗑️ مالک حذف شد');
                        this._openParcelPanel({ id: p.id });
                    } catch(err) { alert('خطا: '+(err?.message||'')); }
                });
            });
            // حذف تاریخچه
            this.ref('panelBody').querySelectorAll('[data-del-history]').forEach(btn => {
                btn.addEventListener('click', async () => {
                    if (!confirm('حذف این آیتم تاریخچه؟')) return;
                    try {
                        await this.api.delete(`/gis/parcels/${p.id}/history/${btn.dataset.delHistory}`);
                        this._toast('🗑️ تاریخچه حذف شد');
                        this._openParcelPanel({ id: p.id });
                    } catch(err) { alert('خطا: '+(err?.message||'')); }
                });
            });
        }
        if (tab === 'issues') {
            this.ref('panelBody').querySelector('[data-action="add-issue"]')
                ?.addEventListener('click', () => this._openIssueModal(p.id, p));
            // حذف مشکل
            this.ref('panelBody').querySelectorAll('[data-del-issue]').forEach(btn => {
                btn.addEventListener('click', async () => {
                    if (!confirm('حذف این مشکل؟')) return;
                    try {
                        await this.api.delete(`/gis/parcels/${p.id}/issues/${btn.dataset.delIssue}`);
                        this._toast('🗑️ مشکل حذف شد');
                        this._openParcelPanel({ id: p.id });
                    } catch(err) { alert('خطا: '+(err?.message||'')); }
                });
            });
            // حل مشکل (resolve)
            this.ref('panelBody').querySelectorAll('[data-resolve-issue]').forEach(btn => {
                btn.addEventListener('click', async () => {
                    try {
                        await this.api.put(`/gis/parcels/${p.id}/issues/${btn.dataset.resolveIssue}`, {
                            status: 'resolved',
                            resolved_at: new Date().toISOString().split('T')[0],
                        });
                        this._toast('✅ مشکل به‌عنوان حل‌شده ثبت شد', '#10b981');
                        this._openParcelPanel({ id: p.id });
                    } catch(err) { alert('خطا: '+(err?.message||'')); }
                });
            });
            // نمایش/پنهان رفع‌شده‌ها
            this.ref('panelBody').querySelector('[data-action="toggle-resolved"]')?.addEventListener('click', ev => {
                const showing = ev.currentTarget.dataset.showing === '1';
                this.ref('panelBody').querySelectorAll('.gis-issue-resolved').forEach(el => {
                    el.style.display = showing ? 'none' : '';
                });
                ev.currentTarget.dataset.showing = showing ? '0' : '1';
                ev.currentTarget.textContent = showing
                    ? `👁️ رفع‌شده‌ها (${this.ref('panelBody').querySelectorAll('.gis-issue-resolved').length})`
                    : '🙈 پنهان کردن رفع‌شده‌ها';
            });
            // افزودن کمیسیون
            this.ref('panelBody').querySelector('[data-action="add-commission"]')
                ?.addEventListener('click', () => this._openCommissionModal(p.id));
            // ویرایش کمیسیون
            this.ref('panelBody').querySelectorAll('[data-edit-commission]').forEach(btn => {
                const comm = (p.commissions||[]).find(c => String(c.id) === btn.dataset.editCommission);
                if (comm) btn.addEventListener('click', () => this._openCommissionModal(p.id, comm));
            });
            // حذف کمیسیون
            this.ref('panelBody').querySelectorAll('[data-del-commission]').forEach(btn => {
                btn.addEventListener('click', async () => {
                    if (!confirm('حذف این کمیسیون ماده ۱۰۰؟')) return;
                    try {
                        await this.api.delete(`/gis/parcels/${p.id}/commissions/${btn.dataset.delCommission}`);
                        this._toast('🗑️ کمیسیون حذف شد');
                        this._openParcelPanel({ id: p.id });
                    } catch(err) { alert('خطا: '+(err?.message||'')); }
                });
            });
        }
    }

    /* ── محتوای تب زمین ──────────────────────────────────────── */
    _renderTabLand(l, p) {
        const row = (label, value) => value != null && value !== ''
            ? `<div class="gis-info-row"><span class="gis-info-label">${label}</span><span class="gis-info-value">${value}</span></div>` : '';

        const shapeLabel = {rectangular:'مستطیل',square:'مربع',corner:'گوشه‌ای',irregular:'نامنظم',triangular:'مثلثی'};
        const posLabel   = {middle:'میانی', corner:'گوشه', end:'انتهایی'};
        const ownLabel   = {private:'ملکی', endowment:'وقفی', government:'دولتی', national:'اراضی ملی'};

        const allowedFloors = l.main_street_width
            ? (l.main_street_width < 6 ? '۲ طبقه' : l.main_street_width < 12 ? '۵ طبقه' : l.main_street_width < 24 ? '۷ طبقه' : '۱۰+ طبقه')
            : '—';

        return `
        <div class="gis-tab-content">
            ${row('مساحت', l.area_sqm ? `${this._fmt(l.area_sqm)} م²` : null)}
            ${row('شکل زمین', shapeLabel[l.shape])}
            ${row('موقعیت', posLabel[l.position])}
            ${row('نوع مالکیت زمین', ownLabel[l.ownership_type])}
            ${l.is_national_land ? `<div class="gis-alert-row gis-alert-row--critical">🔴 اراضی ملی</div>` : ''}
            <div class="gis-info-divider">معابر مجاور</div>
            ${row('معبر اصلی', l.main_street_width ? `${l.main_street_width} متر — ${l.main_street_dir||''}` : null)}
            ${row('معبر فرعی', l.second_street_width ? `${l.second_street_width} متر — ${l.second_street_dir||''}` : null)}
            ${row('طبقات مجاز (تخمین)', allowedFloors)}
            <div class="gis-info-divider">ابعاد</div>
            ${row('بر شمالی', l.north_dim ? l.north_dim+' م' : null)}
            ${row('بر جنوبی', l.south_dim ? l.south_dim+' م' : null)}
            ${row('عمق شرقی', l.east_dim  ? l.east_dim +' م' : null)}
            ${row('عمق غربی', l.west_dim  ? l.west_dim +' م' : null)}
            ${p.address ? `<div class="gis-info-divider">آدرس</div><div style="font-size:12px;color:#475569;padding:8px 0;">${this.escape(p.address)}</div>` : ''}
            <div style="margin-top:12px;">
                <button class="gis-btn gis-btn--secondary gis-btn--sm" data-action="edit-land">✏️ ویرایش اطلاعات زمین</button>
            </div>
        </div>`;
    }

    /* ── محتوای تب ساختمان ───────────────────────────────────── */
    _renderTabBuilding(b) {
        if (!b || !b.has_building) {
            return `<div class="gis-empty-tab">🏗️ اطلاعات ساختمان ثبت نشده است.
                <br><button class="gis-btn gis-btn--secondary gis-btn--sm" style="margin-top:12px;" data-action="edit-building">+ ثبت اطلاعات ساختمان</button></div>`;
        }
        const row = (l,v) => v!=null && v!=='' ? `<div class="gis-info-row"><span class="gis-info-label">${l}</span><span class="gis-info-value">${v}</span></div>` : '';
        const age = b.built_year ? (new Date().getFullYear() - b.built_year) + ' سال' : null;
        const struLabel = {concrete:'بتن‌آرمه', steel:'فلزی', masonry:'آجری', other:'سایر'};
        const yn = v => v ? '✅' : '❌';

        return `
        <div class="gis-tab-content">
            ${row('تعداد طبقات', b.floors)}
            ${row('تعداد واحدها', b.units)}
            ${row('مساحت کل بنا', b.total_area_sqm ? this._fmt(b.total_area_sqm)+' م²' : null)}
            ${row('سال ساخت', b.built_year)} ${row('عمر بنا', age)}
            ${row('نوع اسکلت', struLabel[b.structure_type])}
            ${row('نما', b.facade)}
            <div class="gis-info-divider">مدارک</div>
            ${row('پروانه ساخت', b.has_permit==='yes'?'✅ دارد':b.has_permit==='no'?'❌ ندارد':'⚠️ نامعلوم')}
            ${b.permit_number ? row('شماره پروانه', b.permit_number) : ''}
            ${row('پایان کار', b.has_completion==='yes'?'✅ دارد':b.has_completion==='no'?'❌ ندارد':'⚠️ ناقص')}
            <div class="gis-info-divider">امکانات</div>
            <div class="gis-amenities-grid">
                <span>${yn(b.has_water)} آب</span><span>${yn(b.has_electricity)} برق</span>
                <span>${yn(b.has_gas)} گاز</span><span>${yn(b.has_elevator)} آسانسور</span>
                <span>${yn(b.has_parking)} پارکینگ</span><span>${yn(b.has_storage)} انباری</span>
                ${b.has_basement ? '<span>✅ زیرزمین</span>' : ''}
            </div>
        </div>`;
    }

    /* ── محتوای تب مالکیت ────────────────────────────────────── */
    _renderTabOwnership(owners, history) {
        const deedLabel = {single_page:'تک‌برگ', old:'منگوله‌دار', qolnameh:'قولنامه‌ای', other:'سایر'};
        const histLabel = {sale:'خرید و فروش', inheritance:'ارث', gift:'هبه', auction:'مزایده', government:'تملک دولتی', endowment:'وقف', other:'سایر'};

        const ownersHtml = owners.length ? owners.map(o => `
            <div class="gis-owner-card ${o.is_primary=='1'?'gis-owner-card--primary':''}">
                <div class="gis-owner-name">${this.escape(o.name)} ${o.is_primary=='1'?'<span class="gis-badge">اصلی</span>':''}</div>
                <div class="gis-owner-meta">
                    ${deedLabel[o.deed_type]||o.deed_type}
                    ${o.deed_number ? ' — سند '+o.deed_number : ''}
                    ${o.ownership_share ? ' — '+o.ownership_share : ''}
                </div>
                ${o.phone ? `<div class="gis-owner-meta">📞 ${this.escape(o.phone)}</div>` : ''}
                <div style="display:flex;gap:6px;margin-top:8px;">
                    <button class="gis-btn gis-btn--xs" data-edit-owner="${o.id}">✏️ ویرایش</button>
                    <button class="gis-btn gis-btn--xs gis-btn--danger" data-del-owner="${o.id}">🗑️ حذف</button>
                </div>
            </div>`).join('')
            : `<div class="gis-empty-tab">مالکی ثبت نشده است.</div>`;

        const histHtml = history.length ? `<div class="gis-timeline">` + history.map(h => `
            <div class="gis-timeline-item">
                <div class="gis-timeline-dot"></div>
                <div class="gis-timeline-body">
                    <div class="gis-timeline-title">${this.escape(h.owner_name)}</div>
                    <div class="gis-timeline-meta">
                        ${histLabel[h.transfer_type]||h.transfer_type}
                        ${h.transfer_date ? ' — '+this._jalali(h.transfer_date) : ''}
                        ${h.transfer_price ? ' — کد نوسازی: <bdi dir="ltr">'+this.escape(h.transfer_price)+'</bdi>' : ''}
                    </div>
                    ${h.notes ? `<div class="gis-timeline-note">${this.escape(h.notes)}</div>` : ''}
                    <button class="gis-btn gis-btn--xs gis-btn--danger" data-del-history="${h.id}" style="margin-top:4px;">🗑️ حذف</button>
                </div>
            </div>`).join('') + '</div>'
            : '<div class="gis-empty-tab" style="margin-top:8px;">تاریخچه‌ای ثبت نشده.</div>';

        return `
        <div class="gis-tab-content">
            <div class="gis-section-title">مالکین فعلی
                <button class="gis-btn gis-btn--xs" data-action="add-owner">+ افزودن</button>
            </div>
            ${ownersHtml}
            <div class="gis-section-title" style="margin-top:16px;">تاریخچه مالکیت
                <button class="gis-btn gis-btn--xs" data-action="add-history">+ افزودن</button>
            </div>
            ${histHtml}
        </div>`;
    }

    /* ── محتوای تب کاربری ───────────────────────────────────── */
    _renderTabUse(u, p) {
        const row = (label, value, note='') => value != null && value !== ''
            ? `<div class="gis-info-row">
                   <span class="gis-info-label">${label}</span>
                   <span class="gis-info-value">${value}${note ? `<span style="font-size:10px;color:#94a3b8;margin-right:4px;">${note}</span>` : ''}</span>
               </div>` : '';

        const isEmpty = !u || (!u.current_use && !u.approved_use && !u.density_pct);

        /* تشخیص تعارض کاربری */
        const hasConflict = u.current_use && u.approved_use &&
            u.current_use.trim() !== u.approved_use.trim();

        /* محاسبه حداکثر بنا از مساحت زمین */
        const landArea = parseFloat(p.land?.area_sqm || 0);
        const density  = parseFloat(u.density_pct  || 0);
        const coverage = parseFloat(u.coverage_pct || 0);
        const maxBuild = u.max_build_area
            ? parseFloat(u.max_build_area)
            : (landArea > 0 && density > 0 ? landArea * density / 100 : null);
        const footprint = (landArea > 0 && coverage > 0)
            ? landArea * coverage / 100 : null;

        if (isEmpty) {
            return `
            <div class="gis-tab-content">
                <div class="gis-empty-tab">
                    🏷️ اطلاعات کاربری ثبت نشده است.
                    <br>
                    <button class="gis-btn gis-btn--secondary gis-btn--sm" style="margin-top:12px;"
                        data-action="edit-use">+ ثبت اطلاعات کاربری</button>
                </div>
            </div>`;
        }

        return `
        <div class="gis-tab-content">

            ${hasConflict ? `
            <div class="gis-alert-row gis-alert-row--critical" style="margin-bottom:12px;">
                ⚠️ تعارض کاربری: کاربری فعلی با مصوب طرح تفصیلی مغایرت دارد
            </div>` : ''}

            <div class="gis-info-divider">کاربری</div>
            ${row('کاربری فعلی', u.current_use ? this.escape(u.current_use) : null)}
            ${row('کاربری مصوب (طرح تفصیلی)', u.approved_use ? this.escape(u.approved_use) : null,
                hasConflict ? '⚠️ مغایرت' : (u.approved_use ? '✅ مطابقت' : ''))}

            <div class="gis-info-divider">ضوابط ساختمانی</div>
            ${row('تراکم ساختمانی مجاز', density > 0 ? `${density}%` : null)}
            ${row('سطح اشغال مجاز', coverage > 0 ? `${coverage}%` : null)}
            ${row('حداکثر طبقات مجاز', u.max_floors || null)}

            ${(maxBuild || footprint) ? `
            <div class="gis-info-divider">محاسبات اتوماتیک</div>
            ${maxBuild ? `
            <div class="gis-info-row" style="background:#f0fdf4;border-radius:8px;padding:8px 12px;">
                <span class="gis-info-label">حداکثر زیربنای مجاز</span>
                <span class="gis-info-value" style="color:#166534;font-weight:800;font-size:15px;">
                    ${this._fmt(maxBuild)} م²
                </span>
            </div>` : ''}
            ${footprint ? `
            <div class="gis-info-row" style="background:#eff6ff;border-radius:8px;padding:8px 12px;">
                <span class="gis-info-label">سطح اشغال زمین</span>
                <span class="gis-info-value" style="color:#1e40af;font-weight:700;">
                    ${this._fmt(footprint)} م²
                </span>
            </div>` : ''}
            ` : ''}

            <div style="margin-top:14px;">
                <button class="gis-btn gis-btn--secondary gis-btn--sm" data-action="edit-use">
                    ✏️ ویرایش اطلاعات کاربری
                </button>
            </div>
        </div>`;
    }

    /* ── مودال ویرایش کاربری ─────────────────────────────────── */
    _openUseModal(parcelId, u = {}) {
        const commonUses = [
            'مسکونی','تجاری','اداری','صنعتی','آموزشی',
            'درمانی','فرهنگی','ورزشی','باغی','مختلط مسکونی-تجاری',
        ];
        const datalistOpts = commonUses.map(v => `<option value="${v}">`).join('');

        const ov = document.createElement('div'); ov.className = 'acc-modal-overlay';
        ov.innerHTML = `
            <div class="acc-modal" style="max-width:460px;">
                <button class="acc-modal__close">✕</button>
                <div class="acc-modal__title">🏷️ اطلاعات کاربری</div>

                <datalist id="use-suggestions">${datalistOpts}</datalist>

                <form>
                    <div class="acc-form-group">
                        <label>کاربری فعلی واقعی</label>
                        <input name="current_use" list="use-suggestions"
                            value="${this.escape(u.current_use||'')}"
                            placeholder="مثلاً: مسکونی، تجاری...">
                    </div>
                    <div class="acc-form-group">
                        <label>کاربری مصوب (طرح تفصیلی)</label>
                        <input name="approved_use" list="use-suggestions"
                            value="${this.escape(u.approved_use||'')}"
                            placeholder="کاربری که شهرداری تعیین کرده">
                    </div>

                    <div class="gis-info-divider">ضوابط ساختمانی</div>

                    <div class="doc-form-row">
                        <div class="acc-form-group">
                            <label>تراکم مجاز (%)</label>
                            <input name="density_pct" type="number" min="0" max="1000" step="5"
                                value="${u.density_pct||''}" placeholder="مثلاً: 240">
                        </div>
                        <div class="acc-form-group">
                            <label>سطح اشغال (%)</label>
                            <input name="coverage_pct" type="number" min="0" max="100" step="5"
                                value="${u.coverage_pct||''}" placeholder="مثلاً: 60">
                        </div>
                    </div>
                    <div class="acc-form-group">
                        <label>حداکثر طبقات مجاز</label>
                        <input name="max_floors" type="number" min="0" max="50"
                            value="${u.max_floors||''}">
                    </div>

                    <div style="background:#f0fdf4;border-radius:8px;padding:10px 12px;font-size:12px;color:#166534;margin:10px 0;" id="use-calc-preview">
                        💡 حداکثر زیربنا پس از ذخیره محاسبه می‌شود
                    </div>

                    <div class="acc-modal__actions">
                        <button type="button" class="acc-btn acc-btn--secondary" data-action="cancel">انصراف</button>
                        <button type="submit" class="acc-btn acc-btn--primary">ذخیره</button>
                    </div>
                </form>
            </div>`;

        document.body.appendChild(ov);
        const close = () => ov.remove();
        ov.querySelector('.acc-modal__close').addEventListener('click', close);
        ov.querySelector('[data-action="cancel"]').addEventListener('click', close);
        ov.addEventListener('click', ev => { if (ev.target === ov) close(); });

        /* پیش‌نمایش زیربنا هنگام تایپ */
        const landArea = parseFloat(this._selected?.data?.land?.area_sqm || 0);
        const calcPreview = ov.querySelector('#use-calc-preview');
        const updatePreview = () => {
            const d = parseFloat(ov.querySelector('[name="density_pct"]').value) || 0;
            const c = parseFloat(ov.querySelector('[name="coverage_pct"]').value) || 0;
            if (landArea > 0 && (d > 0 || c > 0)) {
                const parts = [];
                if (d > 0) parts.push(`حداکثر زیربنا: <b>${this._fmt(landArea*d/100)} م²</b>`);
                if (c > 0) parts.push(`سطح اشغال: <b>${this._fmt(landArea*c/100)} م²</b>`);
                calcPreview.innerHTML = '💡 ' + parts.join(' | ');
            } else {
                calcPreview.textContent = landArea > 0
                    ? '💡 تراکم یا سطح اشغال را وارد کنید'
                    : '💡 ابتدا مساحت زمین را در دفتر زمین ثبت کنید';
            }
        };
        ov.querySelector('[name="density_pct"]').addEventListener('input', updatePreview);
        ov.querySelector('[name="coverage_pct"]').addEventListener('input', updatePreview);
        updatePreview();

        ov.querySelector('form').addEventListener('submit', async ev => {
            ev.preventDefault();
            const body = Object.fromEntries(new FormData(ev.target).entries());
            // پاکسازی مقادیر خالی
            ['density_pct','coverage_pct','max_floors'].forEach(k => {
                if (!body[k]) delete body[k];
            });
            const btn = ev.target.querySelector('[type="submit"]');
            btn.disabled = true; btn.textContent = 'در حال ذخیره...';
            try {
                await this.api.put(`/gis/parcels/${parcelId}/use`, body);
                close();
                this._toast('✅ اطلاعات کاربری ذخیره شد');
                this._openParcelPanel({ id: parcelId });
            } catch(err) {
                alert('خطا: ' + (err?.message || ''));
                btn.disabled = false; btn.textContent = 'ذخیره';
            }
        });
    }

    /* ── محتوای تب مشکلات ────────────────────────────────────── */
    _renderTabIssues(issues, commissions) {
        const sevColor = {critical:'#fee2e2',warning:'#fef3c7',info:'#eff6ff'};
        const sevBorder= {critical:'#ef4444',warning:'#f59e0b',info:'#3b82f6'};
        const statusLabel = {active:'فعال',resolved:'رفع‌شده',partial:'جزئی'};
        const verdictLabel = {demolish:'🔴 تخریب',fine:'🟡 جریمه',conditional:'🟠 مشروط'};
        const vs = {pending:'در انتظار', executed:'اجرا شده', not_executed:'اجرا نشده', appealed:'اعتراض'};

        const activeIssues   = issues.filter(i => i.status === 'active');
        const resolvedIssues = issues.filter(i => i.status !== 'active');

        const issuesHtml = activeIssues.length ? activeIssues.map(i => `
            <div class="gis-issue-card" style="background:${sevColor[i.severity]||'#f8fafc'};border-right:3px solid ${sevBorder[i.severity]||'#cbd5e1'}">
                <div class="gis-issue-title">${this.escape(i.title)}</div>
                <div class="gis-issue-meta">${ISSUE_LABEL[i.type]||i.type} ${i.amount ? ' — '+this._fmt(i.amount)+' ﷼' : ''}</div>
                ${i.description ? `<div class="gis-issue-desc">${this.escape(i.description)}</div>` : ''}
                <div style="display:flex;gap:6px;margin-top:6px;">
                    <button class="gis-btn gis-btn--xs" style="background:#dcfce7;color:#166534;border:1px solid #86efac;"
                        data-resolve-issue="${i.id}">✅ حل شد</button>
                    <button class="gis-btn gis-btn--xs gis-btn--danger" data-del-issue="${i.id}">🗑️ حذف</button>
                </div>
            </div>`).join('')
            : '<div class="gis-empty-tab" style="padding:12px 0;">مشکل فعالی ثبت نشده ✅</div>';

        const resolvedHtml = resolvedIssues.length ? resolvedIssues.map(i => `
            <div class="gis-issue-card gis-issue-resolved" style="background:#f8fafc;border-right:3px solid #cbd5e1;opacity:0.7;display:none;">
                <div class="gis-issue-title" style="text-decoration:line-through;color:#94a3b8;">${this.escape(i.title)}</div>
                <div class="gis-issue-meta" style="color:#94a3b8;">
                    ✅ ${statusLabel[i.status]||i.status}
                    ${i.resolved_at ? ' — '+this._jalali(i.resolved_at) : ''}
                </div>
            </div>`).join('') : '';

        const commsHtml = commissions.length ? commissions.map(c => `
            <div class="gis-issue-card" style="background:#fef9c3;border-right:3px solid #eab308;">
                <div class="gis-issue-title">ماده ۱۰۰ — سال ${c.year}</div>
                <div class="gis-issue-meta">
                    ${VIOLATION_LABEL[c.violation_type]||c.violation_type} |
                    ${verdictLabel[c.verdict]||c.verdict} |
                    ${vs[c.verdict_status]||c.verdict_status}
                    ${c.fine_amount ? ' — '+this._fmt(c.fine_amount)+' ﷼' : ''}
                </div>
                ${c.case_number ? `<div class="gis-issue-meta">پرونده: ${c.case_number}</div>` : ''}
                <div style="display:flex;gap:6px;margin-top:6px;">
                    <button class="gis-btn gis-btn--xs" data-edit-commission="${c.id}">✏️ ویرایش</button>
                    <button class="gis-btn gis-btn--xs gis-btn--danger" data-del-commission="${c.id}">🗑️ حذف</button>
                </div>
            </div>`).join('')
            : '';

        return `
        <div class="gis-tab-content">
            <div class="gis-section-title">مشکلات و موانع
                <button class="gis-btn gis-btn--xs" data-action="add-issue">+ افزودن</button>
                ${resolvedIssues.length ? `<button class="gis-btn gis-btn--xs" data-action="toggle-resolved"
                    style="background:#f1f5f9;color:#64748b;" data-showing="0">
                    👁️ رفع‌شده‌ها (${resolvedIssues.length})</button>` : ''}
            </div>
            ${issuesHtml}
            ${resolvedHtml}
            <div class="gis-section-title" style="margin-top:16px;">کمیسیون ماده ۱۰۰
                <button class="gis-btn gis-btn--xs" data-action="add-commission">+ افزودن</button>
            </div>
            ${commsHtml || '<div class="gis-empty-tab" style="padding:8px 0;">سابقه‌ای ثبت نشده ✅</div>'}
        </div>`;
    }

    /* ── محتوای تب کارنامه ───────────────────────────────────── */
    _renderTabScore(score) {
        const color  = { good:'#10b981', moderate:'#f59e0b', risky:'#ef4444' }[score.level] || '#6b7280';
        const label  = { good:'خوب', moderate:'متوسط', risky:'پرریسک' }[score.level] || '—';
        const pct    = (score.score || 0) + '%';

        return `
        <div class="gis-tab-content">
            <div class="gis-score-display" style="border-color:${color}">
                <div class="gis-score-value" style="color:${color}">${score.score||0}</div>
                <div class="gis-score-label">${label}</div>
            </div>
            <div class="gis-score-bar-wrap">
                <div class="gis-score-bar-track">
                    <div class="gis-score-bar-fill" style="width:${pct};background:${color}"></div>
                </div>
            </div>
            ${(score.warnings||[]).length ? `
            <div class="gis-section-title" style="margin-top:14px;">موارد کاهش امتیاز</div>
            ${score.warnings.map(w => `
                <div class="gis-issue-card" style="background:${w.level==='critical'?'#fee2e2':'#fef3c7'};border-right:3px solid ${w.level==='critical'?'#ef4444':'#f59e0b'}">
                    <span style="font-size:13px;">${w.level==='critical'?'🔴':'🟡'} ${this.escape(w.text)}</span>
                </div>`).join('')}` : `
            <div class="gis-empty-tab" style="margin-top:16px;color:#10b981;">✅ هیچ مشکل کاهش‌دهنده‌ای یافت نشد</div>`}
        </div>`;
    }

    /* ── مودال افزودن پارسل جدید ────────────────────────────── */
    _openAddParcelModal(lat, lng) {
        this._exitAddMode();

        const distOpts = `<option value="">— انتخاب —</option>` +
            (this._mapData.districts||[]).map(d => `<option value="${d.id}">${this.escape(d.name)}</option>`).join('');

        const statusOpts = Object.entries(STATUS_LABEL)
            .map(([k,v]) => `<option value="${k}">${v}</option>`).join('');

        const ov = document.createElement('div'); ov.className = 'acc-modal-overlay';
        ov.innerHTML = `
            <div class="acc-modal" style="max-width:480px;">
                <button class="acc-modal__close">✕</button>
                <div class="acc-modal__title">📍 افزودن پارسل جدید</div>
                <div style="background:#f0fdf4;border-radius:8px;padding:8px 12px;font-size:12px;color:#166534;margin-bottom:14px;">
                    مختصات: ${lat.toFixed(6)} , ${lng.toFixed(6)}
                </div>
                <form>
                    <div class="doc-form-row">
                        <div class="acc-form-group">
                            <label>پلاک اصلی</label>
                            <input name="code" type="text" placeholder="مثال: ۲۳">
                        </div>
                        <div class="acc-form-group">
                            <label>پلاک فرعی</label>
                            <input name="sub_code" type="text" placeholder="مثال: ۱۴۵">
                        </div>
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group">
                            <label>منطقه</label>
                            <select name="district_id" id="new-district-sel">${distOpts}</select>
                        </div>
                        <div class="acc-form-group">
                            <label>محله</label>
                            <select name="neighborhood_id" id="new-neighborhood-sel">
                                <option value="">— ابتدا منطقه انتخاب کنید —</option>
                            </select>
                        </div>
                    </div>
                    <div class="acc-form-group">
                        <label>آدرس</label>
                        <input name="address" type="text" placeholder="آدرس دقیق...">
                    </div>
                    <div class="acc-form-group">
                        <label>وضعیت</label>
                        <select name="status">${statusOpts}</select>
                    </div>
                    <div class="acc-form-group">
                        <label>کارشناس مسئول</label>
                        <input name="assigned_user_name" type="text" placeholder="نام کارشناس (اختیاری)">
                    </div>
                    <div class="acc-modal__actions">
                        <button type="button" class="acc-btn acc-btn--secondary" data-action="cancel">انصراف</button>
                        <button type="submit" class="acc-btn acc-btn--primary">ثبت پارسل</button>
                    </div>
                </form>
            </div>`;

        document.body.appendChild(ov);

        // پر کردن محلات با انتخاب منطقه
        const dSel = ov.querySelector('#new-district-sel');
        const nSel = ov.querySelector('#new-neighborhood-sel');
        dSel.addEventListener('change', () => {
            const did = parseInt(dSel.value);
            const opts = `<option value="">— انتخاب —</option>` +
                (this._mapData.neighborhoods||[])
                    .filter(n => n.district_id == did)
                    .map(n => `<option value="${n.id}">${this.escape(n.name)}</option>`)
                    .join('');
            nSel.innerHTML = opts;
        });

        const close = () => ov.remove();
        ov.querySelector('.acc-modal__close').addEventListener('click', close);
        ov.querySelector('[data-action="cancel"]').addEventListener('click', close);
        ov.addEventListener('click', ev => { if(ev.target===ov) close(); });

        ov.querySelector('form').addEventListener('submit', async ev => {
            ev.preventDefault();
            const fd   = new FormData(ev.target);
            const body = Object.fromEntries(fd.entries());
            body.lat = lat; body.lng = lng;
            if (!body.district_id) delete body.district_id;
            if (!body.neighborhood_id) delete body.neighborhood_id;
            if (!body.assigned_user_name) delete body.assigned_user_name;

            const btn = ev.target.querySelector('[type="submit"]');
            btn.disabled = true; btn.textContent = 'در حال ثبت...';
            try {
                const res = await this.api.post('/gis/parcels', body);
                close();
                this._toast('✅ پارسل با موفقیت ثبت شد');
                await this._loadMapData();
                // باز کردن پانل پارسل جدید
                if (res?.id) this._openParcelPanel({ id: res.id });
            } catch(err) {
                alert('خطا: '+(err?.message||''));
                btn.disabled = false; btn.textContent = 'ثبت پارسل';
            }
        });
    }

    /* ── مودال ویرایش پارسل ──────────────────────────────────── */
    _openEditParcelModal(p) {
        const distOpts = `<option value="">— انتخاب —</option>` +
            (this._mapData.districts||[]).map(d =>
                `<option value="${d.id}" ${d.id==p.district_id?'selected':''}>${this.escape(d.name)}</option>`
            ).join('');

        const ov = document.createElement('div'); ov.className = 'acc-modal-overlay';
        ov.innerHTML = `
            <div class="acc-modal" style="max-width:520px;">
                <button class="acc-modal__close">✕</button>
                <div class="acc-modal__title">✏️ ویرایش پارسل</div>
                <form>
                    <div class="doc-form-row">
                        <div class="acc-form-group">
                            <label>پلاک اصلی</label>
                            <input name="code" value="${this.escape(p.code||'')}">
                        </div>
                        <div class="acc-form-group">
                            <label>پلاک فرعی</label>
                            <input name="sub_code" value="${this.escape(p.sub_code||'')}">
                        </div>
                    </div>
                    <div class="acc-form-group">
                        <label>بخش ثبتی</label>
                        <input name="registry_section" value="${this.escape(p.registry_section||'')}">
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group">
                            <label>منطقه</label>
                            <select name="district_id">${distOpts}</select>
                        </div>
                        <div class="acc-form-group">
                            <label>وضعیت</label>
                            <select name="status">
                                ${Object.entries(STATUS_LABEL).map(([k,v]) =>
                                    `<option value="${k}" ${p.status===k?'selected':''}>${v}</option>`).join('')}
                            </select>
                        </div>
                    </div>
                    <div class="acc-form-group">
                        <label>آدرس</label>
                        <textarea name="address" rows="2">${this.escape(p.address||'')}</textarea>
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group">
                            <label>کارشناس مسئول</label>
                            <input name="assigned_user_name" value="${this.escape(p.assigned_user_name||'')}">
                        </div>
                    </div>
                    <div class="acc-form-group">
                        <label>یادداشت</label>
                        <textarea name="notes" rows="2">${this.escape(p.notes||'')}</textarea>
                    </div>
                    <div class="acc-modal__actions">
                        <button type="button" class="acc-btn acc-btn--secondary" data-action="cancel">انصراف</button>
                        <button type="submit" class="acc-btn acc-btn--primary">ذخیره تغییرات</button>
                    </div>
                </form>
            </div>`;
        document.body.appendChild(ov);
        const close = () => ov.remove();
        ov.querySelector('.acc-modal__close').addEventListener('click', close);
        ov.querySelector('[data-action="cancel"]').addEventListener('click', close);
        ov.addEventListener('click', ev => { if(ev.target===ov) close(); });
        ov.querySelector('form').addEventListener('submit', async ev => {
            ev.preventDefault();
            const body = Object.fromEntries(new FormData(ev.target).entries());
            const btn  = ev.target.querySelector('[type="submit"]');
            btn.disabled = true; btn.textContent = 'در حال ذخیره...';
            try {
                await this.api.put(`/gis/parcels/${p.id}`, body);
                close();
                this._toast('✅ تغییرات ذخیره شد');
                await this._loadMapData();
                this._openParcelPanel({ id: p.id });
            } catch(err) {
                alert('خطا: '+(err?.message||''));
                btn.disabled = false; btn.textContent = 'ذخیره تغییرات';
            }
        });
    }

    /* ── مودال افزودن/ویرایش مالک ────────────────────────────── */
    _openOwnerModal(parcelId, owner = null) {
        const isEdit = !!owner;
        const deedOpts = [['single_page','تک‌برگ'],['old','منگوله‌دار'],['qolnameh','قولنامه‌ای'],['other','سایر']];
        const sel = (k) => owner?.deed_type === k ? 'selected' : '';

        const ov = document.createElement('div'); ov.className = 'acc-modal-overlay';
        ov.innerHTML = `
            <div class="acc-modal" style="max-width:420px;">
                <button class="acc-modal__close">✕</button>
                <div class="acc-modal__title">👤 ${isEdit ? 'ویرایش' : 'افزودن'} مالک</div>
                <form>
                    <div class="acc-form-group"><label>نام مالک *</label>
                        <input name="name" required value="${this.escape(owner?.name||'')}">
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>کد ملی</label>
                            <input name="national_id" value="${this.escape(owner?.national_id||'')}">
                        </div>
                        <div class="acc-form-group"><label>سهم (مثلاً 6/6)</label>
                            <input name="ownership_share" value="${this.escape(owner?.ownership_share||'6/6')}">
                        </div>
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>نوع سند</label>
                            <select name="deed_type">
                                ${deedOpts.map(([k,v])=>`<option value="${k}" ${sel(k)}>${v}</option>`).join('')}
                            </select>
                        </div>
                        <div class="acc-form-group"><label>شماره سند</label>
                            <input name="deed_number" value="${this.escape(owner?.deed_number||'')}">
                        </div>
                    </div>
                    <div class="acc-form-group"><label>دفترخانه</label>
                        <input name="registry_office" value="${this.escape(owner?.registry_office||'')}">
                    </div>
                    <div class="acc-form-group"><label>تلفن</label>
                        <input name="phone" type="tel" value="${this.escape(owner?.phone||'')}">
                    </div>
                    <label style="display:flex;gap:8px;align-items:center;font-size:13px;margin:10px 0;">
                        <input type="checkbox" name="is_primary" value="1" ${owner?.is_primary=='1'?'checked':''}> مالک اصلی
                    </label>
                    <div class="acc-modal__actions">
                        <button type="button" class="acc-btn acc-btn--secondary" data-action="cancel">انصراف</button>
                        <button type="submit" class="acc-btn acc-btn--primary">${isEdit ? 'ذخیره' : 'ثبت مالک'}</button>
                    </div>
                </form>
            </div>`;
        document.body.appendChild(ov);
        const close = () => ov.remove();
        ov.querySelector('.acc-modal__close').addEventListener('click', close);
        ov.querySelector('[data-action="cancel"]').addEventListener('click', close);
        ov.addEventListener('click', ev => { if(ev.target===ov) close(); });
        ov.querySelector('form').addEventListener('submit', async ev => {
            ev.preventDefault();
            const body = Object.fromEntries(new FormData(ev.target).entries());
            body.is_primary = body.is_primary ? 1 : 0;
            if (isEdit) body.owner_id = owner.id;
            const btn = ev.target.querySelector('[type="submit"]');
            btn.disabled = true;
            try {
                if (isEdit) {
                    await this.api.put(`/gis/parcels/${parcelId}/owners/${owner.id}`, body);
                    this._toast('✅ اطلاعات مالک به‌روز شد');
                } else {
                    await this.api.post(`/gis/parcels/${parcelId}/owners`, body);
                    this._toast('✅ مالک ثبت شد');
                }
                close();
                this._openParcelPanel({ id: parcelId });
            } catch(err) { alert('خطا: '+(err?.message||'')); btn.disabled=false; }
        });
    }

    /* ── مودال افزودن مشکل ───────────────────────────────────── */
    _openIssueModal(parcelId, p) {
        const types = Object.entries(ISSUE_LABEL);
        const ov = document.createElement('div'); ov.className = 'acc-modal-overlay';
        ov.innerHTML = `
            <div class="acc-modal" style="max-width:420px;">
                <button class="acc-modal__close">✕</button>
                <div class="acc-modal__title">⚠️ افزودن مشکل</div>
                <form>
                    <div class="acc-form-group"><label>نوع مشکل</label>
                        <select name="type">${types.map(([k,v])=>`<option value="${k}">${v}</option>`).join('')}</select>
                    </div>
                    <div class="acc-form-group"><label>عنوان *</label><input name="title" required></div>
                    <div class="acc-form-group"><label>شدت</label>
                        <select name="severity">
                            <option value="critical">🔴 بحرانی</option>
                            <option value="warning" selected>🟡 هشدار</option>
                            <option value="info">🔵 اطلاع</option>
                        </select>
                    </div>
                    <div class="acc-form-group"><label>مبلغ (اختیاری)</label>
                        <input name="amount" type="number" min="0" placeholder="ریال">
                    </div>
                    <div class="acc-form-group"><label>توضیحات</label>
                        <textarea name="description" rows="2"></textarea>
                    </div>
                    <div class="acc-modal__actions">
                        <button type="button" class="acc-btn acc-btn--secondary" data-action="cancel">انصراف</button>
                        <button type="submit" class="acc-btn acc-btn--primary">ثبت مشکل</button>
                    </div>
                </form>
            </div>`;
        document.body.appendChild(ov);
        const close = () => ov.remove();
        ov.querySelector('.acc-modal__close').addEventListener('click', close);
        ov.querySelector('[data-action="cancel"]').addEventListener('click', close);
        ov.addEventListener('click', ev => { if(ev.target===ov) close(); });
        ov.querySelector('form').addEventListener('submit', async ev => {
            ev.preventDefault();
            const body = Object.fromEntries(new FormData(ev.target).entries());
            const btn = ev.target.querySelector('[type="submit"]');
            btn.disabled = true;
            try {
                await this.api.post(`/gis/parcels/${parcelId}/issues`, body);
                close(); this._toast('⚠️ مشکل ثبت شد');
                this._openParcelPanel({ id: parcelId });
            } catch(err) { alert('خطا: '+(err?.message||'')); btn.disabled=false; }
        });
    }

    /* ── مودال افزودن/ویرایش کمیسیون ماده ۱۰۰ ────────────────── */
    _openCommissionModal(parcelId, commission = null) {
        const isEdit = !!commission;
        const c = commission || {};
        const vtypes = Object.entries(VIOLATION_LABEL);
        const selV = (k) => c.violation_type === k ? 'selected' : '';
        const selR = (k) => c.verdict         === k ? 'selected' : '';
        const selS = (k) => c.verdict_status  === k ? 'selected' : '';

        const ov = document.createElement('div'); ov.className = 'acc-modal-overlay';
        ov.innerHTML = `
            <div class="acc-modal" style="max-width:420px;">
                <button class="acc-modal__close">✕</button>
                <div class="acc-modal__title">🔨 ${isEdit?'ویرایش':'ثبت'} کمیسیون ماده ۱۰۰</div>
                <form>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>سال</label>
                            <input name="year" type="number" value="${c.year||new Date().getFullYear()}" min="1350">
                        </div>
                        <div class="acc-form-group"><label>شماره پرونده</label>
                            <input name="case_number" value="${this.escape(c.case_number||'')}" placeholder="اختیاری">
                        </div>
                    </div>
                    <div class="acc-form-group"><label>نوع تخلف</label>
                        <select name="violation_type">
                            ${vtypes.map(([k,v])=>`<option value="${k}" ${selV(k)}>${v}</option>`).join('')}
                        </select>
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>رأی</label>
                            <select name="verdict">
                                <option value="fine"        ${selR('fine')}>🟡 جریمه</option>
                                <option value="demolish"    ${selR('demolish')}>🔴 تخریب</option>
                                <option value="conditional" ${selR('conditional')}>🟠 مشروط</option>
                            </select>
                        </div>
                        <div class="acc-form-group"><label>وضعیت اجرا</label>
                            <select name="verdict_status">
                                <option value="pending"      ${selS('pending')}>در انتظار</option>
                                <option value="executed"     ${selS('executed')}>اجرا شده</option>
                                <option value="not_executed" ${selS('not_executed')}>اجرا نشده</option>
                                <option value="appealed"     ${selS('appealed')}>اعتراض</option>
                            </select>
                        </div>
                    </div>
                    <div class="acc-form-group"><label>مبلغ جریمه (ریال)</label>
                        <input name="fine_amount" type="number" min="0" value="${c.fine_amount||''}">
                    </div>
                    <div class="acc-form-group"><label>توضیحات</label>
                        <textarea name="description" rows="2">${this.escape(c.description||'')}</textarea>
                    </div>
                    <div class="acc-modal__actions">
                        <button type="button" class="acc-btn acc-btn--secondary" data-action="cancel">انصراف</button>
                        <button type="submit" class="acc-btn acc-btn--primary">${isEdit?'ذخیره':'ثبت'}</button>
                    </div>
                </form>
            </div>`;
        document.body.appendChild(ov);
        const close = () => ov.remove();
        ov.querySelector('.acc-modal__close').addEventListener('click', close);
        ov.querySelector('[data-action="cancel"]').addEventListener('click', close);
        ov.addEventListener('click', ev => { if(ev.target===ov) close(); });
        ov.querySelector('form').addEventListener('submit', async ev => {
            ev.preventDefault();
            const body = Object.fromEntries(new FormData(ev.target).entries());
            const btn = ev.target.querySelector('[type="submit"]');
            btn.disabled = true;
            try {
                if (isEdit) {
                    await this.api.put(`/gis/parcels/${parcelId}/commissions/${c.id}`, body);
                    this._toast('✅ کمیسیون به‌روز شد', '#eab308');
                } else {
                    await this.api.post(`/gis/parcels/${parcelId}/commissions`, body);
                    this._toast('🔨 کمیسیون ثبت شد', '#eab308');
                }
                close();
                this._openParcelPanel({ id: parcelId });
            } catch(err) { alert('خطا: '+(err?.message||'')); btn.disabled=false; }
        });
    }

    /* ── تاریخچه مالکیت مودال ───────────────────────────────── */
    _openHistoryModal(parcelId) {
        const ov = document.createElement('div'); ov.className = 'acc-modal-overlay';
        ov.innerHTML = `
            <div class="acc-modal" style="max-width:400px;">
                <button class="acc-modal__close">✕</button>
                <div class="acc-modal__title">📜 ثبت تاریخچه مالکیت</div>
                <form>
                    <div class="acc-form-group"><label>نام مالک قبلی *</label><input name="owner_name" required></div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>نوع انتقال</label>
                            <select name="transfer_type">
                                <option value="sale">خرید و فروش</option>
                                <option value="inheritance">ارث</option>
                                <option value="gift">هبه</option>
                                <option value="auction">مزایده</option>
                                <option value="government">تملک دولتی</option>
                                <option value="other">سایر</option>
                            </select>
                        </div>
                        <div class="acc-form-group"><label>تاریخ انتقال</label>
                            <input name="transfer_date" type="date">
                        </div>
                    </div>
                    <div class="acc-form-group"><label>کد نوسازی</label>
                        <input name="transfer_price" type="text" placeholder="مثلاً: 10-2-162-7-0-0-0">
                    </div>
                    <div class="acc-form-group"><label>یادداشت</label>
                        <textarea name="notes" rows="2"></textarea>
                    </div>
                    <div class="acc-modal__actions">
                        <button type="button" class="acc-btn acc-btn--secondary" data-action="cancel">انصراف</button>
                        <button type="submit" class="acc-btn acc-btn--primary">ثبت</button>
                    </div>
                </form>
            </div>`;
        document.body.appendChild(ov);
        const close = () => ov.remove();
        ov.querySelector('.acc-modal__close').addEventListener('click', close);
        ov.querySelector('[data-action="cancel"]').addEventListener('click', close);
        ov.addEventListener('click', ev => { if(ev.target===ov) close(); });
        ov.querySelector('form').addEventListener('submit', async ev => {
            ev.preventDefault();
            const body = Object.fromEntries(new FormData(ev.target).entries());
            const btn  = ev.target.querySelector('[type="submit"]');
            btn.disabled = true;
            try {
                await this.api.post(`/gis/parcels/${parcelId}/history`, body);
                close(); this._toast('✅ تاریخچه ثبت شد');
                this._openParcelPanel({ id: parcelId });
            } catch(err) { alert('خطا: '+(err?.message||'')); btn.disabled=false; }
        });
    }

    /* ── مودال ویرایش اطلاعات زمین ──────────────────────────── */
    _openLandModal(parcelId, l = {}) {
        const dirOpts = (sel) => ['north','south','east','west']
            .map(d => `<option value="${d}" ${l[sel]===d?'selected':''}>${{north:'شمالی',south:'جنوبی',east:'شرقی',west:'غربی'}[d]}</option>`).join('');

        const ov = document.createElement('div'); ov.className = 'acc-modal-overlay';
        ov.innerHTML = `
            <div class="acc-modal" style="max-width:520px;max-height:90vh;overflow-y:auto;">
                <button class="acc-modal__close">✕</button>
                <div class="acc-modal__title">📍 اطلاعات زمین</div>
                <form>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>مساحت (م²) *</label>
                            <input name="area_sqm" type="number" min="0" step="0.01" value="${l.area_sqm||''}" required>
                        </div>
                        <div class="acc-form-group"><label>شکل زمین</label>
                            <select name="shape">
                                <option value="rectangular" ${l.shape==='rectangular'?'selected':''}>مستطیل</option>
                                <option value="square"      ${l.shape==='square'?'selected':''}>مربع</option>
                                <option value="corner"      ${l.shape==='corner'?'selected':''}>گوشه‌ای</option>
                                <option value="irregular"   ${l.shape==='irregular'?'selected':''}>نامنظم</option>
                                <option value="triangular"  ${l.shape==='triangular'?'selected':''}>مثلثی</option>
                            </select>
                        </div>
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>موقعیت پلاک</label>
                            <select name="position">
                                <option value="middle" ${l.position==='middle'?'selected':''}>میانی</option>
                                <option value="corner" ${l.position==='corner'?'selected':''}>گوشه</option>
                                <option value="end"    ${l.position==='end'?'selected':''}>انتهایی</option>
                            </select>
                        </div>
                        <div class="acc-form-group"><label>نوع مالکیت زمین</label>
                            <select name="ownership_type">
                                <option value="private"    ${l.ownership_type==='private'?'selected':''}>ملکی</option>
                                <option value="endowment"  ${l.ownership_type==='endowment'?'selected':''}>وقفی</option>
                                <option value="government" ${l.ownership_type==='government'?'selected':''}>دولتی</option>
                                <option value="national"   ${l.ownership_type==='national'?'selected':''}>اراضی ملی</option>
                            </select>
                        </div>
                    </div>
                    <div style="margin:8px 0;">
                        <label style="display:flex;gap:8px;align-items:center;font-size:13px;color:#dc2626;">
                            <input type="checkbox" name="is_national_land" value="1" ${l.is_national_land=='1'?'checked':''}>
                            🔴 اراضی ملی (کاهش ۵۰ امتیاز)
                        </label>
                    </div>
                    <div class="gis-info-divider">معابر مجاور</div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>عرض معبر اصلی (متر)</label>
                            <input name="main_street_width" type="number" min="0" step="0.5" value="${l.main_street_width||''}">
                        </div>
                        <div class="acc-form-group"><label>جهت معبر اصلی</label>
                            <select name="main_street_dir"><option value="">—</option>${dirOpts('main_street_dir')}</select>
                        </div>
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>عرض معبر فرعی (متر)</label>
                            <input name="second_street_width" type="number" min="0" step="0.5" value="${l.second_street_width||''}">
                        </div>
                        <div class="acc-form-group"><label>جهت معبر فرعی</label>
                            <select name="second_street_dir"><option value="">—</option>${dirOpts('second_street_dir')}</select>
                        </div>
                    </div>
                    <div class="gis-info-divider">ابعاد (متر)</div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>بر شمالی</label>
                            <input name="north_dim" type="number" step="0.01" value="${l.north_dim||''}">
                        </div>
                        <div class="acc-form-group"><label>بر جنوبی</label>
                            <input name="south_dim" type="number" step="0.01" value="${l.south_dim||''}">
                        </div>
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>عمق شرقی</label>
                            <input name="east_dim" type="number" step="0.01" value="${l.east_dim||''}">
                        </div>
                        <div class="acc-form-group"><label>عمق غربی</label>
                            <input name="west_dim" type="number" step="0.01" value="${l.west_dim||''}">
                        </div>
                    </div>
                    <div class="acc-modal__actions">
                        <button type="button" class="acc-btn acc-btn--secondary" data-action="cancel">انصراف</button>
                        <button type="submit" class="acc-btn acc-btn--primary">ذخیره</button>
                    </div>
                </form>
            </div>`;
        document.body.appendChild(ov);
        const close = () => ov.remove();
        ov.querySelector('.acc-modal__close').addEventListener('click', close);
        ov.querySelector('[data-action="cancel"]').addEventListener('click', close);
        ov.addEventListener('click', ev => { if (ev.target === ov) close(); });
        ov.querySelector('form').addEventListener('submit', async ev => {
            ev.preventDefault();
            const body = Object.fromEntries(new FormData(ev.target).entries());
            body.is_national_land = body.is_national_land ? 1 : 0;
            const btn = ev.target.querySelector('[type="submit"]');
            btn.disabled = true; btn.textContent = 'در حال ذخیره...';
            try {
                await this.api.put(`/gis/parcels/${parcelId}/land`, body);
                close(); this._toast('✅ اطلاعات زمین ذخیره شد');
                this._openParcelPanel({ id: parcelId });
            } catch(err) { alert('خطا: '+(err?.message||'')); btn.disabled=false; btn.textContent='ذخیره'; }
        });
    }

    /* ── مودال ویرایش اطلاعات ساختمان ───────────────────────── */
    _openBuildingModal(parcelId, b = {}) {
        const yn = (name, val) => ['yes','no','unknown'].map(v =>
            `<option value="${v}" ${val===v?'selected':''}>${{yes:'✅ دارد',no:'❌ ندارد',unknown:'⚠️ نامعلوم'}[v]}</option>`
        ).join('');
        const ynPartial = (name, val) => ['yes','no','partial'].map(v =>
            `<option value="${v}" ${val===v?'selected':''}>${{yes:'✅ دارد',no:'❌ ندارد',partial:'🟡 ناقص'}[v]}</option>`
        ).join('');
        const chk = (name, val, label) =>
            `<label style="display:flex;gap:6px;align-items:center;font-size:13px;">
                <input type="checkbox" name="${name}" value="1" ${val?'checked':''}> ${label}
             </label>`;

        const ov = document.createElement('div'); ov.className = 'acc-modal-overlay';
        ov.innerHTML = `
            <div class="acc-modal" style="max-width:520px;max-height:90vh;overflow-y:auto;">
                <button class="acc-modal__close">✕</button>
                <div class="acc-modal__title">🏛️ اطلاعات ساختمان</div>
                <form>
                    <div style="margin-bottom:12px;">
                        ${chk('has_building', b.has_building, '🏗️ این پلاک دارای ساختمان است')}
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>تعداد طبقات</label>
                            <input name="floors" type="number" min="0" value="${b.floors||''}">
                        </div>
                        <div class="acc-form-group"><label>تعداد واحدها</label>
                            <input name="units" type="number" min="0" value="${b.units||''}">
                        </div>
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>مساحت کل بنا (م²)</label>
                            <input name="total_area_sqm" type="number" min="0" step="0.1" value="${b.total_area_sqm||''}">
                        </div>
                        <div class="acc-form-group"><label>سال ساخت</label>
                            <input name="built_year" type="number" min="1300" max="${new Date().getFullYear()}" value="${b.built_year||''}">
                        </div>
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>نوع اسکلت</label>
                            <select name="structure_type">
                                <option value="concrete" ${b.structure_type==='concrete'?'selected':''}>بتن‌آرمه</option>
                                <option value="steel"    ${b.structure_type==='steel'?'selected':''}>فلزی</option>
                                <option value="masonry"  ${b.structure_type==='masonry'?'selected':''}>آجری</option>
                                <option value="other"    ${b.structure_type==='other'?'selected':''}>سایر</option>
                            </select>
                        </div>
                        <div class="acc-form-group"><label>نما</label>
                            <input name="facade" type="text" value="${this.escape(b.facade||'')}" placeholder="مثلاً سنگ، آجر، کامپوزیت">
                        </div>
                    </div>
                    <div class="gis-info-divider">مدارک</div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>پروانه ساخت</label>
                            <select name="has_permit">${yn('has_permit', b.has_permit)}</select>
                        </div>
                        <div class="acc-form-group"><label>شماره پروانه</label>
                            <input name="permit_number" value="${this.escape(b.permit_number||'')}">
                        </div>
                    </div>
                    <div class="acc-form-group"><label>پایان کار</label>
                        <select name="has_completion">${ynPartial('has_completion', b.has_completion)}</select>
                    </div>
                    <div class="gis-info-divider">امکانات</div>
                    <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin:8px 0;">
                        ${chk('has_water',       b.has_water,       '💧 آب')}
                        ${chk('has_electricity', b.has_electricity, '⚡ برق')}
                        ${chk('has_gas',         b.has_gas,         '🔥 گاز')}
                        ${chk('has_elevator',    b.has_elevator,    '🛗 آسانسور')}
                        ${chk('has_parking',     b.has_parking,     '🚗 پارکینگ')}
                        ${chk('has_storage',     b.has_storage,     '📦 انباری')}
                        ${chk('has_basement',    b.has_basement,    '🏚️ زیرزمین')}
                    </div>
                    <div class="acc-modal__actions">
                        <button type="button" class="acc-btn acc-btn--secondary" data-action="cancel">انصراف</button>
                        <button type="submit" class="acc-btn acc-btn--primary">ذخیره</button>
                    </div>
                </form>
            </div>`;
        document.body.appendChild(ov);
        const close = () => ov.remove();
        ov.querySelector('.acc-modal__close').addEventListener('click', close);
        ov.querySelector('[data-action="cancel"]').addEventListener('click', close);
        ov.addEventListener('click', ev => { if (ev.target === ov) close(); });
        ov.querySelector('form').addEventListener('submit', async ev => {
            ev.preventDefault();
            const fd   = new FormData(ev.target);
            const body = Object.fromEntries(fd.entries());
            // checkboxes: if not in FormData => 0
            ['has_building','has_basement','has_water','has_electricity','has_gas','has_elevator','has_parking','has_storage'].forEach(k => {
                body[k] = body[k] ? 1 : 0;
            });
            const btn = ev.target.querySelector('[type="submit"]');
            btn.disabled = true; btn.textContent = 'در حال ذخیره...';
            try {
                await this.api.put(`/gis/parcels/${parcelId}/building`, body);
                close(); this._toast('✅ اطلاعات ساختمان ذخیره شد');
                this._openParcelPanel({ id: parcelId });
            } catch(err) { alert('خطا: '+(err?.message||'')); btn.disabled=false; btn.textContent='ذخیره'; }
        });
    }

    /* ── مودال ایجاد پروژه CPM ───────────────────────────────── */
    _openCreateProjectModal(p) {
        const defaultName = `پروژه پلاک ${p.code||p.id}${p.sub_code ? '/'+p.sub_code : ''}`;
        const today = new Date().toISOString().split('T')[0];

        const ov = document.createElement('div'); ov.className = 'acc-modal-overlay';
        ov.innerHTML = `
            <div class="acc-modal" style="max-width:460px;">
                <button class="acc-modal__close">✕</button>
                <div class="acc-modal__title">🏗️ ایجاد پروژه ساخت</div>
                <div style="background:#eff6ff;border-radius:8px;padding:10px 14px;font-size:12px;color:#1e40af;margin-bottom:14px;">
                    📁 پلاک: ${this.escape(p.code||'—')}/${this.escape(p.sub_code||'—')}
                    ${p.district_name ? ` | 🏙️ ${this.escape(p.district_name)}` : ''}
                </div>
                <form>
                    <div class="acc-form-group"><label>نام پروژه *</label>
                        <input name="name" required value="${this.escape(defaultName)}">
                    </div>
                    <div class="doc-form-row">
                        <div class="acc-form-group"><label>کد پروژه</label>
                            <input name="code" placeholder="مثلاً PRJ-001">
                        </div>
                        <div class="acc-form-group"><label>تاریخ شروع</label>
                            <input name="start_date" type="date" value="${today}">
                        </div>
                    </div>
                    <div class="acc-form-group"><label>مدیر پروژه</label>
                        <input name="manager_name" value="${this.escape(p.assigned_user_name||'')}">
                    </div>
                    <div class="acc-form-group"><label>بودجه اولیه (ریال)</label>
                        <input name="budget" type="number" min="0" placeholder="اختیاری">
                    </div>
                    <div class="acc-form-group"><label>توضیحات</label>
                        <textarea name="description" rows="2" placeholder="خلاصه پروژه...">${
                            this.escape(p.address ? 'آدرس: '+p.address : '')
                        }</textarea>
                    </div>
                    <div class="acc-modal__actions">
                        <button type="button" class="acc-btn acc-btn--secondary" data-action="cancel">انصراف</button>
                        <button type="submit" class="acc-btn acc-btn--success">🏗️ ایجاد پروژه</button>
                    </div>
                </form>
            </div>`;
        document.body.appendChild(ov);
        const close = () => ov.remove();
        ov.querySelector('.acc-modal__close').addEventListener('click', close);
        ov.querySelector('[data-action="cancel"]').addEventListener('click', close);
        ov.addEventListener('click', ev => { if (ev.target === ov) close(); });
        ov.querySelector('form').addEventListener('submit', async ev => {
            ev.preventDefault();
            const body = Object.fromEntries(new FormData(ev.target).entries());
            body.type   = 'construction';
            body.status = 'planned';
            body.parcel_id = p.id;
            if (!body.budget) delete body.budget;
            const btn = ev.target.querySelector('[type="submit"]');
            btn.disabled = true; btn.textContent = 'در حال ایجاد...';
            try {
                const res = await this.api.post('/pc/projects', body);
                const projectId = res?.id || res?.data?.id;
                // ذخیره لینک در پارسل
                if (projectId) {
                    await this.api.put(`/gis/parcels/${p.id}`, { cpm_project_id: projectId });
                }
                close();
                this._toast(`✅ پروژه با موفقیت ایجاد شد${projectId?' (ID: '+projectId+')':''}`, '#10b981');
                await this._loadMapData();
                this._openParcelPanel({ id: p.id });
            } catch(err) {
                alert('خطا در ایجاد پروژه: '+(err?.message||''));
                btn.disabled=false; btn.textContent='🏗️ ایجاد پروژه';
            }
        });
    }

    /* ── قفل تیمی ────────────────────────────────────────────── */
    async _toggleLock(p) {
        const currentUser = this._getCurrentUser();
        try {
            if (p.locked_by_user_id && p.locked_by_user_id != currentUser.id) {
                alert(`این پارسل توسط ${p.locked_by_name} در دست بررسی است.`);
                return;
            }
            if (p.locked_by_user_id) {
                await this.api.post(`/gis/parcels/${p.id}/unlock`, {});
                this._toast('🔓 پارسل آزاد شد');
            } else {
                await this.api.post(`/gis/parcels/${p.id}/lock`, { user_id: currentUser.id, user_name: currentUser.name });
                this._toast('🔒 پارسل رزرو شد برای شما');
            }
            await this._loadMapData();
            this._openParcelPanel({ id: p.id });
        } catch(err) { alert('خطا: '+(err?.message||'')); }
    }

    _getCurrentUser() {
        try {
            const token = sessionStorage.getItem('acc_token') || '';
            const payload = token.split('.')[1];
            const data = JSON.parse(atob(payload));
            return { id: data.user_id || data.sub || 0, name: data.name || data.display_name || 'کاربر' };
        } catch { return { id: 0, name: 'کاربر' }; }
    }

    /* ── حالت افزودن پارسل ───────────────────────────────────── */
    _enterAddMode() {
        this._addMode = true;
        this.ref('addBtn').style.display = 'none';
        this.ref('cancelAddBtn').style.display = '';
        this.ref('addHint').style.display = '';
        if (this.ref('mapEl')) this.ref('mapEl').style.cursor = 'crosshair';
    }

    _exitAddMode() {
        this._addMode = false;
        this.ref('addBtn').style.display = '';
        this.ref('cancelAddBtn').style.display = 'none';
        this.ref('addHint').style.display = 'none';
        if (this.ref('mapEl')) this.ref('mapEl').style.cursor = '';
    }

    /* ── اتصال رویدادها ──────────────────────────────────────── */
    /* ── سوئیچ لایه نقشه ────────────────────────────────────── */
    _switchTile(key) {
        if (!this._map || !this._tileLayers || key === this._activeTileKey) return;
        this._map.removeLayer(this._tileLayers[this._activeTileKey]);
        this._tileLayers[key].addTo(this._map);
        this._activeTileKey = key;
        // آپدیت دکمه‌ها
        this.ref('tileEsri')   ?.classList.toggle('gis-tile-btn--active', key === 'esri');
        this.ref('tileVoyager')?.classList.toggle('gis-tile-btn--active', key === 'voyager');
        this.ref('tileCarto')  ?.classList.toggle('gis-tile-btn--active', key === 'carto');
    }

    /* ── پانل آفلاین ─────────────────────────────────────────── */
    _showOfflinePanel() {
        const api = (window.ACC_CONFIG?.api ?? '/wp-json/acc/v1').replace(/\/+$/, '');

        const ov = document.createElement('div');
        ov.className = 'acc-modal-overlay';
        ov.innerHTML = `
        <div class="acc-modal" style="max-width:460px;">
            <button class="acc-modal__close">✕</button>
            <div class="acc-modal__title">📥 دانلود نقشه آفلاین — شیراز</div>

            <div style="background:#f0fdf4;border:1px solid #86efac;border-radius:8px;padding:12px;font-size:12px;color:#166534;margin-bottom:14px;">
                کاشی‌های نقشه برای محدوده شیراز دانلود و در سرور ذخیره می‌شوند.
                پس از دانلود، نقشه بدون نیاز به اینترنت کار می‌کند.
            </div>

            <div class="doc-form-row">
                <div class="acc-form-group">
                    <label>حداقل zoom</label>
                    <select id="_zm_min" style="padding:7px;">
                        ${[10,11,12].map(z=>`<option value="${z}" ${z===10?'selected':''}>${z}</option>`).join('')}
                    </select>
                </div>
                <div class="acc-form-group">
                    <label>حداکثر zoom</label>
                    <select id="_zm_max" style="padding:7px;">
                        ${[12,13,14,15,16,17].map(z=>`<option value="${z}" ${z===14?'selected':''}>${z}</option>`).join('')}
                    </select>
                </div>
            </div>

            <div class="acc-form-group" style="font-size:11px;color:#64748b;">
                محدوده پیش‌فرض: شیراز کامل (lat 29.35–29.85 | lng 52.25–52.95)
            </div>

            <div id="_tile_status_bar" style="padding:10px;background:#f8fafc;border-radius:8px;font-size:12px;display:none;"></div>

            <div class="acc-modal__actions">
                <button class="acc-btn acc-btn--secondary" id="_tile_status_btn">📊 وضعیت کش</button>
                <button class="acc-btn acc-btn--primary"   id="_tile_dl_btn">📥 شروع دانلود</button>
            </div>
        </div>`;

        document.body.appendChild(ov);
        const close = () => ov.remove();
        ov.querySelector('.acc-modal__close').addEventListener('click', close);
        ov.addEventListener('click', ev => { if (ev.target === ov) close(); });

        // وضعیت کش
        ov.querySelector('#_tile_status_btn').addEventListener('click', async () => {
            const bar = ov.querySelector('#_tile_status_bar');
            bar.style.display = 'block';
            bar.textContent = '⏳ در حال بررسی...';
            try {
                const r = await fetch(`${api}/tiles/status`, {
                    headers: { Authorization: `Bearer ${sessionStorage.getItem('acc_token')}` }
                }).then(r => r.json());
                bar.innerHTML = r.is_offline
                    ? `✅ <b>${r.tile_count.toLocaleString('fa-IR')}</b> کاشی در کش | حجم: <b>${r.size_kb.toLocaleString('fa-IR')} KB</b>`
                    : `⚠️ هیچ کاشی‌ای در کش نیست. دانلود را شروع کنید.`;
            } catch { bar.textContent = '❌ خطا در بررسی وضعیت'; }
        });

        // دانلود
        ov.querySelector('#_tile_dl_btn').addEventListener('click', async () => {
            const btn = ov.querySelector('#_tile_dl_btn');
            const bar = ov.querySelector('#_tile_status_bar');
            const zMin = parseInt(ov.querySelector('#_zm_min').value);
            const zMax = parseInt(ov.querySelector('#_zm_max').value);
            bar.style.display = 'block';
            bar.textContent = '⏳ در حال دانلود کاشی‌ها... (ممکن است چند دقیقه طول بکشد)';
            btn.disabled = true;
            try {
                const token = sessionStorage.getItem('acc_token');
                const res = await fetch(`${api}/tiles/download`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
                    body: JSON.stringify({
                        lat_min: 29.35, lat_max: 29.85,
                        lng_min: 52.25, lng_max: 52.95,
                        zoom_min: zMin, zoom_max: zMax,
                    }),
                }).then(r => r.json());

                if (res.success) {
                    bar.innerHTML = `✅ دانلود کامل شد!<br>
                        📥 دانلود جدید: <b>${res.downloaded}</b> |
                        ⏭ موجود: <b>${res.skipped}</b> |
                        ❌ خطا: <b>${res.failed}</b>`;
                } else {
                    bar.innerHTML = `❌ ${res.message}`;
                }
            } catch (e) {
                bar.innerHTML = `❌ خطا: ${e.message}`;
            }
            btn.disabled = false;
        });
    }

    /* ══════════════════════════════════════════════════════════
       انتخاب بلوک
    ══════════════════════════════════════════════════════════ */

    _toggleBlockMode() {
        this._blockMode = !this._blockMode;
        const btn = this.ref('blockModeBtn');
        if (this._blockMode) {
            btn.style.background    = '#dbeafe';
            btn.style.borderColor   = '#3b82f6';
            btn.style.color         = '#1d4ed8';
            btn.textContent         = '📦 حالت انتخاب بلوک (فعال)';
            if (this._map) this._map.getContainer().style.cursor = 'crosshair';
        } else {
            btn.style.background    = '';
            btn.style.borderColor   = '';
            btn.style.color         = '';
            btn.textContent         = '📦 انتخاب بلوک';
            if (this._map) this._map.getContainer().style.cursor = '';
        }
    }

    /* ── لیست لایه‌ها (LayerID) ──────────────────────────────── */
    async _loadLayersList() {
        try {
            const res = await this.api.get('/gis/layers-list');
            const list = res?.data ?? [];
            const sel = this.ref('layerFilter');
            if (!sel || !list.length) return;
            list.forEach(l => {
                const o = document.createElement('option');
                o.value = l.layer_id;
                o.textContent = `📚 لایه ${l.layer_id} (${l.parcel_count})`;
                sel.appendChild(o);
            });
        } catch {}
    }

    /* ── جستجو بر اساس کد نوسازی ────────────────────────────── */
    async _searchByCode() {
        const input = this.ref('codeSearch');
        const box   = this.ref('codeSearchResults');
        const code  = (input?.value ?? '').trim();
        if (!code) {
            this._toast('کد نوسازی را وارد کنید', '#f59e0b');
            return;
        }

        box.style.display = 'block';
        box.innerHTML = `<div style="padding:10px;color:#64748b;font-size:12px;">⏳ در حال جستجو...</div>`;

        try {
            const res = await this.api.get('/gis/search-by-code', { code });

            if (res?.match_type === 'exact' && res.parcel) {
                box.style.display = 'none';
                this._jumpToParcel(res.parcel, res.block, res.parcels);
                this._toast(`✅ پارسل ${this.escape(res.parcel.code)} پیدا شد`, '#10b981');
                return;
            }

            if (res?.match_type === 'partial' && res.matches?.length) {
                box.innerHTML = `
                    <div style="padding:8px;color:#64748b;font-size:11px;background:#f8fafc;border-bottom:1px solid #e2e8f0;">
                        💡 ${res.matches.length} نتیجه — یکی را انتخاب کنید:
                    </div>
                    ${res.matches.map(m => `
                        <div class="gis-search-result-item" data-code="${this.escape(m.code)}"
                             style="padding:8px 12px;border-bottom:1px solid #f1f5f9;cursor:pointer;font-size:12px;direction:ltr;text-align:left;">
                            <bdi>${this.escape(m.code)}</bdi>
                            ${m.address ? `<div style="font-size:10px;color:#94a3b8;margin-top:2px;direction:rtl;text-align:right;">${this.escape(m.address)}</div>` : ''}
                        </div>
                    `).join('')}
                `;
                box.querySelectorAll('.gis-search-result-item').forEach(item => {
                    item.addEventListener('mouseenter', () => item.style.background = '#eff6ff');
                    item.addEventListener('mouseleave', () => item.style.background = '');
                    item.addEventListener('click', () => {
                        input.value = item.dataset.code;
                        this._searchByCode();
                    });
                });
                return;
            }

            box.innerHTML = `<div style="padding:12px;color:#ef4444;font-size:12px;text-align:center;">❌ پارسلی با این کد یافت نشد</div>`;
            setTimeout(() => { box.style.display = 'none'; }, 2500);
        } catch (e) {
            box.innerHTML = `<div style="padding:12px;color:#ef4444;font-size:12px;">❌ خطا در جستجو</div>`;
        }
    }

    /** پرش به یک پارسل + نمایش بلوک آن + باز کردن پانل جزئیات */
    _jumpToParcel(parcel, blockCode, parcels) {
        const L = window.L;
        if (!L || !this._map) return;

        const lat = parseFloat(parcel.lat);
        const lng = parseFloat(parcel.lng);

        // اگر این بلوک قبلاً نمایش داده نشده، آن را نمایش بده
        if (blockCode && !this._selectedBlocks.has(blockCode) && parcels?.length) {
            this._renderBlockData(blockCode, parcels);
        }

        // zoom به مختصات پارسل
        if (!isNaN(lat) && !isNaN(lng)) {
            this._map.setView([lat, lng], 18, { animate: true });

            // یک marker موقت چشمک‌زن
            const highlight = L.circleMarker([lat, lng], {
                radius: 18, color: '#ef4444', weight: 4, fillColor: '#fbbf24', fillOpacity: 0.6,
            }).addTo(this._map);

            // pulse animation
            let r = 18, dir = 1;
            const pulse = setInterval(() => {
                r += dir; if (r > 24 || r < 14) dir = -dir;
                highlight.setRadius(r);
            }, 60);
            setTimeout(() => { clearInterval(pulse); this._map.removeLayer(highlight); }, 3000);
        }

        // باز کردن پانل جزئیات
        this._openParcelPanel(parcel);
    }

    /* ── بازسازی index بلوک‌ها ─────────────────────────────── */
    async _rebuildBlocks() {
        if (!confirm("بازسازی index بلوک‌ها (چند ثانیه طول می‌کشد)؟")) return;
        const btn = this.ref('rebuildBtn');
        if (btn) { btn.disabled = true; btn.textContent = "⏳ بازسازی..."; }
        try {
            const res = await this.api.post('/gis/rebuild-blocks', {});
            this._toast(`✅ ${res?.blocks_count ?? 0} بلوک بازسازی شد`, '#10b981');
        } catch(e) {
            this._toast('❌ خطا در بازسازی', '#ef4444');
        } finally {
            if (btn) { btn.disabled = false; btn.textContent = "🔧 بازسازی index"; }
        }
    }

    /* ── کلیک روی نقشه → نزدیک‌ترین بلوک ──────────────────── */
    async _loadBlockByClick(lat, lng) {
        this._toast('🔍 جستجوی نزدیک‌ترین بلوک...', '#6366f1');
        try {
            const params = { lat, lng };
            if (this._activeLayerId) params.layer_id = this._activeLayerId;
            const res = await this.api.get('/gis/parcels-by-click', params);
            if (!res?.block) {
                this._toast('⚠️ بلوکی در این ناحیه یافت نشد', '#f59e0b');
                return;
            }
            if (this._selectedBlocks.has(res.block)) {
                this._removeBlock(res.block);
                return;
            }
            this._renderBlockData(res.block, res.parcels ?? []);
        } catch(e) {
            this._toast('❌ خطا در جستجوی بلوک', '#ef4444');
        }
    }

    _renderBlockData(blockCode, parcels, skipSave = false) {
        const L     = window.L;
        const color = BLOCK_PALETTE[this._blockColorIdx % BLOCK_PALETTE.length];
        this._blockColorIdx++;

        const layerGroup = L.layerGroup().addTo(this._map);
        this._selectedBlocks.set(blockCode, { color, layerGroup, parcels });

        parcels.forEach(p => {
            if (!p.lat || !p.lng) return;

            // polygon
            if (p.geometry) {
                try {
                    const geo = typeof p.geometry === 'string' ? JSON.parse(p.geometry) : p.geometry;
                    L.geoJSON(geo, {
                        style: { color, weight: 2, fillColor: color, fillOpacity: 0.25 }
                    }).addTo(layerGroup);
                } catch {}
            }

            // marker
            const m = L.circleMarker([parseFloat(p.lat), parseFloat(p.lng)], {
                radius: 7, fillColor: color, color: '#fff', weight: 2, fillOpacity: 0.9,
            });
            m.bindTooltip(`<b>${p.code || '—'}</b><br>بلوک: ${blockCode}`,
                { direction: 'top', offset: [0, -8] });
            m.on('click', () => this._openParcelPanel(p));
            m.addTo(layerGroup);
        });

        this._updateBlockBar();

        if (!skipSave) {
            this._saveSelectedBlocks();
            this._toast(`✅ بلوک ${blockCode}: ${parcels.length} پارسل`, color);

            // zoom به محدوده بلوک — فقط هنگام انتخاب جدید
            if (parcels.length && this._map) {
                const lats = parcels.map(p => parseFloat(p.lat)).filter(Boolean);
                const lngs = parcels.map(p => parseFloat(p.lng)).filter(Boolean);
                if (lats.length) {
                    this._map.fitBounds(
                        L.latLngBounds([Math.min(...lats), Math.min(...lngs)],
                                       [Math.max(...lats), Math.max(...lngs)]),
                        { padding: [40, 40], maxZoom: 17 }
                    );
                }
            }
        }
    }

    async _selectBlock(blockCode, sampleParcel) {
        if (!blockCode) return;

        // اگر قبلاً انتخاب شده → حذف کن
        if (this._selectedBlocks.has(blockCode)) {
            this._removeBlock(blockCode);
            return;
        }

        // رنگ جدید
        const color = BLOCK_PALETTE[this._blockColorIdx % BLOCK_PALETTE.length];
        this._blockColorIdx++;

        // لایه گروه جدید
        const L = window.L;
        const layerGroup = L.layerGroup().addTo(this._map);

        // نگهداری در map
        this._selectedBlocks.set(blockCode, { color, layerGroup, parcels: [] });
        this._updateBlockBar();

        // نمایش placeholder
        this._toast(`📦 بارگذاری بلوک ${blockCode}...`, color);

        try {
            const params = { block: blockCode, per_page: 500 };
            if (this._activeLayerId) params.layer_id = this._activeLayerId;
            const res = await this.api.get('/gis/parcels', params);
            const parcels = res?.data ?? [];

            this._selectedBlocks.get(blockCode).parcels = parcels;

            parcels.forEach(p => {
                if (!p.lat || !p.lng) return;

                // نمایش polygon اگر geometry دارد
                if (p.geometry) {
                    try {
                        const geo = typeof p.geometry === 'string'
                            ? JSON.parse(p.geometry) : p.geometry;
                        L.geoJSON(geo, {
                            style: { color, weight: 2, fillColor: color, fillOpacity: 0.25 }
                        }).addTo(layerGroup);
                    } catch {}
                }

                // marker
                const m = L.circleMarker([parseFloat(p.lat), parseFloat(p.lng)], {
                    radius: 7, fillColor: color, color: '#fff',
                    weight: 2, fillOpacity: 0.9,
                });
                m.bindTooltip(
                    `<b>${p.code || '—'}</b><br>بلوک: ${blockCode}`,
                    { direction: 'top', offset: [0,-8] }
                );
                m.on('click', () => this._openParcelPanel(p));
                m.addTo(layerGroup);
            });

            this._updateBlockBar();
            this._toast(`✅ بلوک ${blockCode}: ${parcels.length} پارسل`, color);
        } catch(e) {
            this._toast(`❌ خطا در بارگذاری بلوک ${blockCode}`, '#ef4444');
        }
    }

    _removeBlock(blockCode) {
        const entry = this._selectedBlocks.get(blockCode);
        if (!entry) return;
        if (this._map && entry.layerGroup) {
            this._map.removeLayer(entry.layerGroup);
        }
        this._selectedBlocks.delete(blockCode);
        this._updateBlockBar();
        this._saveSelectedBlocks();
    }

    _clearAllBlocks() {
        for (const [code, entry] of this._selectedBlocks) {
            if (this._map && entry.layerGroup) this._map.removeLayer(entry.layerGroup);
        }
        this._selectedBlocks.clear();
        this._updateBlockBar();
        this._saveSelectedBlocks();
    }

    _updateBlockBar() {
        const bar   = this.ref('blockBar');
        const chips = this.ref('blockChips');
        if (!bar || !chips) return;

        if (this._selectedBlocks.size === 0) {
            bar.style.display = 'none';
            return;
        }

        bar.style.display = 'flex';
        chips.innerHTML = '';

        for (const [code, entry] of this._selectedBlocks) {
            const count = entry.parcels.length;
            const chip  = document.createElement('div');
            chip.className = 'gis-block-chip';
            chip.style.cssText = `
                display:inline-flex;align-items:center;gap:4px;
                background:${entry.color}22;border:1.5px solid ${entry.color};
                color:${entry.color};border-radius:20px;
                padding:2px 10px;font-size:11px;font-weight:700;
                cursor:pointer;white-space:nowrap;
            `;
            chip.innerHTML = `
                <span style="width:8px;height:8px;border-radius:50%;
                    background:${entry.color};display:inline-block;"></span>
                ${this.escape(code)}
                ${count ? `<span style="opacity:.7;">(${count})</span>` : ''}
                <span class="gis-block-chip-remove" style="margin-right:2px;font-size:13px;
                    line-height:1;opacity:.7;">✕</span>
            `;
            chip.querySelector('.gis-block-chip-remove')
                .addEventListener('click', e => { e.stopPropagation(); this._removeBlock(code); });
            chips.appendChild(chip);
        }
    }

    _bindToolbar() {
        this.on(this.ref('addBtn'),       'click', () => this._enterAddMode());
        this.on(this.ref('cancelAddBtn'), 'click', () => this._exitAddMode());
        this.on(this.ref('refreshBtn'),   'click', async () => { await this._loadMapData(); this._toast('🔄 نقشه به‌روزرسانی شد','#3b82f6'); });
        this.on(this.ref('offlineBtn'),     'click', () => this._showOfflinePanel());
        this.on(this.ref('tileEsri'),      'click', () => this._switchTile('esri'));
        this.on(this.ref('tileVoyager'),   'click', () => this._switchTile('voyager'));
        this.on(this.ref('tileCarto'),     'click', () => this._switchTile('carto'));
        this.on(this.ref('blockModeBtn'),  'click', () => this._toggleBlockMode());
        this.on(this.ref('clearBlocksBtn'),'click', () => this._clearAllBlocks());
        this.on(this.ref('rebuildBtn'),    'click', () => this._rebuildBlocks());
        this.on(this.ref('codeSearchBtn'), 'click', () => this._searchByCode());

        // ناوبری بخش‌های GIS (نقشه / پرونده‌ها / لایه‌ها / نقشه عمومی)
        this.container.querySelectorAll('[data-section-nav]').forEach(btn =>
            btn.addEventListener('click', () => {
                const key = btn.dataset.sectionNav;
                if (this.gisView && typeof this.gisView._switch === 'function') {
                    this.gisView._switch(key);
                }
            })
        );

        // toggle tools panel (drawer آکاردیونی)
        this.on(this.ref('toolsBtn'), 'click', () => {
            const panel = this.ref('toolsPanel');
            const isOpen = panel.style.display !== 'none';
            panel.style.display = isOpen ? 'none' : 'block';
            this.ref('toolsBtn').textContent = isOpen ? '⚙️ ابزارها' : '✕ بستن ابزارها';
        });

        // layer filter
        this.on(this.ref('layerFilter'), 'change', () => {
            this._activeLayerId = this.ref('layerFilter').value || null;
            this._toast(this._activeLayerId
                ? `📚 لایه فعال: ${this._activeLayerId}`
                : '📚 همه لایه‌ها', '#3b82f6');
        });

        // لیست لایه‌ها
        this._loadLayersList();
        // Enter در input → جستجو
        this.on(this.ref('codeSearch'), 'keydown', (e) => {
            if (e.key === 'Enter') { e.preventDefault(); this._searchByCode(); }
        });
        // کلیک بیرون از نتایج → بستن dropdown
        document.addEventListener('click', (e) => {
            const box = this.ref('codeSearchResults');
            if (box && !box.contains(e.target) && e.target !== this.ref('codeSearch')) {
                box.style.display = 'none';
            }
        });

        // فیلتر وضعیت
        this.container.querySelectorAll('.gis-filter-btn').forEach(btn => {
            btn.addEventListener('click', () => {
                this.container.querySelectorAll('.gis-filter-btn').forEach(b => b.classList.remove('gis-filter-btn--active'));
                btn.classList.add('gis-filter-btn--active');
                this._activeFilter = btn.dataset.filter || 'all';
                this._renderParcels();
            });
        });

        // لایه‌ها
        this.container.querySelectorAll('.gis-layer-toggle input').forEach(chk => {
            chk.addEventListener('change', () => {
                const key = chk.dataset.layer;
                const lyr = this._layers[key];
                if (!lyr || !this._map) return;
                if (chk.checked) lyr.addTo(this._map);
                else this._map.removeLayer(lyr);
            });
        });
    }

    /* ── helpers ──────────────────────────────────────────────── */
    _updateCountLabel() {
        const lbl = this.ref('countLbl');
        if (!lbl) return;
        const filtered = this._activeFilter === 'all'
            ? this._mapData.parcels : this._mapData.parcels.filter(p => p.status === this._activeFilter);
        lbl.textContent = `📁 ${filtered.length} پارسل`;
    }

    _fmt(v) { return new Intl.NumberFormat('fa-IR').format(Math.round(Number(v ?? 0))); }

    /** تبدیل تاریخ میلادی (YYYY-MM-DD یا ISO) به شمسی */
    _jalali(d) {
        if (!d) return '';
        try {
            const date = new Date(d);
            if (isNaN(date.getTime())) return d;
            return new Intl.DateTimeFormat('fa-IR-u-ca-persian', {
                year: 'numeric', month: '2-digit', day: '2-digit'
            }).format(date);
        } catch { return d; }
    }

    _toast(msg, bg = '#10b981') {
        const t = document.createElement('div');
        t.style.cssText = `position:fixed;bottom:24px;left:24px;background:${bg};color:#fff;padding:12px 20px;border-radius:10px;font-size:13px;font-weight:600;z-index:9999;box-shadow:0 4px 20px rgba(0,0,0,.15);max-width:340px;direction:rtl;`;
        t.textContent = msg;
        document.body.appendChild(t);
        setTimeout(() => t.remove(), 3500);
    }

    destroy() {
        if (this._map) { this._map.remove(); this._map = null; }
        super.destroy();
    }
}
