# -*- coding: utf-8 -*-
"""
修正面图形插件（增强版：自动修复四点错序矩形）
"""

import os
import traceback

from qgis.core import (
    QgsGeometry, QgsVectorLayer, QgsField, QgsProject, QgsFeature,
    QgsCoordinateReferenceSystem, QgsCoordinateTransform,
    QgsWkbTypes, QgsFillSymbol, QgsSimpleFillSymbolLayer,
    QgsMapLayerProxyModel
)
from qgis.PyQt import uic
from qgis.PyQt.QtCore import QVariant
from qgis.PyQt.QtWidgets import QDockWidget, QApplication
from qgis.PyQt.QtGui import QColor

FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'cyanlove_xiuzheng_geometry_base.ui'))


class cyanlove_xiuzheng_geometry(QDockWidget, FORM_CLASS):
    def __init__(self, parent=None):
        super(cyanlove_xiuzheng_geometry, self).__init__(parent)
        self.setupUi(self)
        self.init_ui()
        self.btn_calc_area.clicked.connect(self.fix_geometries)
        self.progressBar.setVisible(False)
        self.result_layer = None

    def init_ui(self):
        self.mMapLayerComboBox.setFilters(QgsMapLayerProxyModel.PolygonLayer)
        self.label_show.setText("说明：分解多部件为单部件，保留每个原始要素中面积最大的部分")

    def update_status_message(self, message, is_error=False):
        if is_error:
            self.label_show.setStyleSheet("color:#d9534f; background:#f2dede; padding:6px; border-radius:4px; border-left:3px solid #d9534f; font-weight:bold;")
        else:
            self.label_show.setStyleSheet("color:#5a6c7d; background:#f0f4f8; padding:6px; border-radius:4px; border-left:3px solid #4a6fa5; font-weight:bold;")
        self.label_show.setText(message)
        QApplication.processEvents()

    # ========== 改进的识别：面积比法 + 顶点数限制 ==========
    @staticmethod
    def is_crossed_rectangle(geometry):
        """识别四点错序矩形：顶点数4~5，且面积明显小于边界框面积（<90%）"""
        if geometry is None or geometry.isEmpty():
            return False

        # 获取顶点并去重
        vertices = list(geometry.vertices())
        if len(vertices) >= 5 and vertices[0] == vertices[-1]:
            vertices = vertices[:-1]

        if len(vertices) not in (4, 5):
            return False

        bbox = geometry.boundingBox()
        bbox_area = (bbox.xMaximum() - bbox.xMinimum()) * (bbox.yMaximum() - bbox.yMinimum())
        if bbox_area == 0:
            return False

        geom_area = geometry.area()
        # 自相交X形矩形的面积约为边界框的一半，用0.9作为安全阈值
        if geom_area / bbox_area < 0.9:
            return True
        return False

    def fix_crossed_rectangle(self, geometry):
        """直接用边界框修复"""
        bbox = geometry.boundingBox()
        return QgsGeometry.fromRect(bbox)
    # =================================================

    def fix_geometries(self):
        layer = self.mMapLayerComboBox.currentLayer()
        if not layer:
            self.update_status_message("❌ 请先选择一个图层！", is_error=True)
            return
        if layer.geometryType() != QgsWkbTypes.PolygonGeometry:
            self.update_status_message("❌ 请选择多边形图层！", is_error=True)
            return

        self.progressBar.setVisible(True)
        self.progressBar.setValue(0)
        self.btn_calc_area.setEnabled(False)
        self.update_status_message(f"⏳ 正在处理图层：{layer.name()} ...")
        QApplication.processEvents()

        try:
            result_layer = self.process_layer(layer)
            if result_layer and result_layer.featureCount() > 0:
                QgsProject.instance().addMapLayer(result_layer)
                original_count = layer.featureCount()
                result_count = result_layer.featureCount()
                removed_count = original_count - result_count
                self.update_status_message(f"✅ 完成！原始:{original_count} → 处理后:{result_count} 移除退化:{removed_count}")
            else:
                self.update_status_message("⚠️ 处理失败或无有效要素", is_error=True)
        except Exception as e:
            self.update_status_message(f"❌ 出错：{str(e)}", is_error=True)
            print(traceback.format_exc())
        finally:
            self.progressBar.setVisible(False)
            self.btn_calc_area.setEnabled(True)

    def process_layer(self, input_layer):
        layer_name = f"{input_layer.name()}_fixed"
        self.result_layer = QgsVectorLayer(
            f"MultiPolygon?crs={input_layer.crs().authid()}",
            layer_name, "memory"
        )

        fields = input_layer.fields()
        fields.append(QgsField("fixed_area_sqm", QVariant.Double))
        original_fields = [f.name() for f in input_layer.fields()]

        data_provider = self.result_layer.dataProvider()
        data_provider.addAttributes(fields)
        self.result_layer.updateFields()

        features = list(input_layer.getFeatures())
        total_features = len(features)

        source_crs = input_layer.crs()
        if source_crs.authid() == "EPSG:4326":
            utm_crs = QgsCoordinateReferenceSystem("EPSG:32648")
        else:
            utm_crs = source_crs
        transform_to_utm = None
        if source_crs.authid() != utm_crs.authid():
            transform_to_utm = QgsCoordinateTransform(source_crs, utm_crs, QgsProject.instance())

        output_features = []
        last_progress = -1

        for idx, feature in enumerate(features):
            progress = int((idx + 1) / total_features * 100)
            self.progressBar.setValue(progress)
            if progress % 10 == 0 and progress != last_progress:
                self.update_status_message(f"⏳ 处理中：{idx+1}/{total_features} ({progress}%)")
                last_progress = progress
            QApplication.processEvents()

            geom = feature.geometry()
            if geom is None or geom.isEmpty():
                continue

            # 修复决策
            if self.is_crossed_rectangle(geom):
                valid_geom = self.fix_crossed_rectangle(geom)
                # 调试输出（可选，可在控制台看到）
                print(f"修复四点自相交矩形: FID={feature.id()}")
            else:
                valid_geom = geom.makeValid()

            if valid_geom is None or valid_geom.isEmpty():
                continue

            # 分解为单部件
            parts = self.explode_geometry(valid_geom)

            valid_parts = []
            for part in parts:
                if part.type() != QgsWkbTypes.PolygonGeometry:
                    continue
                area = self.calculate_area(part, transform_to_utm)
                if area > 0.01:
                    valid_parts.append((part, area))

            if valid_parts:
                valid_parts.sort(key=lambda x: x[1], reverse=True)
                largest_geom, largest_area = valid_parts[0]

                out_feature = QgsFeature(self.result_layer.fields())
                out_feature.setGeometry(largest_geom)
                for field_name in original_fields:
                    try:
                        out_feature[field_name] = feature[field_name]
                    except:
                        pass
                out_feature["fixed_area_sqm"] = largest_area
                output_features.append(out_feature)

        if output_features:
            data_provider.addFeatures(output_features)
            self.result_layer.updateExtents()
            self.set_layer_style(self.result_layer)
        return self.result_layer

    def explode_geometry(self, geometry):
        parts = []
        if geometry.isMultipart():
            const_geom = geometry.constGet()
            for i in range(const_geom.partCount()):
                part_geom = const_geom.geometryN(i)
                if part_geom:
                    parts.append(QgsGeometry(part_geom.clone()))
        else:
            parts.append(QgsGeometry(geometry))
        return parts

    def calculate_area(self, geometry, transform=None):
        if geometry is None or geometry.isEmpty():
            return 0.0
        try:
            if transform:
                geom_proj = QgsGeometry(geometry)
                geom_proj.transform(transform)
                return geom_proj.area()
            else:
                return geometry.area()
        except:
            return 0.0

    def set_layer_style(self, layer):
        symbol = QgsFillSymbol()
        symbol_layer = QgsSimpleFillSymbolLayer()
        symbol_layer.setColor(QColor(100, 150, 200, 180))
        symbol_layer.setStrokeColor(QColor(50, 50, 50))
        symbol_layer.setStrokeWidth(0.5)
        symbol.changeSymbolLayer(0, symbol_layer)
        layer.renderer().setSymbol(symbol)
        layer.triggerRepaint()

    def closeEvent(self, event):
        event.accept()