import csv
import os
import pathlib
import sqlite3
import threading
from datetime import datetime


import chardet
import pandas as pd
from qgis.PyQt.QtCore import QThread
from qgis.PyQt.QtWidgets import QApplication

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

from qgis.core import QgsProject, QgsVectorLayer, QgsPointXY, QgsGeometry, QgsFeature, QgsFillSymbol, \
    QgsSingleSymbolRenderer, QgsField, QgsFields, QgsMarkerSymbol
from qgis.utils import iface

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


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

    def __init__(self, parent=None):
        super(cyanlove_createpoint, self).__init__(parent)
        self.export_thread = None
        self.setupUi(self)
        self.setFloating(True)
        self.mQgsFileWidget.setFilter("*.csv;*.xlsx")
        self.setWindowFlags(QtCore.Qt.Dialog)
        self.mQgsFileWidget.fileChanged.connect(self.selectfilepath)
        self.pushButton.clicked.connect(self.writer_point)

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

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

    def selectfilepath(self):
        filepath = self.mQgsFileWidget.filePath()
        self.label_show.setText('')
        if filepath:
            file_path = pathlib.Path(filepath)
            file_extension = file_path.suffix
            self.comboBox.clear()
            self.comboBox_2.clear()
            self.comboBox_3.clear()
            if file_extension.lower() == '.csv':
                self.readcsvpath(filepath)
            if file_extension.lower() == '.xlsx':
                self.readexcelpath(filepath)
        else:
            self.label_2.setText("没有选择文件")

    def readcsvpath(self, csvpath: str):
        try:
            self.label_show.setText('')
            with open(csvpath, 'rb') as f:
                raw_data = f.read(2000)
                result = chardet.detect(raw_data)
                encoding = result['encoding']
                print(encoding)
            if encoding.lower() == 'gb2312':
                encoding = 'gbk'
            df = pd.read_csv(csvpath, encoding=encoding, nrows=1)

            for column in df.columns:
                self.comboBox.addItem(column)
                self.comboBox_2.addItem(column)
                self.comboBox_3.addItem(column)
        except Exception as e:
            self.label_show.setText(f"读取文件时出错: {e}")
            print(f"读取文件时出错: {e}")

    def readexcelpath(self, excelpath: str):
        try:
            self.label_show.setText('')
            self.label_show.setText(f"读取Excel....")
            QApplication.processEvents()  # 进度交换控制
            df = pd.read_excel(excelpath, header=0, nrows=1)
            headers = df.columns.tolist()
            self.comboBox.addItems(headers)
            self.comboBox_2.addItems(headers)
            self.comboBox_3.addItems(headers)
            self.label_show.setText(f"读取Excel完毕！")
            QApplication.processEvents()  # 进度交换控制
        except Exception as e:
            self.label_show.setText(f"读取文件时出错: {e}")
            print(f"读取文件时出错: {e}")

    def writer_point(self):
        excel_or_csv_path = self.mQgsFileWidget.filePath()
        timestamp = datetime.now().strftime("%H%M%S")
        base_filename = os.path.splitext(os.path.basename(excel_or_csv_path))[0]
        layname = f'{base_filename}_Point_{timestamp}'

        if not layname and not excel_or_csv_path:
            self.label_show.setText("没有图层名称和文件路径")
            return
        elif not layname:
            self.label_show.setText("没有图层名称")
            return
        elif not excel_or_csv_path:
            self.label_show.setText("没有文件路径")
            return
        self.label_show.setText(f"绘制点中....")
        QApplication.processEvents()  # 进度交换控制
        lngcolumn = self.comboBox.currentText()
        latcolumn = self.comboBox_2.currentText()
        lnglatcolumn = self.comboBox_3.currentText()

        file_path = pathlib.Path(excel_or_csv_path)
        file_extension = file_path.suffix

        if file_extension.lower() == '.csv':
            with open(excel_or_csv_path, 'rb') as f:
                raw_data = f.read(2000)
                result = chardet.detect(raw_data)
                encoding = result['encoding']
                print(encoding)
            if encoding.lower() == 'gb2312':
                encoding = 'gbk'

            df = pd.read_csv(excel_or_csv_path, encoding=encoding, header=0)
            if self.checkBox_iswkt.isChecked():
                if lnglatcolumn:
                    self.writethread_iswkt(df, layname, lnglatcolumn)
                else:
                    self.label_show.setText("没有选择wkt列")
            else:
                if lngcolumn and latcolumn:
                    self.writethread(df, layname, lngcolumn, latcolumn)
                else:
                    self.label_show.setText("没有选择经度/纬度列")

        if file_extension.lower() == '.xlsx':
            df = pd.read_excel(excel_or_csv_path, header=0)
            if self.checkBox_iswkt.isChecked():
                self.writethread_iswkt(df, layname, lnglatcolumn)
            else:
                self.writethread(df, layname, lngcolumn, latcolumn)

    def writethread(self, df, layName, lngcolumn, latcolumn):
        print('开始线程...')
        self.label_show.setText("开始处理数据...")

        # 检查列是否存在
        if lngcolumn not in df.columns or latcolumn not in df.columns:
            self.label_show.setText(f"错误：列 '{lngcolumn}' 或 '{latcolumn}' 不存在")
            return

        layers = QgsProject.instance().mapLayersByName(layName)
        if layers:
            for layer in layers:
                QgsProject.instance().removeMapLayer(layer.id())

        layer = QgsVectorLayer("Point?crs=EPSG:4326", layName, "memory")
        selected_color = self.mColorButton.color().name()

        self.export_thread = FixedExportThread(df, layer, selected_color, lngcolumn, latcolumn)
        self.export_thread.updatelabel.connect(self.update_label)
        self.export_thread.layerAdded.connect(lambda: QgsProject.instance().addMapLayer(layer, True))
        self.export_thread.layerAdded.connect(iface.mapCanvas().refresh)
        self.export_thread.start()

    def writethread_iswkt(self, df, layName, lng_lat_column):
        print('开始线程...')
        self.label_show.setText("开始处理数据...")

        # 检查列是否存在
        if lng_lat_column not in df.columns:
            self.label_show.setText(f"错误：列 '{lng_lat_column}' 不存在")
            return

        layers = QgsProject.instance().mapLayersByName(layName)
        if layers:
            for layer in layers:
                QgsProject.instance().removeMapLayer(layer.id())

        layer = QgsVectorLayer("Point?crs=EPSG:4326", layName, "memory")
        selected_color = self.mColorButton.color().name()

        self.export_thread = FixedExportThread2(df, layer, selected_color, lng_lat_column)
        self.export_thread.updatelabel.connect(self.update_label)
        self.export_thread.layerAdded.connect(lambda: QgsProject.instance().addMapLayer(layer, True))
        self.export_thread.layerAdded.connect(iface.mapCanvas().refresh)
        self.export_thread.start()


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

    def __init__(self, dfs, layers, selected_color, lngcolumns, latcolumns):
        super().__init__()
        self.df = dfs.copy()
        self.layer = layers
        self.lngcolumn = lngcolumns
        self.latcolumn = latcolumns
        self.selected_color = selected_color

    def run(self):
        try:
            self.updatelabel.emit("正在预处理数据...")

            # 转换为数值类型
            self.df[self.lngcolumn] = pd.to_numeric(self.df[self.lngcolumn], errors='coerce')
            self.df[self.latcolumn] = pd.to_numeric(self.df[self.latcolumn], errors='coerce')

            # 过滤掉包含NaN的行
            valid_mask = (~self.df[self.lngcolumn].isna()) & (~self.df[self.latcolumn].isna())
            self.df = self.df[valid_mask]

            # 重置索引
            self.df = self.df.reset_index(drop=True)
            countdf = len(self.df)

            if countdf == 0:
                self.updatelabel.emit("错误：没有有效的坐标数据")
                return

            self.updatelabel.emit(f"找到 {countdf} 个有效数据点，开始创建要素...")

            provider = self.layer.dataProvider()

            # 创建字段
            fields = QgsFields()
            for column in self.df.columns:
                fields.append(QgsField(column, QVariant.String))

            provider.addAttributes(fields)
            self.layer.updateFields()

            # 创建符号
            marker_symbol = QgsMarkerSymbol.createSimple({
                'name': 'circle',
                'color': f'{self.selected_color}',
                'size': '4'
            })
            self.layer.setRenderer(QgsSingleSymbolRenderer(marker_symbol))

            # 批量处理要素
            features = []
            batch_size = 1000
            valid_count = 0
            error_count = 0

            for index, row in self.df.iterrows():
                try:
                    lng = row[self.lngcolumn]
                    lat = row[self.latcolumn]

                    # 创建几何对象
                    point = QgsPointXY(float(lng), float(lat))
                    geom = QgsGeometry.fromPointXY(point)

                    if geom.isGeosValid():
                        feature = QgsFeature()
                        feature.setFields(fields)
                        feature.setGeometry(geom)

                        # 设置属性
                        for column in self.df.columns:
                            value = row[column]
                            if pd.isna(value):
                                feature[column] = ''
                            else:
                                feature[column] = str(value)

                        features.append(feature)
                        valid_count += 1

                        # 批量提交 - 修复返回值处理
                        if len(features) >= batch_size:
                            try:
                                result = provider.addFeatures(features)
                                # 检查返回值类型并处理
                                if isinstance(result, bool):
                                    # 如果返回bool，表示整体成功或失败
                                    if not result:
                                        print(f"批量提交失败，特征数量: {len(features)}")
                                elif isinstance(result, tuple):
                                    # 如果返回tuple，包含成功和失败的特征
                                    success_count = len(result[0]) if result[0] else 0
                                    failed_count = len(result[1]) if result[1] else 0
                                    print(f"批量提交: 成功 {success_count} 个, 失败 {failed_count} 个")
                                else:
                                    # 其他情况，假设成功
                                    print(f"批量提交完成，特征数量: {len(features)}")
                            except Exception as e:
                                print(f"批量提交异常: {e}")

                            features = []  # 清空列表

                    # 进度更新
                    if (index + 1) % 100 == 0 or (index + 1) == countdf:
                        progress_value = int((index + 1) / countdf * 100)
                        self.updatelabel.emit(f"进度：{progress_value}%，已处理 {valid_count} 个要素")

                except Exception as e:
                    error_count += 1
                    # 减少错误输出频率，避免界面卡顿
                    if error_count <= 10:  # 只显示前10个错误
                        self.updatelabel.emit(f"行 {index} 错误: {str(e)}")
                    continue

            # 添加剩余要素 - 同样修复返回值处理
            if features:
                try:
                    result = provider.addFeatures(features)
                    if isinstance(result, bool):
                        if not result:
                            print(f"最后批量提交失败，特征数量: {len(features)}")
                    elif isinstance(result, tuple):
                        success_count = len(result[0]) if result[0] else 0
                        failed_count = len(result[1]) if result[1] else 0
                        print(f"最后批量提交: 成功 {success_count} 个, 失败 {failed_count} 个")
                    else:
                        print(f"最后批量提交完成，特征数量: {len(features)}")
                except Exception as e:
                    print(f"最后批量提交异常: {e}")

            self.layer.triggerRepaint()

            # 发出完成信号
            self.layerAdded.emit()
            final_msg = f'绘制完毕！成功创建 {valid_count} 个要素，失败 {error_count} 个'
            self.updatelabel.emit(final_msg)
            print(final_msg)

        except Exception as e:
            error_msg = f"处理要素时出错: {str(e)}"
            self.updatelabel.emit(error_msg)
            print(error_msg)
            import traceback
            print(traceback.format_exc())


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

    def __init__(self, dfs, layers, selected_color, lnglatcolumns=None):
        super().__init__()
        self.df = dfs.copy()
        self.layer = layers
        self.lnglatcolumns = lnglatcolumns
        self.selected_color = selected_color

    def run(self):
        try:
            self.updatelabel.emit("正在预处理WKT数据...")

            countdf = len(self.df)
            provider = self.layer.dataProvider()

            # 创建字段
            fields = QgsFields()
            for column in self.df.columns:
                fields.append(QgsField(column, QVariant.String))

            provider.addAttributes(fields)
            self.layer.updateFields()

            # 创建符号
            marker_symbol = QgsMarkerSymbol.createSimple({
                'name': 'circle',
                'color': f'{self.selected_color}',
                'size': '4'
            })
            self.layer.setRenderer(QgsSingleSymbolRenderer(marker_symbol))

            # 批量处理
            features = []
            batch_size = 1000
            valid_count = 0
            error_count = 0

            for index, row in self.df.iterrows():
                try:
                    wkt_str = str(row[self.lnglatcolumns])

                    # 跳过空字符串
                    if not wkt_str or wkt_str.lower() == 'nan':
                        continue

                    geom = QgsGeometry.fromWkt(wkt_str)

                    if geom.isGeosValid() and not geom.isEmpty():
                        feature = QgsFeature()
                        feature.setFields(fields)
                        feature.setGeometry(geom)

                        for column in self.df.columns:
                            value = row[column]
                            if pd.isna(value):
                                feature[column] = ''
                            else:
                                feature[column] = str(value)

                        features.append(feature)
                        valid_count += 1

                        # 批量提交 - 修复返回值处理
                        if len(features) >= batch_size:
                            try:
                                result = provider.addFeatures(features)
                                if isinstance(result, bool):
                                    if not result:
                                        print(f"WKT批量提交失败，特征数量: {len(features)}")
                                elif isinstance(result, tuple):
                                    success_count = len(result[0]) if result[0] else 0
                                    failed_count = len(result[1]) if result[1] else 0
                                    print(f"WKT批量提交: 成功 {success_count} 个, 失败 {failed_count} 个")
                                else:
                                    print(f"WKT批量提交完成，特征数量: {len(features)}")
                            except Exception as e:
                                print(f"WKT批量提交异常: {e}")

                            features = []

                    # 进度更新
                    if (index + 1) % 100 == 0 or (index + 1) == countdf:
                        progress_value = int((index + 1) / countdf * 100)
                        self.updatelabel.emit(f"进度：{progress_value}%，有效要素：{valid_count}")

                except Exception as e:
                    error_count += 1
                    # 减少错误输出频率
                    if error_count <= 10:
                        self.updatelabel.emit(f"WKT行 {index} 错误: {str(e)}")
                    continue

            # 添加剩余要素
            if features:
                try:
                    result = provider.addFeatures(features)
                    if isinstance(result, bool):
                        if not result:
                            print(f"WKT最后批量提交失败，特征数量: {len(features)}")
                    elif isinstance(result, tuple):
                        success_count = len(result[0]) if result[0] else 0
                        failed_count = len(result[1]) if result[1] else 0
                        print(f"WKT最后批量提交: 成功 {success_count} 个, 失败 {failed_count} 个")
                    else:
                        print(f"WKT最后批量提交完成，特征数量: {len(features)}")
                except Exception as e:
                    print(f"WKT最后批量提交异常: {e}")

            self.layer.triggerRepaint()

            final_msg = f'WKT绘制完毕！共处理 {valid_count} 个有效要素，失败 {error_count} 个'
            self.layerAdded.emit()
            self.updatelabel.emit(final_msg)
            print(final_msg)

        except Exception as e:
            error_msg = f"处理WKT要素时出错: {str(e)}"
            self.updatelabel.emit(error_msg)
            print(error_msg)
            import traceback
            print(traceback.format_exc())