# -*- coding: utf-8 -*-
"""
LVT EUDR Module — GeoJSON Export Dialog.

Provides a complete UI for exporting QGIS vector layers to
EUDR-compliant GeoJSON format (EU Regulation 2023/1115).

Author: Lộc Vũ Trung (LVT) / Slow Forest
License: GPL-3.0
"""


from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import (
    QDialog, QVBoxLayout, QHBoxLayout, QTabWidget, QWidget,
    QLabel, QComboBox, QLineEdit, QPushButton, QSpinBox,
    QDoubleSpinBox, QFileDialog, QMessageBox, QGroupBox,
    QFormLayout, QCheckBox, QScrollArea, QFrame,
    QApplication,
)
from qgis.core import QgsWkbTypes, QgsProject, QgsVectorLayer

from .eudr_i18n import tr as eudr_tr
from .geojson_builder import (
    EudrGeoJsonBuilder,
    MODE_EUDR_MIXED, MODE_ALL_POINTS, MODE_ALL_POLYGONS,
    MODE_POINT_UNDER_4, MODE_POLY_OVER_4,
)


class EudrExportDialog(QDialog):
    """EUDR GeoJSON Export Dialog.

    Provides:
        - Layer selection with geometry/CRS info
        - EUDR field mapping (combo boxes for each EUDR property)
        - Export settings (precision, area threshold)
        - Preview statistics
        - Guide/Help tab
        - Author tab
    """

    # EUDR required/optional fields
    EUDR_FIELDS = [
        ("PlotID", "Plot ID:", True),
        ("Species", "Species:", True),
        ("Latitude", "Latitude:", True),
        ("Longitude", "Longitude:", True),
        ("Area_ha", "Area (ha):", True),
        ("DataCollectionDate", "Data Collection Date:", True),
        ("FarmerID", "Farmer ID:", True),
        ("ProducerCountry", "Producer Country (ISO2):", True),
        ("ProductionPlace", "Production Place:", True),
        ("Country", "Country of Production:", False),
        ("ProductDescription", "Product Description:", False),
        ("HSCode", "HS Code:", False),
        ("OperatorName", "Operator Name:", False),
        ("ProductionDate", "Date of Production:", False),
    ]

    def __init__(self, iface, parent=None):
        super().__init__(parent or iface.mainWindow())
        self.iface = iface
        self.lang = 'vi'
        self._field_combos = {}
        self._manual_edits = {}

        screen = QApplication.primaryScreen()
        if screen:
            sh = int(screen.availableGeometry().height() * 0.9)
        else:
            sh = 700
        self.setMinimumSize(750, 650)
        self.resize(850, sh)
        self.setWindowFlags(
            self.windowFlags() & ~Qt.WindowType.WindowContextHelpButtonHint
        )

        self._setup_ui()
        self._refresh_layers()
        self._refresh_ui_text()

    # ------------------------------------------------------------------
    # UI Construction
    # ------------------------------------------------------------------

    def _setup_ui(self):
        """Build the complete dialog UI."""
        main_layout = QVBoxLayout(self)
        main_layout.setSpacing(8)

        # Language toggle
        top_bar = QHBoxLayout()
        self.btn_lang = QPushButton()
        self.btn_lang.setFixedWidth(110)
        self.btn_lang.clicked.connect(self._toggle_language)
        top_bar.addWidget(self.btn_lang)
        top_bar.addStretch()
        main_layout.addLayout(top_bar)

        # Tabs
        self.tabs = QTabWidget()
        main_layout.addWidget(self.tabs)

        # Tab 1: Export
        self.tab_export = QWidget()
        self._setup_export_tab()
        self.tabs.addTab(self.tab_export, "")

        # Bottom buttons
        btn_layout = QHBoxLayout()
        self.btn_help = QPushButton()
        self.btn_help.setStyleSheet(
            "QPushButton{background:#ff8f00;color:#fff;font-weight:bold;"
            "padding:6px 14px;border-radius:4px}"
            "QPushButton:hover{background:#ffa000}"
        )
        self.btn_help.clicked.connect(self._show_help)
        btn_layout.addWidget(self.btn_help)
        btn_layout.addStretch()
        self.btn_close = QPushButton()
        self.btn_close.clicked.connect(self.close)
        btn_layout.addWidget(self.btn_close)
        main_layout.addLayout(btn_layout)

    def _setup_export_tab(self):
        """Build the main export tab with scroll area."""
        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setFrameShape(QFrame.Shape.NoFrame)
        content = QWidget()
        layout = QVBoxLayout(content)
        layout.setSpacing(10)

        # --- 1. Layer Selection ---
        self.grp_layer = QGroupBox()
        ly1 = QFormLayout()

        self.cbo_layer = QComboBox()
        self.cbo_layer.currentIndexChanged.connect(self._on_layer_changed)
        ly1.addRow("", self.cbo_layer)

        self.lbl_geom_type = QLabel("—")
        self.lbl_feat_count = QLabel("—")
        self.lbl_layer_crs = QLabel("—")
        self.lbl_output_crs = QLabel("WGS84 (EPSG:4326)")
        self.lbl_output_crs.setStyleSheet("color: #1B5E20; font-weight: bold;")

        self.lbl_geom_type_label = QLabel()
        self.lbl_feat_count_label = QLabel()
        self.lbl_layer_crs_label = QLabel()
        self.lbl_output_crs_label = QLabel()

        ly1.addRow(self.lbl_geom_type_label, self.lbl_geom_type)
        ly1.addRow(self.lbl_feat_count_label, self.lbl_feat_count)
        ly1.addRow(self.lbl_layer_crs_label, self.lbl_layer_crs)
        ly1.addRow(self.lbl_output_crs_label, self.lbl_output_crs)

        self.grp_layer.setLayout(ly1)
        layout.addWidget(self.grp_layer)

        # --- 2. Field Mapping ---
        self.grp_fields = QGroupBox()
        ly2 = QFormLayout()

        for key, label, required in self.EUDR_FIELDS:
            row = QHBoxLayout()
            cbo = QComboBox()
            cbo.setMinimumWidth(200)
            row.addWidget(cbo, 3)

            txt = QLineEdit()
            txt.setPlaceholderText("or type value..."
                                   if self.lang == 'en' else
                                   "hoặc nhập giá trị...")
            txt.setEnabled(False)
            row.addWidget(txt, 2)

            self._field_combos[key] = cbo
            self._manual_edits[key] = txt

            # Connect: when combo selects "-- Manual value --", enable text
            # input
            cbo.currentIndexChanged.connect(
                lambda idx, k=key: self._on_combo_changed(k)
            )

            lbl = QLabel()
            if required:
                lbl.setStyleSheet("font-weight: bold;")
            ly2.addRow(lbl, row)
            # Store label reference for i18n
            setattr(self, f"_lbl_{key}", lbl)

        self.grp_fields.setLayout(ly2)
        layout.addWidget(self.grp_fields)

        # --- 3. Export Settings ---
        self.grp_settings = QGroupBox()
        ly3 = QFormLayout()

        # Export mode selector
        self.cbo_export_mode = QComboBox()
        self.lbl_export_mode = QLabel()
        ly3.addRow(self.lbl_export_mode, self.cbo_export_mode)

        self.spn_precision = QSpinBox()
        self.spn_precision.setRange(6, 12)
        self.spn_precision.setValue(6)
        self.lbl_precision = QLabel()
        ly3.addRow(self.lbl_precision, self.spn_precision)

        self.spn_threshold = QDoubleSpinBox()
        self.spn_threshold.setRange(0.1, 100.0)
        self.spn_threshold.setValue(4.0)
        self.spn_threshold.setSuffix(" ha")
        self.spn_threshold.setDecimals(1)
        self.lbl_threshold = QLabel()
        ly3.addRow(self.lbl_threshold, self.spn_threshold)

        self.chk_validate = QCheckBox()
        self.chk_validate.setChecked(True)
        ly3.addRow("", self.chk_validate)

        self.chk_auto_area = QCheckBox()
        self.chk_auto_area.setChecked(True)
        ly3.addRow("", self.chk_auto_area)

        self.grp_settings.setLayout(ly3)
        layout.addWidget(self.grp_settings)

        # --- 4. Statistics ---
        self.grp_stats = QGroupBox()
        ly4 = QFormLayout()

        self.lbl_stat_total = QLabel("—")
        self.lbl_stat_point = QLabel("—")
        self.lbl_stat_poly = QLabel("—")
        self.lbl_stat_invalid = QLabel("—")

        self.lbl_st_total = QLabel()
        self.lbl_st_point = QLabel()
        self.lbl_st_poly = QLabel()
        self.lbl_st_invalid = QLabel()

        ly4.addRow(self.lbl_st_total, self.lbl_stat_total)
        ly4.addRow(self.lbl_st_point, self.lbl_stat_point)
        ly4.addRow(self.lbl_st_poly, self.lbl_stat_poly)
        ly4.addRow(self.lbl_st_invalid, self.lbl_stat_invalid)

        self.grp_stats.setLayout(ly4)
        layout.addWidget(self.grp_stats)

        # --- Action buttons ---
        action_ly = QHBoxLayout()
        self.btn_preview = QPushButton()
        self.btn_preview.clicked.connect(self._preview_statistics)
        self.btn_preview.setStyleSheet(
            "padding: 8px 16px; background-color: #2196F3; color: white; "
            "font-weight: bold; border-radius: 4px;"
        )
        action_ly.addWidget(self.btn_preview)

        self.btn_export = QPushButton()
        self.btn_export.clicked.connect(self._export_geojson)
        self.btn_export.setStyleSheet(
            "padding: 8px 16px; background-color: #1B5E20; color: white; "
            "font-weight: bold; border-radius: 4px;"
        )
        action_ly.addWidget(self.btn_export)
        layout.addLayout(action_ly)

        layout.addStretch()
        scroll.setWidget(content)

        tab_layout = QVBoxLayout(self.tab_export)
        tab_layout.setContentsMargins(0, 0, 0, 0)
        tab_layout.addWidget(scroll)

    # ------------------------------------------------------------------
    # i18n
    # ------------------------------------------------------------------

    def _t(self, text):
        """Translate using EUDR i18n with current language."""
        return eudr_tr(text, self.lang)

    def _toggle_language(self):
        """Toggle between English and Vietnamese."""
        self.lang = 'en' if self.lang == 'vi' else 'vi'
        self._refresh_ui_text()

    def _refresh_ui_text(self):
        """Update all UI text for current language."""
        self.setWindowTitle(
            "LVT — " + self._t("EUDR GeoJSON Export")
        )
        self.btn_lang.setText(
            "🌐 English" if self.lang == 'vi' else "🌐 Tiếng Việt"
        )

        # Tab titles
        self.tabs.setTabText(0, self._t("EUDR GeoJSON Export"))

        # Group boxes
        self.grp_layer.setTitle(self._t("1. Select Layer"))
        self.grp_fields.setTitle(self._t("2. EUDR Field Mapping"))
        self.grp_settings.setTitle(self._t("3. Export Settings"))
        self.grp_stats.setTitle(self._t("4. Validation & Statistics"))

        # Layer info labels
        self.lbl_geom_type_label.setText(self._t("Geometry Type:"))
        self.lbl_feat_count_label.setText(self._t("Feature Count:"))
        self.lbl_layer_crs_label.setText(self._t("Layer CRS:"))
        self.lbl_output_crs_label.setText(self._t("Output CRS:"))
        self.lbl_output_crs.setText(
            self._t("WGS84 (EPSG:4326) — Required by EUDR")
        )

        # Field mapping labels
        field_labels = {
            "PlotID": self._t("Plot ID:"),
            "Species": self._t("Species:"),
            "Latitude": self._t("Latitude:"),
            "Longitude": self._t("Longitude:"),
            "Area_ha": self._t("Area (ha):"),
            "DataCollectionDate": self._t("Data Collection Date:"),
            "FarmerID": self._t("Farmer ID:"),
            "ProducerCountry": self._t("Producer Country (ISO2):"),
            "ProductionPlace": self._t("Production Place:"),
            "Country": self._t("Country of Production:"),
            "ProductDescription": self._t("Product Description:"),
            "HSCode": self._t("HS Code:"),
            "OperatorName": self._t("Operator Name:"),
            "ProductionDate": self._t("Date of Production:"),
        }
        for key, label_text in field_labels.items():
            lbl = getattr(self, f"_lbl_{key}", None)
            if lbl:
                lbl.setText(label_text)

        # Export mode combo
        self.lbl_export_mode.setText(self._t("Export Mode:"))
        self.cbo_export_mode.blockSignals(True)
        self.cbo_export_mode.clear()
        is_vi = self.lang == 'vi'
        self.cbo_export_mode.addItem(
            "EUDR chuẩn (≤4ha→Điểm, >4ha→Polygon)" if is_vi
            else "EUDR Standard (≤4ha→Point, >4ha→Polygon)",
            MODE_EUDR_MIXED)
        self.cbo_export_mode.addItem(
            "Tất cả → Điểm (Point on Surface)" if is_vi
            else "All → Point on Surface",
            MODE_ALL_POINTS)
        self.cbo_export_mode.addItem(
            "Tất cả → Polygon + Lat/Lon" if is_vi
            else "All → Polygon + Lat/Lon",
            MODE_ALL_POLYGONS)
        self.cbo_export_mode.addItem(
            "Chỉ lô ≤4ha → Điểm" if is_vi
            else "Only ≤4ha → Point",
            MODE_POINT_UNDER_4)
        self.cbo_export_mode.addItem(
            "Chỉ lô >4ha → Polygon" if is_vi
            else "Only >4ha → Polygon",
            MODE_POLY_OVER_4)
        self.cbo_export_mode.blockSignals(False)

        # Settings labels
        self.lbl_precision.setText(
            self._t("Coordinate Precision (decimals):")
        )
        self.lbl_threshold.setText(self._t("Area Threshold (ha):"))
        self.chk_validate.setText(
            self._t("Validate geometries before export")
        )
        self.chk_auto_area.setText(
            self._t("Calculate area from geometry")
        )

        # Statistics labels
        threshold = self.spn_threshold.value()
        self.lbl_st_total.setText(self._t("Total features:"))
        self.lbl_st_point.setText(
            self._t("Point (≤ {threshold} ha):").format(threshold=threshold)
        )
        self.lbl_st_poly.setText(
            self._t("Polygon (> {threshold} ha):").format(threshold=threshold)
        )
        self.lbl_st_invalid.setText(self._t("Invalid geometries:"))

        # Buttons
        self.btn_preview.setText("📊 " + self._t("Preview Statistics"))
        self.btn_export.setText("🚀 " + self._t("Export GeoJSON"))
        self.btn_close.setText(self._t("Close"))
        self.btn_help.setText("❓ " + self._t("Help"))

    # ------------------------------------------------------------------
    # Layer / Field Handling
    # ------------------------------------------------------------------

    def _refresh_layers(self):
        """Populate the layer combo box with vector layers."""
        self.cbo_layer.blockSignals(True)
        self.cbo_layer.clear()
        for layer in QgsProject.instance().mapLayers().values():
            if isinstance(layer, QgsVectorLayer):
                self.cbo_layer.addItem(layer.name(), layer.id())
        self.cbo_layer.blockSignals(False)
        if self.cbo_layer.count() > 0:
            self._on_layer_changed()

    def refresh_layers(self):
        """Public method called by lvt_plugin before showing."""
        self._refresh_layers()

    def _get_selected_layer(self):
        """Return the currently selected QgsVectorLayer or None."""
        layer_id = self.cbo_layer.currentData()
        if layer_id:
            return QgsProject.instance().mapLayer(layer_id)
        return None

    def _on_layer_changed(self):
        """Update layer info and field combos when layer selection changes."""
        layer = self._get_selected_layer()
        if not layer:
            self.lbl_geom_type.setText("—")
            self.lbl_feat_count.setText("—")
            self.lbl_layer_crs.setText("—")
            return

        # Geometry type
        geom_type = QgsWkbTypes.displayString(layer.wkbType())
        self.lbl_geom_type.setText(geom_type)

        # Feature count
        self.lbl_feat_count.setText(str(layer.featureCount()))

        # CRS
        crs = layer.crs()
        crs_text = f"{crs.authid()} — {crs.description()}"
        if crs.authid() == "EPSG:4326":
            self.lbl_layer_crs.setText(crs_text)
            self.lbl_layer_crs.setStyleSheet("color: #1B5E20;")
        else:
            self.lbl_layer_crs.setText(
                crs_text + " → will transform"
            )
            self.lbl_layer_crs.setStyleSheet("color: #E65100;")

        # Update field combos
        field_names = [f.name() for f in layer.fields()]
        manual_text = self._t("-- Manual value --")
        empty_text = self._t("-- Leave empty --")

        for key, cbo in self._field_combos.items():
            cbo.blockSignals(True)
            cbo.clear()

            if key == "Area_ha":
                cbo.addItem(self._t("(auto-calculated from geometry)"),
                            "__auto__")
            elif key == "Latitude":
                cbo.addItem(self._t("(auto — Point on Surface Y)"),
                            "__auto__")
            elif key == "Longitude":
                cbo.addItem(self._t("(auto — Point on Surface X)"),
                            "__auto__")
            else:
                cbo.addItem(empty_text, "")

            for fname in field_names:
                cbo.addItem(fname, fname)

            cbo.addItem(manual_text, "__manual__")

            # Auto-match: try to find a field that matches the EUDR key
            self._auto_match_field(key, cbo, field_names)

            cbo.blockSignals(False)
            self._on_combo_changed(key)

    def _auto_match_field(self, eudr_key, cbo, field_names):
        """Try to auto-match a source field to an EUDR key."""
        # Simple heuristic matching
        hints = {
            "PlotID": ["ma_lo", "plot_id", "id", "fid", "ma_thua",
                       "plot"],
            "Species": ["species", "loai_cay", "cay_trong", "tree",
                        "loaicay", "caytrong"],
            "DataCollectionDate": ["date", "ngay", "ngay_thu_thap",
                                   "collection_date", "survey_date"],
            "FarmerID": ["farmer_id", "farmer", "nong_dan", "ho_sx",
                         "ma_nd", "producer_id"],
            "ProducerCountry": ["country", "quoc_gia", "nation",
                                "producer_country", "iso"],
            "ProductionPlace": ["ten_lo", "name", "place", "location",
                                "noi_sx", "production"],
            "Country": ["country", "quoc_gia", "nation"],
            "ProductDescription": ["product", "san_pham", "description",
                                   "mo_ta"],
            "HSCode": ["hs_code", "hscode", "ma_hs"],
            "OperatorName": ["operator", "company", "doanh_nghiep",
                             "ten_dn"],
            "ProductionDate": ["date", "ngay", "ngay_sx",
                               "production_date"],
        }

        keywords = hints.get(eudr_key, [])
        for fname in field_names:
            fname_lower = fname.lower()
            for hint in keywords:
                if hint in fname_lower:
                    idx = cbo.findData(fname)
                    if idx >= 0:
                        cbo.setCurrentIndex(idx)
                        return

    def _on_combo_changed(self, key):
        """Enable/disable manual text input based on combo selection."""
        cbo = self._field_combos.get(key)
        txt = self._manual_edits.get(key)
        if cbo and txt:
            is_manual = (cbo.currentData() == "__manual__")
            txt.setEnabled(is_manual)
            if is_manual:
                txt.setFocus()

    # ------------------------------------------------------------------
    # Field Mapping Builder
    # ------------------------------------------------------------------

    def _build_field_mapping(self):
        """Build field_mapping dict from current UI state."""
        mapping = {}
        for key, cbo in self._field_combos.items():
            data = cbo.currentData()
            if data == "__manual__":
                # Use static value from text input
                txt = self._manual_edits[key]
                val = txt.text().strip()
                if val:
                    mapping[key] = f"__static__:{val}"
            elif data == "__auto__":
                mapping[key] = "__auto__"
            elif data:
                mapping[key] = data
        return mapping

    # ------------------------------------------------------------------
    # Preview Statistics
    # ------------------------------------------------------------------

    def _preview_statistics(self):
        """Run preview statistics on the selected layer."""
        layer = self._get_selected_layer()
        if not layer:
            QMessageBox.warning(
                self, "LVT",
                self._t("No vector layer selected.")
            )
            return

        if layer.featureCount() == 0:
            QMessageBox.warning(
                self, "LVT",
                self._t("Selected layer has no features.")
            )
            return

        mapping = self._build_field_mapping()
        area_field = None
        if not self.chk_auto_area.isChecked():
            area_data = self._field_combos["Area_ha"].currentData()
            if area_data and area_data not in ("__auto__", "__manual__", ""):
                area_field = area_data

        builder = EudrGeoJsonBuilder(
            layer=layer,
            field_mapping=mapping,
            area_threshold_ha=self.spn_threshold.value(),
            precision=self.spn_precision.value(),
            area_field=area_field,
            validate_geometries=self.chk_validate.isChecked(),
            export_mode=self.cbo_export_mode.currentData() or MODE_EUDR_MIXED,
        )

        result = builder.preview_statistics()
        threshold = self.spn_threshold.value()

        self.lbl_stat_total.setText(str(result.total_features))
        self.lbl_stat_point.setText(str(result.point_count))
        self.lbl_stat_poly.setText(str(result.polygon_count))

        if result.invalid_count > 0 or result.null_geometry_count > 0:
            total_issues = result.invalid_count + result.null_geometry_count
            self.lbl_stat_invalid.setText(
                f"<span style='color:red;font-weight:bold;'>"
                f"{total_issues}</span>"
            )
            # Show detailed geometry warning dialog
            self._show_geometry_warnings(result)
        else:
            self.lbl_stat_invalid.setText(
                "<span style='color:#1B5E20;'>0 ✓</span>"
            )

        # Update threshold labels
        self.lbl_st_point.setText(
            self._t("Point (≤ {threshold} ha):").format(
                threshold=threshold)
        )
        self.lbl_st_poly.setText(
            self._t("Polygon (> {threshold} ha):").format(
                threshold=threshold)
        )

    # ------------------------------------------------------------------
    # Export
    # ------------------------------------------------------------------

    def _export_geojson(self):
        """Export to EUDR-compliant GeoJSON file."""
        layer = self._get_selected_layer()
        if not layer:
            QMessageBox.warning(
                self, "LVT",
                self._t("No vector layer selected.")
            )
            return

        if layer.featureCount() == 0:
            QMessageBox.warning(
                self, "LVT",
                self._t("Selected layer has no features.")
            )
            return

        # Ask for output path
        out_path, _ = QFileDialog.getSaveFileName(
            self,
            self._t("Save GeoJSON File"),
            "",
            self._t("GeoJSON Files (*.geojson)"),
        )
        if not out_path:
            return

        mapping = self._build_field_mapping()
        area_field = None
        if not self.chk_auto_area.isChecked():
            area_data = self._field_combos["Area_ha"].currentData()
            if area_data and area_data not in ("__auto__", "__manual__", ""):
                area_field = area_data

        builder = EudrGeoJsonBuilder(
            layer=layer,
            field_mapping=mapping,
            area_threshold_ha=self.spn_threshold.value(),
            precision=self.spn_precision.value(),
            area_field=area_field,
            validate_geometries=self.chk_validate.isChecked(),
            export_mode=self.cbo_export_mode.currentData() or MODE_EUDR_MIXED,
        )

        success, message, result = builder.build(out_path)

        if success:
            msg = self._t(
                "Export completed successfully!\n\n"
                "File: {path}\nFeatures: {count}\n"
                "Points: {points}\nPolygons: {polygons}"
            ).format(
                path=message,
                count=result.valid_count,
                points=result.point_count,
                polygons=result.polygon_count,
            )
            QMessageBox.information(self, "LVT", msg)

            # Update statistics panel
            self.lbl_stat_total.setText(str(result.total_features))
            self.lbl_stat_point.setText(str(result.point_count))
            self.lbl_stat_poly.setText(str(result.polygon_count))
            self.lbl_stat_invalid.setText(str(result.invalid_count))
        else:
            QMessageBox.critical(
                self, "LVT",
                self._t("Export failed:\n{error}").format(error=message),
            )

    def _show_help(self):
        """Open help dialog for EUDR module."""
        from ..shared.help_dialog import HelpDialog
        dlg = HelpDialog("eudr", parent=self)
        dlg.exec()

    def _show_geometry_warnings(self, result):
        """Show a detailed geometry error/warning dialog."""
        is_vi = self.lang == 'vi'
        title = "⚠️ Cảnh báo lỗi hình học" if is_vi else "⚠️ Geometry Warnings"

        lines = []
        if result.null_geometry_count > 0:
            lines.append(
                f"• {result.null_geometry_count} đối tượng không có hình học (NULL geometry)"
                if is_vi else
                f"• {result.null_geometry_count} features have no geometry (NULL)"
            )
        if result.invalid_count > 0:
            lines.append(
                f"• {result.invalid_count} hình học không hợp lệ (không thể sửa tự động)"
                if is_vi else
                f"• {result.invalid_count} invalid geometries (could not auto-repair)"
            )
        if result.repaired_count > 0:
            lines.append(
                f"• {result.repaired_count} hình học đã được tự động sửa chữa"
                if is_vi else
                f"• {result.repaired_count} geometries were auto-repaired"
            )

        if result.errors:
            lines.append("")
            lines.append(
                "Chi tiết lỗi:" if is_vi else "Error details:"
            )
            for err in result.errors[:20]:  # max 20 errors shown
                lines.append(f"  → {err}")
            if len(result.errors) > 20:
                lines.append(
                    f"  ... và {len(result.errors) - 20} lỗi khác"
                    if is_vi else
                    f"  ... and {len(result.errors) - 20} more errors"
                )

        lines.append("")
        lines.append(
            "Các lỗi phổ biến và cách khắc phục:" if is_vi else
            "Common errors and fixes:"
        )
        common_errors = [
            ("Polygon không khép kín", "Thêm điểm cuối = điểm đầu",
             "Unclosed polygon", "Add last point = first point"),
            ("Sai hệ tọa độ", "Chuyển về EPSG:4326 (decimal degrees)",
             "Wrong CRS", "Reproject to EPSG:4326 (decimal degrees)"),
            ("Có lỗ (hole) trong polygon", "Tách thành 2 polygon riêng",
             "Polygon has holes", "Split into separate polygons"),
            ("Polygon tự cắt (self-intersection)", "Dùng Fix Geometry trong QGIS",
             "Self-intersecting polygon", "Use Fix Geometry in QGIS"),
            ("LineString/GeometryCollection", "Chỉ dùng Point hoặc Polygon",
             "LineString/GeometryCollection", "Only Point or Polygon allowed"),
            ("Tọa độ trùng nhau do làm tròn", "Dùng 6 số thập phân",
             "Duplicate coordinates from rounding", "Use 6 decimal places"),
        ]
        for vi_err, vi_fix, en_err, en_fix in common_errors:
            if is_vi:
                lines.append(f"  • {vi_err} → {vi_fix}")
            else:
                lines.append(f"  • {en_err} → {en_fix}")

        QMessageBox.warning(self, title, "\n".join(lines))
