import csv
import os
import re
import time
from datetime import datetime

from qgis import processing
from qgis.PyQt.QtCore import QVariant, QThread
from qgis.PyQt.QtWidgets import QFileDialog
from qgis.core import QgsFeatureRequest, QgsWkbTypes,  \
     QgsDistanceArea, QgsProcessingContext, QgsSpatialIndex
from qgis.utils import iface

from qgis.PyQt import QtWidgets, uic, QtCore
from qgis.PyQt.QtCore import pyqtSignal

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


class cyanlove_calc_contain_point_in_geometry(QtWidgets.QDockWidget, FORM_CLASS):

    def __init__(self, parent=None):
        super(cyanlove_calc_contain_point_in_geometry, 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.setWindowModality(QtCore.Qt.ApplicationModal)  # 或者使用 Qt.WindowModal
        self.btn_calc_contain_point_geometry.clicked.connect(self.calc_contain_point_in_geometry)

    def calc_contain_point_in_geometry(self):
        options = QFileDialog.Options()  # 创建文件对话框选项
        options |= QFileDialog.ReadOnly  # 可以设置一些选项，例如只读
        csv_file_path, _ = QFileDialog.getSaveFileName(self,
                                                       "选择文件",
                                                       "",
                                                       "CSV文件 (*.csv);;所有文件 (*)",  # 可以添加其他过滤器
                                                       options=options)  # 传递 options 参数
        # 检查用户是否选择了文件
        if csv_file_path:
            current_layer1 = self.mMapLayerComboBox.currentLayer()
            current_layer2 = self.mMapLayerComboBox_2.currentLayer()
            geom_type1 = current_layer1.wkbType()
            geom_type2 = current_layer2.wkbType()
            if geom_type1 not in [QgsWkbTypes.Polygon, QgsWkbTypes.MultiPolygon]:
                self.label_show.setText("第一个图层必须是Polygon边界类图层！")  # 更新值
                return
            if geom_type1 in [QgsWkbTypes.Polygon, QgsWkbTypes.MultiPolygon] and \
               geom_type2 in [QgsWkbTypes.Point, QgsWkbTypes.MultiPoint,
                              QgsWkbTypes.Polygon, QgsWkbTypes.MultiPolygon,
                              QgsWkbTypes.LineString, QgsWkbTypes.MultiLineString]:
                # 确保使用现有的进度条
                self.progressBar.setRange(0, 100)  # 设置进度条范围
                self.progressBar.setValue(0)  # 初始化进度条值
                self.progressBar.show()  # 显示进度条 (如果之前是隐藏状态)
                # 启动导出线程
                self.export_thread = ExportThread(current_layer1, current_layer2, csv_file_path)
                self.export_thread.progress.connect(self.update_progress)  # 连接信号到槽
                self.export_thread.updatelabel.connect(self.update_label)
                self.export_thread.finished.connect(self.export_finished)  # 导出完成后连接到槽
                self.export_thread.start()  # 启动线程

    def update_label(self, value):
        self.label_show.setText(value)  # 更新值

    def update_progress(self, value):
        self.progressBar.setValue(value)  # 更新进度条的值

    def export_finished(self):
        self.progressBar.setValue(100)


class ExportThread(QThread):
    progress = pyqtSignal(int)  # 声明一个信号
    updatelabel = pyqtSignal(str)  # 声明一个更新label新增信号

    def __init__(self, selected_layer1, selected_layer2, csv_file_path):
        super().__init__()
        self.selected_layer1 = selected_layer1
        self.selected_layer2 = selected_layer2
        self.csv_file_path = csv_file_path

    def run(self):
        start_time = time.time()
        # 创建处理上下文
        field_names1 = [f"{field.name()}" for field in self.selected_layer1.fields()]
        field_names2 = [f"{field.name()}" for field in self.selected_layer2.fields()]
        combined_list1 = field_names1+field_names2

        # 创建空间索引
        self.updatelabel.emit("创建索引...")
        spatial_index = QgsSpatialIndex(self.selected_layer2.getFeatures())

        total_features = self.selected_layer1.featureCount()
        self.updatelabel.emit("开始计算...")
        context = QgsDistanceArea()

        with open(self.csv_file_path, mode='w', newline='', encoding='gbk') as csv_file:
            writer = csv.writer(csv_file)
            writer.writerow(combined_list1)

            for index, feature1 in enumerate(self.selected_layer1.getFeatures()):
                try:
                    row = []
                    geom1 = feature1.geometry()
                    if geom1:
                        for field_name in field_names1:  # 不包括 WKT_BJ
                            value = feature1[field_name]
                            row.append(f'{value}')

                        # 判断是否相交
                        intersecting_ids = spatial_index.intersects(geom1.boundingBox())
                        if intersecting_ids:  # 仅处理相交的要素
                            request = QgsFeatureRequest().setFilterFids(intersecting_ids)

                            for feature2 in self.selected_layer2.getFeatures(request):
                                geom2 = feature2.geometry()
                                if geom2 and geom1.contains(geom2):  # 检查是否相交
                                    row2 = []
                                    for field_name in field_names2:
                                        value = feature2[field_name]
                                        row2.append(f'{value}')
                                    if row2:
                                        # 确保 row 不为空
                                        writer.writerow(row + row2)

                        progress_value = int((index + 1) / total_features * 100)
                        self.progress.emit(progress_value)

                except Exception as e:
                    print(f"处理要素 {index} 时出错: {str(e)}")

        end_time = time.time()
        # 计算并打印运行时间
        execution_time = end_time - start_time
        self.updatelabel.emit(f"代码运行时间: {execution_time:.2f} 秒")
