# -*- coding: utf-8 -*-
"""
Dialog to delete ArrayStorage raster data (and optionally metadata).
"""

import os

from qgis.PyQt import uic, QtWidgets
from qgis.PyQt.QtCore import QDateTime
from qgis.PyQt.QtWidgets import QDialogButtonBox, QMessageBox
from qgis.core import QgsProcessingException

from .arraystorage_core import (
    delete_data,
    delete_metadata,
    list_raster_timeseries,
    make_session,
    qdt_to_iso_with_tz,
)
from .arraystorage_settings import ArrayStorageSettingsStore
from qgis.core import QgsApplication, QgsAuthMethodConfig

FORM_CLASS_ARRAYSTORE_DELETE, _ = uic.loadUiType(
    os.path.join(os.path.dirname(__file__), "arraystorage_dialog_delete.ui")
)


class ArrayStorageDialogDelete(QtWidgets.QDialog, FORM_CLASS_ARRAYSTORE_DELETE):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)

        try:
            self.buttonBox.accepted.disconnect()
        except Exception:
            pass
        self.buttonBox.accepted.connect(self._on_delete_clicked)
        self.buttonBox.rejected.connect(self.reject)

        ok_btn = self.buttonBox.button(QDialogButtonBox.Ok)
        if ok_btn is not None:
            ok_btn.setText(self.tr("Delete"))

        # defaults
        now = QDateTime.currentDateTimeUtc()
        self.dtFrom.setDateTime(now)
        self.dtUntil.setDateTime(now)
        self.dtFrom.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
        self.dtUntil.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
        self.lineBaseUrl.setText("http://localhost:8013")

        self.chkLimitRange.toggled.connect(self._update_range_enabled)
        self.chkDeleteData.toggled.connect(self._update_range_enabled)
        self.chkDeleteMeta.toggled.connect(self._on_meta_toggled)
        self.btnRefreshPaths.clicked.connect(self._refresh_paths)
        self.comboTsPath.currentIndexChanged.connect(self._on_path_changed)
        self.comboConfig.currentIndexChanged.connect(self._apply_selected_config)
        self._reload_configs()
        self._update_range_enabled()
        self._refresh_paths(auto=True)

    def _update_range_enabled(self) -> None:
        enable = self.chkDeleteData.isChecked() and self.chkLimitRange.isChecked()
        for w in (
            self.dtFrom,
            self.dtUntil,
            self.lineT0,
            self.lineDispatch,
            self.lineMember,
        ):
            w.setEnabled(enable)

    def _on_meta_toggled(self) -> None:
        if self.chkDeleteMeta.isChecked():
            self.chkDeleteData.setChecked(True)
            self.chkLimitRange.setChecked(False)
            self._update_range_enabled()

    def _refresh_paths(self, auto: bool = False) -> None:
        base_url = self.lineBaseUrl.text().strip()
        as_user = self.lineUser.text().strip() or None
        as_pass = self.linePass.text().strip() or None

        if not base_url:
            if not auto:
                self._show_error(
                    self.tr("Missing Base URL"),
                    self.tr("Base URL is required to refresh paths."),
                )
            return

        try:
            session = make_session(as_user, as_pass)
            items = list_raster_timeseries(
                base_url, session, store_id=self.lineStoreId.text().strip() or None
            )
            self.comboTsPath.blockSignals(True)
            self.comboTsPath.clear()
            for ts in items:
                path = str(ts.get("path") or "").strip()
                ts_id = str(
                    ts.get("timeseriesId")
                    or ts.get("timeSeriesId")
                    or ts.get("id")
                    or ""
                ).strip()
                label = path or ts_id or "<unknown>"
                self.comboTsPath.addItem(label, path or ts_id)
            self.comboTsPath.blockSignals(False)
            if self.comboTsPath.count() > 0:
                self.comboTsPath.setCurrentIndex(0)
        except Exception as e:
            if not auto:
                self._show_error(
                    self.tr("Refresh failed"),
                    self.tr(f"Could not fetch raster time series:\n{e}"),
                )

    def _on_path_changed(self, idx: int) -> None:
        # Keep editable text in sync; no-op needed because editable combo already sets currentText
        pass

    def _resolve_credentials_from_authcfg(
        self, authcfg: str | None
    ) -> tuple[str | None, str | None]:
        if not authcfg:
            return None, None
        try:
            cfg = QgsAuthMethodConfig()
            if QgsApplication.authManager().loadAuthenticationConfig(
                authcfg, cfg, True
            ):
                return cfg.config("username") or None, cfg.config("password") or None
        except Exception:
            pass
        return None, None

    def _reload_configs(self) -> None:
        store = ArrayStorageSettingsStore()
        configs = store.list()
        self.comboConfig.blockSignals(True)
        self.comboConfig.clear()
        for cfg in configs:
            label = f"{cfg.name} ({cfg.base_url})"
            self.comboConfig.addItem(label, cfg)
        self.comboConfig.blockSignals(False)
        if self.comboConfig.count() > 0:
            self.comboConfig.setCurrentIndex(0)
            self._apply_selected_config()

    def _apply_selected_config(self) -> None:
        idx = self.comboConfig.currentIndex()
        cfg = self.comboConfig.itemData(idx)
        if not cfg:
            return
        self.lineBaseUrl.setText(str(cfg.base_url or "").strip())
        user_from_auth, pass_from_auth = self._resolve_credentials_from_authcfg(
            getattr(cfg, "authcfg", None)
        )
        if user_from_auth:
            self.lineUser.setText(user_from_auth)
        if pass_from_auth:
            self.linePass.setText(pass_from_auth)

    def _show_error(self, title: str, msg: str) -> None:
        QMessageBox.critical(self, title, msg)

    def _on_delete_clicked(self) -> None:
        if self.perform_delete():
            self.accept()

    def perform_delete(self) -> bool:
        base_url = self.lineBaseUrl.text().strip()
        as_user = self.lineUser.text().strip() or None
        as_pass = self.linePass.text().strip() or None
        store_id = self.lineStoreId.text().strip() or None
        ts_path = self.comboTsPath.currentText().strip()

        delete_data_flag = self.chkDeleteData.isChecked()
        delete_meta_flag = self.chkDeleteMeta.isChecked()
        limit_range = self.chkLimitRange.isChecked()

        if not base_url or not ts_path:
            self._show_error(
                self.tr("Missing information"),
                self.tr("Base URL and timeseries path are required."),
            )
            return False

        if delete_meta_flag and not delete_data_flag:
            self._show_error(
                self.tr("Invalid selection"),
                self.tr("Metadata delete requires deleting the data as well."),
            )
            return False

        # If metadata delete requested, we must delete ALL data (no filters)
        if delete_meta_flag and limit_range:
            self._show_error(
                self.tr("Invalid selection"),
                self.tr(
                    "To delete metadata, delete the full dataset (turn off range limits)."
                ),
            )
            return False

        try:
            session = make_session(as_user, as_pass)

            # 1) delete data if requested
            if delete_data_flag:
                from_iso = None
                until_iso = None
                t0_iso = None
                dispatch_info = None
                member = None

                if limit_range:
                    from_dt = self.dtFrom.dateTime()
                    until_dt = self.dtUntil.dateTime()
                    from_iso = (
                        qdt_to_iso_with_tz(from_dt) if from_dt.isValid() else None
                    )
                    until_iso = (
                        qdt_to_iso_with_tz(until_dt) if until_dt.isValid() else None
                    )
                    t0_iso = self.lineT0.text().strip() or None
                    dispatch_info = self.lineDispatch.text().strip() or None
                    member = self.lineMember.text().strip() or None

                delete_data(
                    base_url,
                    ts_path,
                    store_id=store_id,
                    from_iso=from_iso,
                    until_iso=until_iso,
                    t0_iso=t0_iso,
                    member=member,
                    dispatch_info=dispatch_info,
                    session=session,
                )

            # 2) delete metadata if requested
            if delete_meta_flag:
                delete_metadata(
                    base_url,
                    ts_paths=[ts_path],
                    store_id=store_id,
                    delete_parent_metadata=False,
                    delete_groups=False,
                    mode="strict",
                    session=session,
                )

            QMessageBox.information(
                self,
                self.tr("Delete complete"),
                self.tr("Selected ArrayStorage content was deleted."),
            )
            return True
        except QgsProcessingException as e:
            self._show_error(self.tr("Delete failed"), str(e))
            return False
        except Exception as e:
            self._show_error(
                self.tr("Delete failed"),
                self.tr(f"Unexpected error:\n{e}"),
            )
            return False
