# -*- coding: utf-8 -*-
import os
import re
from datetime import datetime

from qgis.PyQt.QtCore import QThread, pyqtSignal
from qgis.PyQt import uic, QtWidgets, QtCore
from qgis.core import (
    QgsMapLayer, QgsWkbTypes, QgsCoordinateReferenceSystem,
    QgsCoordinateTransform, QgsProject, QgsVectorLayer, QgsFields, QgsField,
    QgsFeature
)
from qgis.utils import iface

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


class cyanlove_buffer(QtWidgets.QDockWidget, FORM_CLASS):
    closingPlugin = pyqtSignal()

    def __init__(self, parent=None):
        super(cyanlove_buffer, self).__init__(parent)
        self.export_thread = None
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.setupUi(self)
        self.setFloating(True)
        self.property_dict = None
        self.is_running = False
        self.setWindowFlags(QtCore.Qt.Dialog)
        self.mFieldComboBox.setLayer(self.mMapLayerComboBox.currentLayer())
        self.btn_value_buffer.clicked.connect(self.on_btn_value_buffer)
        self.btn_column_buffer.clicked.connect(self.on_btn_column_buffer)
        self.mMapLayerComboBox.currentIndexChanged.connect(self.selectindexchange)
        self.textEdit_value_buffer.setText('300')
        # 设置线段数默认提示
        self.spinBox_segments.setValue(32)

    def selectindexchange(self):
        self.mFieldComboBox.setLayer(self.mMapLayerComboBox.currentLayer())

    def update_label(self, value):
        self.label_show.setText(value)

    def on_btn_value_buffer(self):
        current_layer = self.mMapLayerComboBox.currentLayer()
        if current_layer is None or current_layer.type() != QgsMapLayer.VectorLayer:
            self.label_show.setText("选择的图层不是矢量图层！")
            return

        # 缓冲距离
        buffer_value = 300
        buffer_valueset = self.textEdit_value_buffer.toPlainText()
        if re.match(r'^[1-9]\d*$', buffer_valueset):
            buffer_value = int(buffer_valueset)
        else:
            self.label_show.setText("输入无效，必须是一个正整数。")
            return

        # 线段数
        segments = self.spinBox_segments.value()

        self.label_show.setText("缓冲开始...")
        layer_name = current_layer.name()
        timestamp = datetime.now().strftime("%H%M%S")
        layname = f'buffer_{buffer_value}_{layer_name}_{timestamp}'
        # 移除同名图层
        for lyr in QgsProject.instance().mapLayersByName(layname):
            QgsProject.instance().removeMapLayer(lyr.id())

        layer = QgsVectorLayer("Polygon?crs=EPSG:4326", layname, "memory")
        provider = layer.dataProvider()
        fields = QgsFields()
        for field in current_layer.fields():
            fields.append(QgsField(field.name(), field.type()))
        provider.addAttributes(fields)
        layer.updateFields()

        self.progressBar.setRange(0, 100)
        self.progressBar.setValue(0)

        self.export_thread = ExportThread(
            current_layer, provider, buffer_value=buffer_value,
            buffer_colname=None, segments=segments
        )
        self.export_thread.updatelabel.connect(self.update_label)
        self.export_thread.progress.connect(self.update_progress)
        self.export_thread.layerAdded.connect(lambda: QgsProject.instance().addMapLayer(layer, True))
        self.export_thread.finished.connect(self.on_thread_finished)
        self.export_thread.start()

    def on_btn_column_buffer(self):
        current_layer = self.mMapLayerComboBox.currentLayer()
        if current_layer is None or current_layer.type() != QgsMapLayer.VectorLayer:
            self.label_show.setText("选择的图层不是矢量图层！")
            return

        # 线段数
        segments = self.spinBox_segments.value()

        self.label_show.setText("缓冲开始...")
        layer_name = current_layer.name()
        timestamp = datetime.now().strftime("%H%M%S")
        layname = f'buffer_{layer_name}_{timestamp}'
        for lyr in QgsProject.instance().mapLayersByName(layname):
            QgsProject.instance().removeMapLayer(lyr.id())

        layer = QgsVectorLayer("Polygon?crs=EPSG:4326", layname, "memory")
        provider = layer.dataProvider()
        fields = QgsFields()
        for field in current_layer.fields():
            fields.append(QgsField(field.name(), field.type()))
        provider.addAttributes(fields)
        layer.updateFields()

        selectcolname = self.mFieldComboBox.currentField()
        self.progressBar.setRange(0, 100)
        self.progressBar.setValue(0)

        self.export_thread = ExportThread(
            current_layer, provider, buffer_value=None,
            buffer_colname=selectcolname, segments=segments
        )
        self.export_thread.updatelabel.connect(self.update_label)
        self.export_thread.progress.connect(self.update_progress)
        self.export_thread.layerAdded.connect(lambda: QgsProject.instance().addMapLayer(layer, True))
        self.export_thread.finished.connect(self.on_thread_finished)
        self.export_thread.start()

    def on_thread_finished(self):
        self.iface.mapCanvas().refresh()
        self.label_show.setText("缓冲完成！")
        self.progressBar.setValue(100)

    def update_progress(self, value):
        self.progressBar.setValue(value)


class ExportThread(QThread):
    progress = pyqtSignal(int)
    layerAdded = pyqtSignal()
    updatelabel = pyqtSignal(str)

    def __init__(self, layerselect, provider, buffer_value=None, buffer_colname=None, segments=32):
        super().__init__()
        self.layerselect = layerselect
        self.buffer_value = buffer_value
        self.provider = provider
        self.buffer_colname = buffer_colname
        self.segments = segments
        self.transform_to_target = None
        self.transform_to_src = None
        self.target_crs = None

    def _get_best_crs_for_china(self, layer):
        """根据图层范围计算最佳 CGCS2000 3度带投影"""
        extent = layer.extent()
        center_lon = (extent.xMinimum() + extent.xMaximum()) / 2.0

        # 中国经度范围约为 73°E ~ 135°E
        if center_lon < 73 or center_lon > 135:
            self.updatelabel.emit("⚠️ 数据范围不在中国境内，将使用 Web Mercator (EPSG:3857)")
            return QgsCoordinateReferenceSystem("EPSG:3857")

        # 计算3度带带号 (中央经线 = 3 * zone)
        zone = int(round(center_lon / 3.0))
        # 限制有效范围（对应中国 73~135°E）
        zone = max(24, min(45, zone))   # 24~45 对应 72~135°E
        epsg_code = 4534 + (zone - 25)  # EPSG:4534 对应中央经线 75°E (zone=25)
        target_crs = QgsCoordinateReferenceSystem(f"EPSG:{epsg_code}")
        self.updatelabel.emit(f"📍 使用投影: EPSG:{epsg_code} (中央经线 {zone*3}°E)")
        return target_crs

    def run(self):
        # 获取输入图层和 CRS
        layer = self.layerselect
        src_crs = layer.crs()
        if src_crs.isGeographic():
            # 若为地理坐标系，直接使用
            wgs84 = src_crs
        else:
            # 若已是投影坐标，先转为 WGS84 经纬度（以便统一处理）
            wgs84 = QgsCoordinateReferenceSystem("EPSG:4326")
            transform_to_wgs84 = QgsCoordinateTransform(src_crs, wgs84, QgsProject.instance())
            # 注意：这里未实际转换，后面会用到

        # 计算适合中国的最佳投影
        self.target_crs = self._get_best_crs_for_china(layer)

        # 创建坐标转换对象（输入 -> 目标，目标 -> 输入）
        # 注意：这里假设输入是 WGS84 (EPSG:4326)，若图层不是 4326，需要先转换到 4326
        # 但为了兼容，我们强制将几何先转为 4326 再转目标投影
        # 更稳健的做法是使用 QgsCoordinateTransform 直接链式转换，但 QGIS 支持直接转换
        # 我们使用目标投影时，明确源为 WGS84
        wgs84_crs = QgsCoordinateReferenceSystem("EPSG:4326")
        self.transform_to_target = QgsCoordinateTransform(wgs84_crs, self.target_crs, QgsProject.instance())
        self.transform_to_src = QgsCoordinateTransform(self.target_crs, wgs84_crs, QgsProject.instance())

        total_features = layer.featureCount()
        feature_list = layer.getFeatures()
        geom_type = layer.wkbType()

        if geom_type in (QgsWkbTypes.Point, QgsWkbTypes.MultiPoint,
                         QgsWkbTypes.Polygon, QgsWkbTypes.MultiPolygon,
                         QgsWkbTypes.LineString, QgsWkbTypes.MultiLineString):
            if self.buffer_value is not None:
                self.mmqgis_buffer_geometry_value(feature_list, total_features)
            elif self.buffer_colname is not None:
                self.mmqgis_buffer_geometry_colname(feature_list, total_features)
        else:
            self.updatelabel.emit("错误: 图层几何类型不支持缓冲区分析！")
        self.layerAdded.emit()

    def mmqgis_buffer_geometry_value(self, feature_list, total_features):
        new_features = []
        for idx, feature in enumerate(feature_list):
            progress = int((idx + 1) / total_features * 100)
            self.progress.emit(progress)

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

            try:
                # 将几何从 WGS84 转换到目标投影（米制）
                geom.transform(self.transform_to_target)
                # 执行缓冲（单位：米）
                buffered_geom = geom.buffer(self.buffer_value, self.segments)
                # 转换回 WGS84
                buffered_geom.transform(self.transform_to_src)

                if buffered_geom and not buffered_geom.isEmpty():
                    new_feat = QgsFeature(feature)
                    new_feat.setGeometry(buffered_geom)
                    new_features.append(new_feat)

                if len(new_features) >= 100:
                    self.provider.addFeatures(new_features)
                    new_features.clear()

            except Exception as e:
                self.updatelabel.emit(f"错误: 要素 {feature.id()} 缓冲失败 - {str(e)}")

        if new_features:
            self.provider.addFeatures(new_features)

    def mmqgis_buffer_geometry_colname(self, feature_list, total_features):
        new_features = []
        for idx, feature in enumerate(feature_list):
            progress = int((idx + 1) / total_features * 100)
            self.progress.emit(progress)

            raw_val = feature[self.buffer_colname]
            try:
                buffer_dist = float(raw_val)
                if buffer_dist < 0:
                    buffer_dist = abs(buffer_dist)
                if buffer_dist == 0:
                    buffer_dist = 0.1
            except (ValueError, TypeError):
                self.updatelabel.emit(f"警告: 要素 {feature.id()} 缓冲距离列值无效，跳过")
                continue

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

            try:
                geom.transform(self.transform_to_target)
                buffered_geom = geom.buffer(buffer_dist, self.segments)
                buffered_geom.transform(self.transform_to_src)

                if buffered_geom and not buffered_geom.isEmpty():
                    new_feat = QgsFeature(feature)
                    new_feat.setGeometry(buffered_geom)
                    new_features.append(new_feat)

                if len(new_features) >= 100:
                    self.provider.addFeatures(new_features)
                    new_features.clear()

            except Exception as e:
                self.updatelabel.emit(f"错误: 要素 {feature.id()} 缓冲失败 - {str(e)}")

        if new_features:
            self.provider.addFeatures(new_features)