# -*- 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

    def run(self):
        total_features = self.layerselect.featureCount()
        feature_list = self.layerselect.getFeatures()
        geom_type = self.layerselect.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):
        # 预先创建坐标转换对象（避免循环内重复创建）
        wgs84 = QgsCoordinateReferenceSystem("EPSG:4326")
        utm_crs = QgsCoordinateReferenceSystem("EPSG:32648")
        transform_to_utm = QgsCoordinateTransform(wgs84, utm_crs, QgsProject.instance())
        transform_to_wgs84 = QgsCoordinateTransform(utm_crs, wgs84, QgsProject.instance())

        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:
                geom.transform(transform_to_utm)
                buffered_geom = geom.buffer(self.buffer_value, self.segments)
                buffered_geom.transform(transform_to_wgs84)

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

                # 每处理 100 个要素批量提交一次，避免内存过大
                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):
        wgs84 = QgsCoordinateReferenceSystem("EPSG:4326")
        utm_crs = QgsCoordinateReferenceSystem("EPSG:32648")
        transform_to_utm = QgsCoordinateTransform(wgs84, utm_crs, QgsProject.instance())
        transform_to_wgs84 = QgsCoordinateTransform(utm_crs, wgs84, QgsProject.instance())

        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(transform_to_utm)
                buffered_geom = geom.buffer(buffer_dist, self.segments)
                buffered_geom.transform(transform_to_wgs84)

                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)