import csv
import json
import os

import numpy as np
from qgis.PyQt import QtWidgets

from ..compat import CHECKED, ITEM_FLAG_CHECKABLE, SPSZ_EXPANDING, SPSZ_MINIMUM, UNCHECKED, USER_ROLE

try:
    import pandas as pd
except ImportError:
    pd = None

from .frm_export_base import get_unique_export_path, sanitize_file_base_name
from .utilities import add_help_button


class FrmGeospatialMetricsExport(QtWidgets.QDialog):
    def __init__(self, parent, project, mask, polygons, metrics):
        super().__init__(parent)
        self.setWindowTitle("Export Geospatial Metrics")
        self.project = project
        self.base_name = "Geospatial Metrics"
        self.file_base_name = sanitize_file_base_name(self.base_name)
        self.last_generated_path = None
        self.metrics = metrics
        self.polygons = polygons

        self.setupUi()

    def browse_path(self):
        ext = self.get_current_extension()
        filter = f"Current Format (*{ext});;All Files (*.*)"
        initial = self.txtOutpath.text()
        folder = os.path.dirname(initial) if initial else ""
        path, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Save Export File", folder, filter)
        if path:
            self.txtOutpath.setText(os.path.normpath(path))

    def get_current_extension(self):
        if self.radioJson.isChecked():
            return ".json"
        if self.radioCsv.isChecked():
            return ".csv"
        return ".xlsx"

    def update_default_path(self):
        home = getattr(self.project, "project_file", None)
        if not home:
            return

        if os.path.isfile(home):
            home = os.path.dirname(home)

        export_dir = os.path.join(home, "exports", self.file_base_name)
        if not os.path.exists(export_dir):
            os.makedirs(export_dir, exist_ok=True)

        default_path = get_unique_export_path(export_dir, self.file_base_name, self.get_current_extension())
        self.txtOutpath.setText(os.path.normpath(default_path))
        self.last_generated_path = self.txtOutpath.text()

    def on_type_changed(self):
        current_path = self.txtOutpath.text()
        if not current_path:
            self.update_default_path()
            return

        if current_path == self.last_generated_path:
            self.update_default_path()
            return

        file, _ext = os.path.splitext(current_path)
        self.txtOutpath.setText(file + self.get_current_extension())

    def export(self):

        path = self.txtOutpath.text()
        if not path:
            QtWidgets.QMessageBox.warning(self, "Export", "Please specify an export file path.")
            return

        selected = [self.listWidget.item(i).data(USER_ROLE) for i in range(self.listWidget.count()) if self.listWidget.item(i).checkState() == CHECKED]
        if not selected:
            QtWidgets.QMessageBox.warning(self, "Export", "No metrics selected.")
            return

        # Gather selected data
        export_data = []
        for layer_name, polygon_id, metric_name in selected:
            value = self.metrics[layer_name][polygon_id][metric_name]
            # Convert numpy types to native Python types for JSON serialization
            if isinstance(value, (np.generic,)):
                value = value.item()
            export_data.append({"layer": layer_name, "polygon": self.polygons[polygon_id]["display_label"], "metric": metric_name, "value": value})

        # Choose file
        if self.radioJson.isChecked():
            fmt = "json"
        elif self.radioCsv.isChecked():
            fmt = "csv"
        else:
            fmt = "xlsx"

        # Export
        try:
            if fmt == "json":
                with open(path, "w", encoding="utf-8") as f:
                    json.dump(export_data, f, indent=2)
            elif fmt == "csv":
                with open(path, "w", newline="", encoding="utf-8") as f:
                    writer = csv.DictWriter(f, fieldnames=["layer", "polygon", "metric", "value"])
                    writer.writeheader()
                    writer.writerows(export_data)
            else:  # xlsx
                if pd is None:
                    QtWidgets.QMessageBox.warning(self, "Export", "pandas is required for XLSX export.")
                    return
                df = pd.DataFrame(export_data)
                df.to_excel(path, index=False)
            QtWidgets.QMessageBox.information(self, "Export", "Export successful!")
            self.accept()
        except Exception as ex:
            QtWidgets.QMessageBox.critical(self, "Export Error", str(ex))

    def setupUi(self):
        self.resize(400, 400)
        layout = QtWidgets.QVBoxLayout(self)

        # List of metrics as checkboxes
        self.lblInstructions = QtWidgets.QLabel("Select metrics to export:")
        layout.addWidget(self.lblInstructions)
        self.listWidget = QtWidgets.QListWidget(self)
        for layer_name, values in self.metrics.items():
            for polygon_id, poly_values in values.items():
                polygon_label = self.polygons[polygon_id]["display_label"]
                for metric_name, _metric_value in poly_values.items():
                    item = QtWidgets.QListWidgetItem(f"{layer_name} - {polygon_label} - {metric_name}")
                    item.setData(USER_ROLE, (layer_name, polygon_id, metric_name))
                    item.setFlags(item.flags() | ITEM_FLAG_CHECKABLE)
                    item.setCheckState(CHECKED)
                    self.listWidget.addItem(item)
        layout.addWidget(self.listWidget)
        self.listWidget.setMinimumHeight(200)
        self.listWidget.setMinimumWidth(300)

        # add select all and select none buttons
        btnLayout = QtWidgets.QHBoxLayout()
        btnSelectAll = QtWidgets.QPushButton("Select All")
        btnSelectAll.clicked.connect(lambda: [self.listWidget.item(i).setCheckState(CHECKED) for i in range(self.listWidget.count())])
        btnSelectNone = QtWidgets.QPushButton("Select None")
        btnSelectNone.clicked.connect(lambda: [self.listWidget.item(i).setCheckState(UNCHECKED) for i in range(self.listWidget.count())])
        btnLayout.addSpacerItem(QtWidgets.QSpacerItem(20, 20, SPSZ_EXPANDING, SPSZ_MINIMUM))
        btnLayout.addWidget(btnSelectAll)
        btnLayout.addWidget(btnSelectNone)
        layout.addLayout(btnLayout)

        # Export format
        info_layout = QtWidgets.QHBoxLayout()
        info_layout.addWidget(QtWidgets.QLabel("Exporting:"))
        info_layout.addWidget(QtWidgets.QLabel(f"<b>{self.base_name}</b>"))
        info_layout.addStretch()
        layout.addLayout(info_layout)

        self.lblFormat = QtWidgets.QLabel("Output Format:")
        self.formatGroup = QtWidgets.QButtonGroup(self)
        self.radioJson = QtWidgets.QRadioButton("JSON")
        self.radioCsv = QtWidgets.QRadioButton("CSV")
        self.radioXls = QtWidgets.QRadioButton("XLSX")
        self.radioJson.setChecked(True)
        self.formatGroup.addButton(self.radioJson)
        self.formatGroup.addButton(self.radioCsv)
        self.formatGroup.addButton(self.radioXls)
        self.formatGroup.buttonClicked.connect(self.on_type_changed)
        fmtLayout = QtWidgets.QHBoxLayout()
        fmtLayout.addWidget(self.lblFormat)
        fmtLayout.addStretch()
        fmtLayout.addWidget(self.radioJson)
        fmtLayout.addWidget(self.radioCsv)
        fmtLayout.addWidget(self.radioXls)
        layout.addLayout(fmtLayout)

        horizontalLayout = QtWidgets.QHBoxLayout()
        self.lblPath = QtWidgets.QLabel("Output Path:")
        horizontalLayout.addWidget(self.lblPath)
        self.txtOutpath = QtWidgets.QLineEdit(self)
        self.txtOutpath.setPlaceholderText("Choose export file path")
        self.txtOutpath.setReadOnly(True)
        horizontalLayout.addWidget(self.txtOutpath)
        self.btnBrowse = QtWidgets.QPushButton("...")
        self.btnBrowse.setFixedWidth(30)
        self.btnBrowse.clicked.connect(self.browse_path)
        horizontalLayout.addWidget(self.btnBrowse)
        layout.addLayout(horizontalLayout)

        self.update_default_path()

        horiz_bottom = QtWidgets.QHBoxLayout()
        layout.addLayout(horiz_bottom)

        horiz_bottom.addWidget(add_help_button(self, "zonal-statistics#export"))
        horiz_bottom.addStretch()

        # Export button
        btnExport = QtWidgets.QPushButton("Export")
        btnExport.clicked.connect(self.export)
        horiz_bottom.addWidget(btnExport)

        # Add cancel button
        self.btnCancel = QtWidgets.QPushButton("Cancel")
        self.btnCancel.clicked.connect(self.reject)
        horiz_bottom.addWidget(self.btnCancel)
