"""Tab 3: Merge multiple SHP files into a single KML/KMZ.

Provides full label/popup/style configuration per geometry type
(Point, Line, Polygon), matching Tab 1 capabilities.
"""

import os
from qgis.PyQt.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QTabWidget,
    QLabel, QComboBox, QLineEdit, QPushButton, QSpinBox,
    QFileDialog, QMessageBox, QTableWidget, QTableWidgetItem,
    QHeaderView, QCheckBox, QColorDialog, QGroupBox,
    QSlider, QScrollArea, QFrame, QDoubleSpinBox, QSplitter
)
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtGui import QColor
from qgis.core import QgsProject, QgsVectorLayer, QgsWkbTypes
from .merge_builder import MergeKmlBuilder


# ── Geometry-type config panel ────────────────────────

class _GeomConfigPanel(QWidget):
    """Reusable config panel for one geometry type (point/line/polygon)."""

    def __init__(self, geom_key, parent=None):
        super().__init__(parent)
        self.geom_key = geom_key  # 'point', 'line', 'polygon'
        self._fields = []  # list of field names from loaded SHPs
        self._setup_ui()

    # ── UI construction ───────────────────────────────

    def _setup_ui(self):
        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setFrameShape(QFrame.NoFrame)
        inner = QWidget()
        ly = QVBoxLayout(inner)
        scroll.setWidget(inner)
        outer = QVBoxLayout(self)
        outer.setContentsMargins(0, 0, 0, 0)
        outer.addWidget(scroll)

        # 1 — Name settings
        gp_name = QGroupBox("Nhãn (Label)")
        n_ly = QHBoxLayout()
        self.chk_f1 = QCheckBox("F1:")
        self.chk_f1.setChecked(True)
        self.cbo_f1 = QComboBox()
        self.txt_sep = QLineEdit(" - ")
        self.txt_sep.setFixedWidth(50)
        self.chk_f2 = QCheckBox("F2:")
        self.cbo_f2 = QComboBox()
        self.spn_size = QSpinBox()
        self.spn_size.setRange(8, 72)
        self.spn_size.setValue(12)
        self.btn_name_clr = QPushButton("#000000")
        self.btn_name_clr.setFixedWidth(70)
        self.btn_name_clr.setStyleSheet(
            "background:#000000;color:white")
        self.btn_name_clr.clicked.connect(
            lambda: self._pick(self.btn_name_clr))
        n_ly.addWidget(self.chk_f1)
        n_ly.addWidget(self.cbo_f1, 1)
        n_ly.addWidget(QLabel("Sep:"))
        n_ly.addWidget(self.txt_sep)
        n_ly.addWidget(self.chk_f2)
        n_ly.addWidget(self.cbo_f2, 1)
        n_ly.addWidget(QLabel("Size:"))
        n_ly.addWidget(self.spn_size)
        n_ly.addWidget(self.btn_name_clr)
        gp_name.setLayout(n_ly)
        ly.addWidget(gp_name)

        # 2 — Popup fields
        gp_popup = QGroupBox("Popup (Fields)")
        p_ly = QVBoxLayout()
        btn_row = QHBoxLayout()
        self.btn_chk_all = QPushButton("✅ All")
        self.btn_chk_all.setFixedWidth(70)
        self.btn_chk_all.clicked.connect(self._check_all)
        self.btn_unchk = QPushButton("❎ None")
        self.btn_unchk.setFixedWidth(70)
        self.btn_unchk.clicked.connect(self._uncheck_all)
        btn_row.addWidget(self.btn_chk_all)
        btn_row.addWidget(self.btn_unchk)
        btn_row.addStretch()
        self.btn_up = QPushButton("↑")
        self.btn_up.setFixedWidth(30)
        self.btn_up.clicked.connect(self._move_up)
        self.btn_down = QPushButton("↓")
        self.btn_down.setFixedWidth(30)
        self.btn_down.clicked.connect(self._move_down)
        btn_row.addWidget(self.btn_up)
        btn_row.addWidget(self.btn_down)
        p_ly.addLayout(btn_row)
        self.tbl_fields = QTableWidget(0, 4)
        self.tbl_fields.setHorizontalHeaderLabels(
            ["√", "Field", "Alias", "Unit"])
        self.tbl_fields.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        self.tbl_fields.setMinimumHeight(120)
        p_ly.addWidget(self.tbl_fields)
        gp_popup.setLayout(p_ly)
        ly.addWidget(gp_popup)

        # 3 — Style (geometry-dependent)
        gp_style = QGroupBox("Style")
        s_ly = QHBoxLayout()

        if self.geom_key == 'point':
            s_ly.addWidget(QLabel("Icon:"))
            self.btn_icon_clr = QPushButton("#FF4444")
            self.btn_icon_clr.setStyleSheet("background:#FF4444")
            self.btn_icon_clr.clicked.connect(
                lambda: self._pick(self.btn_icon_clr))
            s_ly.addWidget(self.btn_icon_clr)
            s_ly.addWidget(QLabel("Scale:"))
            self.spn_icon_scale = QDoubleSpinBox()
            self.spn_icon_scale.setRange(0.3, 5.0)
            self.spn_icon_scale.setSingleStep(0.1)
            self.spn_icon_scale.setValue(1.0)
            s_ly.addWidget(self.spn_icon_scale)

        elif self.geom_key == 'line':
            s_ly.addWidget(QLabel("Color:"))
            self.btn_line_clr = QPushButton("#0000FF")
            self.btn_line_clr.setStyleSheet("background:#0000FF")
            self.btn_line_clr.clicked.connect(
                lambda: self._pick(self.btn_line_clr))
            s_ly.addWidget(self.btn_line_clr)
            s_ly.addWidget(QLabel("Width:"))
            self.spn_line_w = QSpinBox()
            self.spn_line_w.setRange(1, 20)
            self.spn_line_w.setValue(2)
            s_ly.addWidget(self.spn_line_w)

        else:  # polygon
            s_ly.addWidget(QLabel("Border:"))
            self.btn_border = QPushButton("#FF0000")
            self.btn_border.setStyleSheet("background:#FF0000")
            self.btn_border.clicked.connect(
                lambda: self._pick(self.btn_border))
            s_ly.addWidget(self.btn_border)
            s_ly.addWidget(QLabel("W:"))
            self.spn_bw = QSpinBox()
            self.spn_bw.setRange(1, 20)
            self.spn_bw.setValue(2)
            s_ly.addWidget(self.spn_bw)
            s_ly.addWidget(QLabel("Fill:"))
            self.btn_fill = QPushButton("#00FF00")
            self.btn_fill.setStyleSheet("background:#00FF00")
            self.btn_fill.clicked.connect(
                lambda: self._pick(self.btn_fill))
            s_ly.addWidget(self.btn_fill)
            s_ly.addWidget(QLabel("Op:"))
            self.sld_op = QSlider(Qt.Horizontal)
            self.sld_op.setRange(0, 100)
            self.sld_op.setValue(50)
            s_ly.addWidget(self.sld_op)

        gp_style.setLayout(s_ly)
        ly.addWidget(gp_style)

        # 4 — Header
        gp_hdr = QGroupBox("Header Popup")
        h_ly = QHBoxLayout()
        h_ly.addWidget(QLabel("Title:"))
        self.txt_header = QLineEdit("Thông tin")
        h_ly.addWidget(self.txt_header, 1)
        self.btn_hdr_bg = QPushButton("#1B5E20")
        self.btn_hdr_bg.setStyleSheet("background:#1B5E20")
        self.btn_hdr_bg.clicked.connect(
            lambda: self._pick(self.btn_hdr_bg))
        h_ly.addWidget(self.btn_hdr_bg)
        gp_hdr.setLayout(h_ly)
        ly.addWidget(gp_hdr)

        ly.addStretch()

    # ── Public methods ────────────────────────────────

    def set_fields(self, field_names):
        """Update combos and field table from a list of field names."""
        self._fields = list(field_names)
        self.cbo_f1.clear()
        self.cbo_f1.addItems(self._fields)
        self.cbo_f2.clear()
        self.cbo_f2.addItems(self._fields)
        self.tbl_fields.setRowCount(0)
        for i, fn in enumerate(self._fields):
            self.tbl_fields.insertRow(i)
            chk = QCheckBox()
            chk.setChecked(True)
            self.tbl_fields.setCellWidget(i, 0, chk)
            self.tbl_fields.setItem(i, 1, QTableWidgetItem(fn))
            self.tbl_fields.setItem(i, 2, QTableWidgetItem(fn))
            self.tbl_fields.setItem(i, 3, QTableWidgetItem(""))

    def get_config(self):
        """Return config dict compatible with MergeKmlBuilder."""
        # Name fields
        name_cfg = {
            'field1': self.cbo_f1.currentText(),
            'field1_enabled': self.chk_f1.isChecked(),
            'field2': self.cbo_f2.currentText(),
            'field2_enabled': self.chk_f2.isChecked(),
            'separator': self.txt_sep.text(),
            'font_size': self.spn_size.value(),
            'font_color': self.btn_name_clr.text(),
        }
        # Description fields
        desc = []
        for i in range(self.tbl_fields.rowCount()):
            chk = self.tbl_fields.cellWidget(i, 0)
            if chk and chk.isChecked():
                fi = self.tbl_fields.item(i, 1)
                ai = self.tbl_fields.item(i, 2)
                si = self.tbl_fields.item(i, 3)
                if fi and ai:
                    desc.append({
                        'field': fi.text(),
                        'alias': ai.text(),
                        'suffix': si.text() if si else '',
                        'order': i,
                    })
        # Style
        cfg = {
            'name_fields': name_cfg,
            'description_fields': desc,
            'header': {
                'title': self.txt_header.text(),
                'bg_color': self.btn_hdr_bg.text(),
                'text_color': '#FFFFFF',
                'bold': True,
                'font_size': 14,
            },
            'row_highlights': {'enabled': False, 'rules': []},
        }
        if self.geom_key == 'point':
            cfg['point_style'] = {
                'icon_color': self.btn_icon_clr.text(),
                'icon_scale': self.spn_icon_scale.value(),
            }
        elif self.geom_key == 'line':
            cfg['line_style'] = {
                'line_color': self.btn_line_clr.text(),
                'line_width': self.spn_line_w.value(),
            }
        else:
            cfg['polygon_style'] = {
                'border_color': self.btn_border.text(),
                'border_width': self.spn_bw.value(),
                'fill_color': self.btn_fill.text(),
                'fill_opacity': self.sld_op.value(),
            }
        return cfg

    def update_labels(self, lang):
        """Update UI text for bilingual support."""
        is_vi = lang == 'vi'
        # Labels are mostly self-explanatory icons; update groupboxes
        for gp in self.findChildren(QGroupBox):
            t = gp.title()
            if 'Label' in t or 'Nhãn' in t:
                gp.setTitle("Nhãn (Label)" if is_vi else "Label")
            elif 'Popup' in t:
                gp.setTitle(
                    "Popup (Trường dữ liệu)" if is_vi else "Popup (Fields)")
            elif 'Style' in t:
                gp.setTitle("Kiểu dáng" if is_vi else "Style")
            elif 'Header' in t:
                gp.setTitle(
                    "Tiêu đề Popup" if is_vi else "Popup Header")

    # ── Private helpers ───────────────────────────────

    def _pick(self, btn):
        c = QColorDialog.getColor(QColor(btn.text()))
        if c.isValid():
            btn.setText(c.name())
            btn.setStyleSheet(f"background-color:{c.name()}")

    def _check_all(self):
        for i in range(self.tbl_fields.rowCount()):
            chk = self.tbl_fields.cellWidget(i, 0)
            if chk:
                chk.setChecked(True)

    def _uncheck_all(self):
        for i in range(self.tbl_fields.rowCount()):
            chk = self.tbl_fields.cellWidget(i, 0)
            if chk:
                chk.setChecked(False)

    def _move_up(self):
        row = self.tbl_fields.currentRow()
        if row <= 0:
            return
        self._swap_rows(row, row - 1)
        self.tbl_fields.setCurrentCell(row - 1, 0)

    def _move_down(self):
        row = self.tbl_fields.currentRow()
        if row < 0 or row >= self.tbl_fields.rowCount() - 1:
            return
        self._swap_rows(row, row + 1)
        self.tbl_fields.setCurrentCell(row + 1, 0)

    def _swap_rows(self, r1, r2):
        self.tbl_fields.blockSignals(True)
        chk1 = self.tbl_fields.cellWidget(r1, 0)
        chk2 = self.tbl_fields.cellWidget(r2, 0)
        c1 = chk1.isChecked() if chk1 else True
        c2 = chk2.isChecked() if chk2 else True
        vals1 = [self.tbl_fields.item(r1, c).text()
                 if self.tbl_fields.item(r1, c) else ''
                 for c in range(1, 4)]
        vals2 = [self.tbl_fields.item(r2, c).text()
                 if self.tbl_fields.item(r2, c) else ''
                 for c in range(1, 4)]
        new1 = QCheckBox()
        new1.setChecked(c2)
        new2 = QCheckBox()
        new2.setChecked(c1)
        self.tbl_fields.setCellWidget(r1, 0, new1)
        self.tbl_fields.setCellWidget(r2, 0, new2)
        for c in range(1, 4):
            self.tbl_fields.setItem(r1, c, QTableWidgetItem(vals2[c - 1]))
            self.tbl_fields.setItem(r2, c, QTableWidgetItem(vals1[c - 1]))
        self.tbl_fields.blockSignals(False)


# ── Main Merge Tab widget ─────────────────────────────

class MergeTabWidget(QWidget):
    """Complete Tab 3 widget for merging multiple SHP → 1 KML/KMZ."""

    GEOM_LABELS = {
        QgsWkbTypes.PointGeometry: ('point', '🔵 Điểm (Point)'),
        QgsWkbTypes.LineGeometry: ('line', '🟢 Đường (Line)'),
        QgsWkbTypes.PolygonGeometry: ('polygon', '🟡 Vùng (Polygon)'),
    }

    def __init__(self, lang='vi', parent=None):
        super().__init__(parent)
        self.lang = lang
        self._shp_paths = []   # list of absolute paths
        self._shp_infos = []   # list of (basename, geom_key)
        self._initialized = False
        # Lightweight placeholder until first activation
        self._placeholder_ly = QVBoxLayout(self)
        self._placeholder_ly.addWidget(
            QLabel("⏳ Nhấn vào tab để bắt đầu..."))
        self._placeholder_ly.addStretch()

    def ensure_initialized(self):
        """Lazy-build UI on first access — avoids slow dialog open."""
        if self._initialized:
            return
        self._initialized = True
        # Remove placeholder
        while self._placeholder_ly.count():
            item = self._placeholder_ly.takeAt(0)
            w = item.widget()
            if w:
                w.deleteLater()
        ly = self._placeholder_ly  # reuse existing layout

        # ── File list section ─────────────────────────
        gp_files = QGroupBox("1. Chọn file SHP")
        fl = QVBoxLayout()
        btn_row = QHBoxLayout()
        self.btn_add = QPushButton("➕ Thêm SHP")
        self.btn_add.clicked.connect(self._add_shp)
        self.btn_add_canvas = QPushButton("🗺 Lấy từ QGIS")
        self.btn_add_canvas.setStyleSheet(
            "QPushButton{background:#1565C0;color:#fff;"
            "font-weight:bold;padding:4px 10px;border-radius:3px}"
            "QPushButton:hover{background:#1976D2}")
        self.btn_add_canvas.clicked.connect(self._add_from_canvas)
        self.btn_remove = QPushButton("➖ Xóa")
        self.btn_remove.clicked.connect(self._remove_shp)
        self.btn_clear = QPushButton("🗑 Xóa hết")
        self.btn_clear.clicked.connect(self._clear_shp)
        btn_row.addWidget(self.btn_add)
        btn_row.addWidget(self.btn_add_canvas)
        btn_row.addWidget(self.btn_remove)
        btn_row.addWidget(self.btn_clear)
        btn_row.addStretch()
        fl.addLayout(btn_row)

        self.tbl_files = QTableWidget(0, 3)
        self.tbl_files.setHorizontalHeaderLabels(
            ["File", "Geometry", "Path"])
        self.tbl_files.horizontalHeader().setSectionResizeMode(
            0, QHeaderView.Stretch)
        self.tbl_files.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.ResizeToContents)
        self.tbl_files.horizontalHeader().setSectionResizeMode(
            2, QHeaderView.Stretch)
        self.tbl_files.setMinimumHeight(80)
        self.tbl_files.clicked.connect(self._on_file_clicked)
        fl.addWidget(self.tbl_files)

        self.lbl_summary = QLabel("")
        self.lbl_summary.setStyleSheet("color:#555;font-size:11px")
        fl.addWidget(self.lbl_summary)
        gp_files.setLayout(fl)

        # ── Splitter: file list (top) + config (bottom) ──
        splitter = QSplitter(Qt.Vertical)
        splitter.addWidget(gp_files)

        # ── Per-geometry config tabs ──────────────────
        gp_cfg = QGroupBox("2. Thiết lập theo loại đối tượng")
        cfg_ly = QVBoxLayout()
        self.geom_tabs = QTabWidget()
        self.panel_point = _GeomConfigPanel('point')
        self.panel_line = _GeomConfigPanel('line')
        self.panel_poly = _GeomConfigPanel('polygon')
        self.geom_tabs.addTab(
            self.panel_point, "🔵 Điểm (Point)")
        self.geom_tabs.addTab(
            self.panel_line, "🟢 Đường (Line)")
        self.geom_tabs.addTab(
            self.panel_poly, "🟡 Vùng (Polygon)")
        cfg_ly.addWidget(self.geom_tabs)
        gp_cfg.setLayout(cfg_ly)
        splitter.addWidget(gp_cfg)
        splitter.setStretchFactor(0, 1)  # file list
        splitter.setStretchFactor(1, 3)  # config area
        ly.addWidget(splitter)

        # ── Export button ─────────────────────────────
        self.btn_export = QPushButton("🚀 XUẤT KML / KMZ")
        self.btn_export.setMinimumHeight(45)
        self.btn_export.setStyleSheet(
            "background:#1B5E20;color:white;"
            "font-weight:bold;border-radius:5px;font-size:14px")
        self.btn_export.clicked.connect(self._export)
        ly.addWidget(self.btn_export)

    # ── Public ────────────────────────────────────────

    def refresh_geom_tabs(self):
        """Re-populate field combos in each geometry panel."""
        self.ensure_initialized()
        self._refresh_fields()

    def update_labels(self, lang):
        """Update bilingual labels."""
        self.lang = lang
        if not self._initialized:
            return
        is_vi = lang == 'vi'
        self.btn_add.setText(
            "➕ Thêm SHP" if is_vi else "➕ Add SHP")
        self.btn_add_canvas.setText(
            "🗺 Lấy từ QGIS" if is_vi else "🗺 From QGIS")
        self.btn_remove.setText(
            "➖ Xóa" if is_vi else "➖ Remove")
        self.btn_clear.setText(
            "🗑 Xóa hết" if is_vi else "🗑 Clear")
        self.btn_export.setText(
            "🚀 XUẤT KML / KMZ" if is_vi
            else "🚀 EXPORT KML / KMZ")
        # Group box titles
        for gp in self.findChildren(QGroupBox):
            t = gp.title()
            if 'SHP' in t or 'file' in t.lower():
                gp.setTitle(
                    "1. Chọn file SHP" if is_vi
                    else "1. Select SHP Files")
            elif 'loại' in t or 'geometry' in t.lower():
                gp.setTitle(
                    "2. Thiết lập theo loại đối tượng" if is_vi
                    else "2. Config by Geometry Type")
        self.panel_point.update_labels(lang)
        self.panel_line.update_labels(lang)
        self.panel_poly.update_labels(lang)

    # ── Private ───────────────────────────────────────

    def _on_file_clicked(self, index):
        """Auto-switch geometry tab when clicking a layer row."""
        row = index.row()
        if row < 0 or row >= len(self._shp_infos):
            return
        _, gk = self._shp_infos[row]
        tab_map = {'point': 0, 'line': 1, 'polygon': 2}
        self.geom_tabs.setCurrentIndex(tab_map.get(gk, 0))

    def _add_shp(self):
        paths, _ = QFileDialog.getOpenFileNames(
            self,
            "Chọn file SHP" if self.lang == 'vi' else "Select SHP",
            "", "Shapefile (*.shp)")
        if not paths:
            return
        for p in paths:
            if p in self._shp_paths:
                continue
            bn = os.path.splitext(os.path.basename(p))[0]
            layer = QgsVectorLayer(p, bn, 'ogr')
            if not layer.isValid():
                continue
            gt = layer.geometryType()
            info = self.GEOM_LABELS.get(gt)
            if info is None:
                continue
            gk, glabel = info
            self._shp_paths.append(p)
            self._shp_infos.append((bn, gk))
            row = self.tbl_files.rowCount()
            self.tbl_files.insertRow(row)
            item_name = QTableWidgetItem(bn)
            item_name.setFlags(
                item_name.flags() & ~Qt.ItemIsEditable)
            self.tbl_files.setItem(row, 0, item_name)
            item_geom = QTableWidgetItem(glabel)
            item_geom.setFlags(
                item_geom.flags() & ~Qt.ItemIsEditable)
            self.tbl_files.setItem(row, 1, item_geom)
            item_path = QTableWidgetItem(p)
            item_path.setFlags(
                item_path.flags() & ~Qt.ItemIsEditable)
            self.tbl_files.setItem(row, 2, item_path)
        self._update_summary()
        self._refresh_fields()

    def _add_from_canvas(self):
        """Import vector layers currently loaded in QGIS map canvas."""
        added = 0
        for layer in QgsProject.instance().mapLayers().values():
            if not isinstance(layer, QgsVectorLayer):
                continue
            src = layer.source()
            if not src:
                continue
            # Handle GPKG paths: "/path/file.gpkg|layername=xxx"
            base_src = src.split('|')[0] if '|' in src else src
            if not os.path.exists(base_src):
                continue
            if src in self._shp_paths:
                continue
            gt = layer.geometryType()
            info = self.GEOM_LABELS.get(gt)
            if info is None:
                continue
            gk, glabel = info
            bn = layer.name()
            self._shp_paths.append(src)
            self._shp_infos.append((bn, gk))
            row = self.tbl_files.rowCount()
            self.tbl_files.insertRow(row)
            item_name = QTableWidgetItem(bn)
            item_name.setFlags(
                item_name.flags() & ~Qt.ItemIsEditable)
            self.tbl_files.setItem(row, 0, item_name)
            item_geom = QTableWidgetItem(glabel)
            item_geom.setFlags(
                item_geom.flags() & ~Qt.ItemIsEditable)
            self.tbl_files.setItem(row, 1, item_geom)
            # Show short path
            item_path = QTableWidgetItem(
                os.path.basename(base_src))
            item_path.setFlags(
                item_path.flags() & ~Qt.ItemIsEditable)
            item_path.setToolTip(src)
            self.tbl_files.setItem(row, 2, item_path)
            added += 1
        if added == 0:
            QMessageBox.information(
                self,
                "Info",
                "Không tìm thấy layer SHP nào trên bản đồ!"
                if self.lang == 'vi'
                else "No SHP layers found in map canvas!")
        else:
            self._update_summary()
            self._refresh_fields()

    def _remove_shp(self):
        row = self.tbl_files.currentRow()
        if row < 0:
            return
        self._shp_paths.pop(row)
        self._shp_infos.pop(row)
        self.tbl_files.removeRow(row)
        self._update_summary()
        self._refresh_fields()

    def _clear_shp(self):
        self._shp_paths.clear()
        self._shp_infos.clear()
        self.tbl_files.setRowCount(0)
        self._update_summary()
        self._refresh_fields()

    def _refresh_fields(self):
        """Re-scan all loaded SHPs and update geometry panel fields."""
        pt_fields, ln_fields, pg_fields = set(), set(), set()
        for path, (_, gk) in zip(self._shp_paths, self._shp_infos):
            layer = QgsVectorLayer(path, 'tmp', 'ogr')
            if not layer.isValid():
                continue
            fnames = [f.name() for f in layer.fields()]
            if gk == 'point':
                pt_fields.update(fnames)
            elif gk == 'line':
                ln_fields.update(fnames)
            else:
                pg_fields.update(fnames)
        self.panel_point.set_fields(sorted(pt_fields))
        self.panel_line.set_fields(sorted(ln_fields))
        self.panel_poly.set_fields(sorted(pg_fields))

    def _update_summary(self):
        n = len(self._shp_paths)
        pts = sum(1 for _, g in self._shp_infos if g == 'point')
        lns = sum(1 for _, g in self._shp_infos if g == 'line')
        pgs = sum(1 for _, g in self._shp_infos if g == 'polygon')
        self.lbl_summary.setText(
            f"📂 {n} files  |  🔵 {pts} Point  "
            f"🟢 {lns} Line  🟡 {pgs} Polygon")

    def _export(self):
        if not self._shp_paths:
            QMessageBox.warning(
                self,
                "Lỗi" if self.lang == 'vi' else "Error",
                "Chưa thêm file SHP nào!"
                if self.lang == 'vi'
                else "No SHP files added!")
            return

        out_path, _ = QFileDialog.getSaveFileName(
            self,
            "Lưu KML/KMZ" if self.lang == 'vi'
            else "Save KML/KMZ",
            "", "KML (*.kml);;KMZ (*.kmz)")
        if not out_path:
            return

        configs = {
            'point': self.panel_point.get_config(),
            'line': self.panel_line.get_config(),
            'polygon': self.panel_poly.get_config(),
        }
        fmt = 'kmz' if out_path.lower().endswith('.kmz') else 'kml'
        builder = MergeKmlBuilder(configs)
        ok, msg = builder.build(self._shp_paths, out_path, fmt)

        if ok:
            title = "Thành công" if self.lang == 'vi' else "Success"
            QMessageBox.information(self, title, msg)
        else:
            title = "Lỗi" if self.lang == 'vi' else "Error"
            QMessageBox.warning(self, title, msg)
