from qgis.PyQt.QtGui import QFont
from qgis.PyQt.QtWidgets import QCheckBox, QDialog, QDialogButtonBox, QFileDialog, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QMessageBox, QPushButton, QRadioButton, QSpacerItem, QTabWidget, QVBoxLayout, QWidget

from ..compat import (
    ALIGN_TOP,
    CHECKED,
    DLG_ACCEPTED,
    DLGBTN_CANCEL,
    DLGBTN_OK,
    MSGBOX_NO,
    MSGBOX_YES,
    PLAIN_TEXT,
    RICH_TEXT,
    SPSZ_EXPANDING,
    SPSZ_MINIMUM,
)
from ..lib.climate_engine import clear_api_key, get_api_key, open_climate_engine_website
from ..lib.font_tools import sanitize_chart_font, select_chart_font
from ..model.project import Project
from ..QRiS.protocol_parser import LOCAL_PROTOCOL_FOLDER, SHOW_EXPERIMENTAL_PROTOCOLS
from ..QRiS.settings import Settings
from .frm_api_key import FrmApiKey
from .frm_export_project import DEFAULT_EXPORT_PATH
from .utilities import add_help_button

DOCK_WIDGET_LOCATION = "dock_widget_location"
REMOVE_LAYERS_ON_CLOSE = "remove_layers_on_close"
TELEMETRY_ENABLED_KEY = "telemetryEnabled"
DEFAULT_CHART_FONT = "default_chart_font"
SELECTION_COLOR_OVERRIDE_ENABLED = "selectionColorOverrideEnabled"

default_dock_widget_location = "right"


def _as_bool(value, default=False) -> bool:
    if value is None:
        return default
    if isinstance(value, bool):
        return value
    if isinstance(value, str):
        return value.strip().lower() in {"1", "true", "yes", "on"}
    return bool(value)


def get_default_chart_font() -> QFont:
    font_text = Settings().getValue(DEFAULT_CHART_FONT)

    if font_text:
        font = QFont()
        if font.fromString(font_text):
            if font.pointSize() <= 0:
                font.setPointSize(10)
            return sanitize_chart_font(font)

    return sanitize_chart_font(QFont("Sans Serif", 10))


def set_default_chart_font(font: QFont):
    if font:
        Settings().setValue(DEFAULT_CHART_FONT, font.toString())


class FrmSettings(QDialog):
    def __init__(self, qris_project: Project):
        super().__init__()

        self.s = Settings()
        self.qris_project = qris_project
        self.levels = {}
        self.units = {}

        self.setWindowTitle("QRiS Settings")
        self.setup_ui()

        # Get the dockwidget location from the settings
        dock_location = self.s.getValue(DOCK_WIDGET_LOCATION) or default_dock_widget_location
        self.left_radio.setChecked(dock_location == "left")
        self.right_radio.setChecked(dock_location == "right")

        # Get the remove layers on close setting
        remove_layers_on_close = _as_bool(self.s.getValue(REMOVE_LAYERS_ON_CLOSE), default=True)
        self.chk_remove_layers_on_close.setChecked(remove_layers_on_close)

        # Get the default export path
        default_export_path = self.s.getValue(DEFAULT_EXPORT_PATH) or ""
        self.txt_path_export.setText(default_export_path)

        # Get the local protocol folder
        protocol_folder = self.s.getValue(LOCAL_PROTOCOL_FOLDER) or ""
        self.txt_protocol_folder.setText(protocol_folder)

        show_experimental_protocols = _as_bool(self.s.getValue(SHOW_EXPERIMENTAL_PROTOCOLS), default=False)
        self.chkShowExperimentalProtocols.setChecked(show_experimental_protocols)
        self.chkShowExperimentalProtocols.stateChanged.connect(self.on_show_experimental_changed)

        self.chk_telemetry.setChecked(_as_bool(self.s.getValue(TELEMETRY_ENABLED_KEY), default=False))
        self.chk_selection_color_override.setChecked(_as_bool(self.s.getValue(SELECTION_COLOR_OVERRIDE_ENABLED), default=False))

        self.default_chart_font = get_default_chart_font()
        self.update_chart_font_button_text()

        self._refresh_api_key_status()

    def accept(self):

        if self.left_radio.isChecked():
            self.s.setValue(DOCK_WIDGET_LOCATION, "left")
        else:
            self.s.setValue(DOCK_WIDGET_LOCATION, "right")

        self.s.setValue(REMOVE_LAYERS_ON_CLOSE, self.chk_remove_layers_on_close.isChecked())

        if self.txt_path_export.text() != "":
            self.s.setValue(DEFAULT_EXPORT_PATH, self.txt_path_export.text())
        else:
            self.s.setValue(DEFAULT_EXPORT_PATH, "")

        if self.txt_protocol_folder.text() != "":
            self.s.setValue(LOCAL_PROTOCOL_FOLDER, self.txt_protocol_folder.text())
        else:
            self.s.setValue(LOCAL_PROTOCOL_FOLDER, "")

        self.s.setValue(SHOW_EXPERIMENTAL_PROTOCOLS, self.chkShowExperimentalProtocols.isChecked())
        set_default_chart_font(self.default_chart_font)

        self.s.setValue(TELEMETRY_ENABLED_KEY, self.chk_telemetry.isChecked())
        self.s.setValue(SELECTION_COLOR_OVERRIDE_ENABLED, self.chk_selection_color_override.isChecked())

        super().accept()

    def select_export_path(self):
        path = QFileDialog.getExistingDirectory(self, "Select default export path")
        if path:
            self.txt_path_export.setText(path)

    def select_protocol_folder(self):
        path = QFileDialog.getExistingDirectory(self, "Select local protocol folder")
        if path:
            self.txt_protocol_folder.setText(path)

    def on_show_experimental_changed(self, state):
        if state == CHECKED:
            QMessageBox.warning(
                self,
                "Experimental Protocols",
                "Experimental protocols are protocols that are still under development and testing. They may not be fully functional and can change without notice. Please backup your project before using and proceed with caution.",
            )

    def select_chart_font(self):
        font, ok = select_chart_font(self, self.default_chart_font, "Select Default Chart Font")
        if ok:
            self.default_chart_font = font
            self.update_chart_font_button_text()

    def update_chart_font_button_text(self):
        self.btn_chart_font.setText(f"{self.default_chart_font.family()} {self.default_chart_font.pointSize()}pt")

    def open_api_key_dialog(self):
        dlg = FrmApiKey(self)
        if dlg.exec() == DLG_ACCEPTED:
            self._refresh_api_key_status()

    def remove_api_key(self):
        reply = QMessageBox.question(self, "Remove API Key", "Are you sure you want to remove the Climate Engine API key?", MSGBOX_YES | MSGBOX_NO, MSGBOX_NO)
        if reply == MSGBOX_YES:
            clear_api_key()
            self._refresh_api_key_status()

    def _refresh_api_key_status(self):
        api_key = get_api_key()
        if api_key:
            self.lbl_api_key_status.setText('<span style="color:green;">Configured &#10004;</span>')
            self.btn_remove_api_key.setEnabled(True)
        else:
            self.lbl_api_key_status.setText("Not configured")
            self.btn_remove_api_key.setEnabled(False)

    def setup_ui(self):

        self.resize(500, 300)
        self.setMinimumSize(500, 300)

        self.vert = QVBoxLayout(self)
        self.setLayout(self.vert)
        self.tabs = QTabWidget()
        self.vert.addWidget(self.tabs)

        # General Tab
        self.vertGeneral = QVBoxLayout()

        horiz_export_path = QHBoxLayout()
        self.vertGeneral.addLayout(horiz_export_path)

        lbl_path_export = QLabel("Default Export Path")
        horiz_export_path.addWidget(lbl_path_export)

        self.txt_path_export = QLineEdit()
        self.txt_path_export.setReadOnly(True)
        horiz_export_path.addWidget(self.txt_path_export)

        btn_path_export = QPushButton("...")
        btn_path_export.setFixedWidth(30)
        btn_path_export.clicked.connect(self.select_export_path)
        horiz_export_path.addWidget(btn_path_export)

        btn_clear_path_export = QPushButton("Clear")
        btn_clear_path_export.clicked.connect(lambda: self.txt_path_export.setText(""))
        horiz_export_path.addWidget(btn_clear_path_export)

        horiz_chart_font = QHBoxLayout()
        self.vertGeneral.addLayout(horiz_chart_font)

        lbl_chart_font = QLabel("Default Chart Font")
        horiz_chart_font.addWidget(lbl_chart_font)

        self.btn_chart_font = QPushButton()
        self.btn_chart_font.setToolTip("Software default for chart text. Individual charts can override this setting.")
        self.btn_chart_font.clicked.connect(self.select_chart_font)
        horiz_chart_font.addWidget(self.btn_chart_font)

        horiz_chart_font.addStretch(1)

        self.chk_remove_layers_on_close = QCheckBox("Remove QRiS Project map layers on project close")
        self.chk_remove_layers_on_close.setToolTip("Check this box to remove all layers from the project when it is closed.")
        self.vertGeneral.addWidget(self.chk_remove_layers_on_close)

        self.chk_selection_color_override = QCheckBox("Override feature selection color for QRiS layers")
        self.chk_selection_color_override.setToolTip("Uses white (#ffffff) with 30% transparency so selected features remain visible while editing.")
        self.vertGeneral.addWidget(self.chk_selection_color_override)

        self.grid = QGridLayout()

        self.label = QLabel("Default Dock widget location")
        self.grid.addWidget(self.label, 0, 0, 1, 2)

        self.left_radio = QRadioButton("Dock to left")
        self.right_radio = QRadioButton("Dock to right")
        self.grid.addWidget(self.left_radio, 1, 0)
        self.grid.addWidget(self.right_radio, 1, 1)

        self.vertGeneral.addLayout(self.grid)
        self.vertGeneral.addStretch(1)

        self.chk_telemetry = QCheckBox("Help improve the software by sharing anonymous usage data.")
        self.vertGeneral.addWidget(self.chk_telemetry)

        self.button_box = QDialogButtonBox(DLGBTN_OK | DLGBTN_CANCEL)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)

        self.horiz_buttons = QHBoxLayout()
        self.horiz_buttons.addWidget(add_help_button(self, "toolbar#settings"))
        self.horiz_buttons.addItem(QSpacerItem(40, 20, SPSZ_EXPANDING, SPSZ_MINIMUM))
        self.horiz_buttons.addWidget(self.button_box)
        self.vert.addLayout(self.horiz_buttons)

        self.tabSettings = QWidget()
        self.tabs.addTab(self.tabSettings, "General")
        self.tabSettings.setLayout(self.vertGeneral)

        # Protocools Tab
        self.protocol_layout = QVBoxLayout()

        self.horiz_protocol_folder = QHBoxLayout()
        self.protocol_layout.addLayout(self.horiz_protocol_folder)

        lbl_protocol_folder = QLabel("Local Custom Protocols Folder")
        self.horiz_protocol_folder.addWidget(lbl_protocol_folder)
        self.txt_protocol_folder = QLineEdit()
        self.txt_protocol_folder.setReadOnly(True)
        self.txt_protocol_folder.setToolTip("Select an optional folder to store custom protocols.")
        self.horiz_protocol_folder.addWidget(self.txt_protocol_folder)
        btn_protocol_folder = QPushButton("...")
        btn_protocol_folder.setFixedWidth(40)
        btn_protocol_folder.clicked.connect(self.select_protocol_folder)
        self.horiz_protocol_folder.addWidget(btn_protocol_folder)

        self.chkShowExperimentalProtocols = QCheckBox("Show experimental protocols")
        self.chkShowExperimentalProtocols.setToolTip("Check this box to show experimental protocols in the protocol list. Experimental protocols are protocols that are still under development and testing.")
        self.protocol_layout.addWidget(self.chkShowExperimentalProtocols)

        self.protocol_layout.addStretch(1)
        self.protocol_layout.setAlignment(ALIGN_TOP)

        self.tabProtocols = QWidget()
        self.tabProtocols.setLayout(self.protocol_layout)
        self.tabs.addTab(self.tabProtocols, "Protocols")

        # Climate Engine Tab
        climate_engine_layout = QVBoxLayout()

        lbl_climate_engine_text = QLabel(
            "Climate Engine is a third-party service accessing climate and Earth observation data. QRiS connects to the Climate Engine API to retrieve these data for use in your QRiS projects. Use the buttons below to request a Climate "
            "Engine API key and then set the key so QRiS can use your account when accessing Climate Engine data."
        )
        lbl_climate_engine_text.setTextFormat(PLAIN_TEXT)
        lbl_climate_engine_text.setWordWrap(True)
        climate_engine_layout.addWidget(lbl_climate_engine_text)

        horiz_api_key = QHBoxLayout()
        climate_engine_layout.addLayout(horiz_api_key)

        horiz_api_key.addWidget(QLabel("API Key:"))

        self.lbl_api_key_status = QLabel()
        self.lbl_api_key_status.setTextFormat(RICH_TEXT)
        horiz_api_key.addWidget(self.lbl_api_key_status, 1)

        btn_set_api_key = QPushButton("Set Key…")
        btn_set_api_key.clicked.connect(self.open_api_key_dialog)
        horiz_api_key.addWidget(btn_set_api_key)

        self.btn_remove_api_key = QPushButton("Remove")
        self.btn_remove_api_key.clicked.connect(self.remove_api_key)
        horiz_api_key.addWidget(self.btn_remove_api_key)

        climate_engine_layout.addStretch(1)

        horiz_buttons_layout = QHBoxLayout()
        climate_engine_layout.addLayout(horiz_buttons_layout)

        btn_climate_engine_url = QPushButton("About Climate Engine")
        btn_climate_engine_url.clicked.connect(lambda: open_climate_engine_website())
        horiz_buttons_layout.addWidget(btn_climate_engine_url)

        btn_request_api_key = QPushButton("Request API key")
        btn_request_api_key.clicked.connect(lambda: open_climate_engine_website("/apis/requesting-an-authorization-key-token/"))
        horiz_buttons_layout.addWidget(btn_request_api_key)

        horiz_buttons_layout.addStretch(1)

        self.tabClimateEngine = QWidget()
        self.tabClimateEngine.setLayout(climate_engine_layout)
        self.tabs.addTab(self.tabClimateEngine, "Climate Engine")
