import os
import pathlib

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

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, QgsField, QgsFields
from qgis.utils import iface

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


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

    def __init__(self, parent=None):
        super(cyanlove_import_geometry, self).__init__(parent)
        self.export_thread = None
        self.setupUi(self)
        self.setFloating(True)
        self.setWindowFlags(QtCore.Qt.Dialog)
        self.toolButton.clicked.connect(self.selectfilepath)
        self.pushButton.clicked.connect(self.writerpolygon)

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

    def on_thread_finished(self):
        if self.export_thread:
            good = self.export_thread.layer_good
            bad = self.export_thread.layer_bad
            print(f"正常图层要素数: {good.featureCount() if good else 0}")
            print(f"错误图层要素数: {bad.featureCount() if bad else 0}")

            if good and good.isValid() and good.featureCount() > 0:
                QgsProject.instance().addMapLayer(good, True)
            if bad and bad.isValid() and bad.featureCount() > 0:
                QgsProject.instance().addMapLayer(bad, True)

            if (not good or good.featureCount() == 0) and (not bad or bad.featureCount() == 0):
                self.label.setText("所有几何均无效或解析失败，请检查数据格式")
            else:
                self.label.setText("创建完成！")
        else:
            self.label.setText("线程异常")

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

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

    def selectfilepath(self):
        filters = "Excel & CSV Files (*.xlsx *.csv)"
        filepath, _ = QtWidgets.QFileDialog.getOpenFileName(self, "选择文件", "", filters)
        if filepath is not None:
            self.textEdit.setText(filepath)
            file_path = pathlib.Path(filepath)
            file_extension = file_path.suffix
            self.comboBox.clear()
            if file_extension.lower() == '.csv':
                self.readcsvpath(filepath)
            elif file_extension.lower() == '.xlsx':
                self.readexcelpath(filepath)

    def readcsvpath(self, csvpath: str):
        try:
            self.label.setText('')
            with open(csvpath, 'rb') as f:
                raw_data = f.read(2000)
                result = chardet.detect(raw_data)
                encoding = result['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)
        except Exception as e:
            self.label.setText(f"读取文件时出错: {e}")
            print(f"读取文件时出错: {e}")

    def readexcelpath(self, excelpath: str):
        try:
            df = pd.read_excel(excelpath, header=0, nrows=1)
            self.comboBox.addItems(df.columns.tolist())
        except Exception as e:
            self.label.setText(f"读取文件时出错: {e}")
            print(f"读取文件时出错: {e}")

    def detect_format(self, text):
        """检测文本格式，返回 'wkt' 或 'coord'"""
        text = text.strip()
        if not text:
            return 'unknown'
        # 判断是否为 WKT：通常以 POLYGON, MULTIPOLYGON, LINESTRING 等开头，或包含 '('
        wkt_keywords = ('POLYGON', 'MULTIPOLYGON', 'LINESTRING', 'MULTILINESTRING', 'POINT', 'MULTIPOINT')
        if text.upper().startswith(wkt_keywords):
            return 'wkt'
        # 如果包含分号且不包含括号，可能是坐标串
        if ';' in text and '(' not in text:
            # 进一步检查是否每段都是两个数字用逗号分隔
            parts = text.split(';')
            for part in parts:
                if not part.strip():
                    continue
                coords = part.split(',')
                if len(coords) == 2:
                    try:
                        float(coords[0].strip())
                        float(coords[1].strip())
                    except ValueError:
                        return 'unknown'
                else:
                    return 'unknown'
            return 'coord(x1,y1;x2,y2)'
        return 'unknown'

    def writerpolygon(self):
        reply = QMessageBox.question(self, '确认绘制吗？',
                                     '确定要开始绘制面图层吗？',
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        if reply != QMessageBox.Yes:
            return

        excel_or_csv_path = self.textEdit.toPlainText().strip()
        layName = self.textEdit_2.toPlainText().strip()

        if not layName or not excel_or_csv_path:
            self.label.setText("请填写图层名称和文件路径")
            return

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

        try:
            if file_extension == '.csv':
                with open(excel_or_csv_path, 'rb') as f:
                    raw_data = f.read(2000)
                    result = chardet.detect(raw_data)
                    encoding = result['encoding']
                    if encoding.lower() == 'gb2312':
                        encoding = 'gbk'
                df = pd.read_csv(excel_or_csv_path, encoding=encoding, header=0)
            elif file_extension == '.xlsx':
                df = pd.read_excel(excel_or_csv_path, header=0)
            else:
                self.label.setText("不支持的文件格式")
                return
        except Exception as e:
            self.label.setText(f"读取文件失败: {e}")
            return

        self.writethread(df, layName)

    def writethread(self, df, layName):
        selected_header = self.comboBox.currentText().strip()
        df.columns = df.columns.str.strip()

        if selected_header not in df.columns:
            self.label.setText("选择的列不在文件中")
            return

        # 检测第一行数据的格式
        first_value = df[selected_header].iloc[0]
        if pd.isna(first_value):
            self.label.setText("第一行为空，无法检测格式")
            return
        first_str = str(first_value).strip()
        detected = self.detect_format(first_str)

        # 用户选择的格式
        user_wkt = self.radioButton.isChecked()  # True 表示 WKT
        user_format = 'wkt' if user_wkt else 'coord(x1,y1;x2,y2)'

        # 如果检测到格式且与用户选择不符，弹出警告
        if detected != 'unknown' and detected != user_format:
            msg = f"检测到数据格式为 '{detected}'，但您选择了 '{user_format}'。\n是否继续使用检测到的格式？"
            reply = QMessageBox.warning(self, "格式不匹配", msg,
                                        QMessageBox.Yes | QMessageBox.No,
                                        QMessageBox.No)
            if reply == QMessageBox.Yes:
                # 使用检测到的格式
                boolwkt = (detected == 'wkt')
            else:
                # 取消操作
                self.label.setText("已取消")
                return
        elif detected == 'unknown':
            # 无法检测，警告但可继续使用用户选择
            msg = "无法自动检测数据格式，将使用您选择的格式。\n如果绘制失败，请检查数据格式。"
            QMessageBox.information(self, "格式未知", msg)
            boolwkt = user_wkt
        else:
            # 匹配，使用用户选择
            boolwkt = user_wkt

        print(f"使用的格式: {'WKT' if boolwkt else '坐标串'}")

        # 继续处理
        print('开始线程...')
        self.progressBar.setRange(0, 100)
        self.progressBar.setValue(0)
        self.progressBar.show()

        # 移除已存在的同名图层
        for name in [layName, "SSJ绘制错误图形"]:
            layers = QgsProject.instance().mapLayersByName(name)
            for layer in layers:
                QgsProject.instance().removeMapLayer(layer.id())

        # 创建两个内存图层
        layer_good = QgsVectorLayer("Polygon?crs=EPSG:4326", layName, "memory")
        layer_bad = QgsVectorLayer("Polygon?crs=EPSG:4326", "SSJ绘制错误图形", "memory")

        self.export_thread = ExportThread(df, layer_good, layer_bad, selected_header, boolwkt)
        self.export_thread.progress.connect(self.update_progress)
        self.export_thread.updatelabel.connect(self.update_label)
        self.export_thread.finished.connect(self.on_thread_finished)
        self.export_thread.start()


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

    def __init__(self, dfs, layer_good, layer_bad, selected_headers, boolwkts):
        super().__init__()
        self.df = dfs
        self.layer_good = layer_good
        self.layer_bad = layer_bad
        self.selected_header = selected_headers
        self.boolwkt = boolwkts

    def run(self):
        countdf = len(self.df)
        provider_good = self.layer_good.dataProvider()
        provider_bad = self.layer_bad.dataProvider()

        # 准备字段
        fields = QgsFields()
        for column in self.df.columns:
            if column != self.selected_header:
                fields.append(QgsField(column, QVariant.String))

        provider_good.addAttributes(fields)
        self.layer_good.updateFields()
        provider_bad.addAttributes(fields)
        self.layer_bad.updateFields()

        for index, row in self.df.iterrows():
            try:
                wkt = str(row[self.selected_header])
                geom = None
                valid = False

                if self.boolwkt:  # WKT 分支
                    geom = QgsGeometry.fromWkt(wkt)
                    if geom and not geom.isEmpty():
                        valid = geom.isGeosValid()
                else:  # 坐标串分支
                    points = []
                    for pair in wkt.split(';'):
                        if not pair.strip():
                            continue
                        coords = pair.split(',')
                        if len(coords) == 2:
                            try:
                                lon = float(coords[0].strip())
                                lat = float(coords[1].strip())
                                points.append(QgsPointXY(lon, lat))
                            except ValueError:
                                pass
                    if len(points) > 2:
                        geom = QgsGeometry.fromPolygonXY([points])
                        if geom and not geom.isEmpty():
                            valid = geom.isGeosValid()
                    else:
                        self.updatelabel.emit(f"点数不足3，行 {index}")
                        continue

                if geom is None or geom.isEmpty():
                    self.updatelabel.emit(f"几何为空，行 {index}")
                    continue

                target_provider = provider_good if valid else provider_bad
                target_name = "正常" if valid else "错误"

                feature = QgsFeature(fields)
                feature.setGeometry(geom)
                for column in self.df.columns:
                    if column != self.selected_header:
                        feature[column] = row[column] if pd.notna(row[column]) else ""

                success, _ = target_provider.addFeatures([feature])
                if not success:
                    self.updatelabel.emit(f"添加要素失败，行 {index}")

                if not valid:
                    self.updatelabel.emit(f"无效几何，行 {index} 已放入错误图层")

            except Exception as e:
                self.updatelabel.emit(f"错误-行: {index}, {str(e)}")
                print(f"错误-行: {index}, {str(e)}")
                continue

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

        print('绘制完毕！')
        self.updatelabel.emit('绘制完毕！')