# -*- coding: utf-8 -*-
"""
Local persistence for Datasphere connection presets.
Non-sensitive data are stored in JSON; credentials are stored in QGIS auth DB.
"""

from __future__ import annotations

import json
import os
from dataclasses import dataclass, asdict
from typing import Optional, List

from qgis.core import QgsApplication, QgsAuthMethodConfig


@dataclass
class DatasphereConfig:
    name: str
    base_url: str
    ds_id: Optional[str] = None
    username: Optional[str] = None
    authcfg: Optional[str] = None

    @staticmethod
    def from_dict(data: dict) -> "DatasphereConfig":
        return DatasphereConfig(
            name=str(data.get("name") or "").strip(),
            base_url=str(data.get("base_url") or "").strip(),
            ds_id=(str(data.get("ds_id")).strip() or None)
            if data.get("ds_id") is not None
            else None,
            username=(str(data.get("username")).strip() or None)
            if data.get("username") is not None
            else None,
            authcfg=str(data.get("authcfg")).strip() or None,
        )


class DatasphereSettingsStore:
    def __init__(self) -> None:
        self._path = os.path.join(
            QgsApplication.qgisSettingsDirPath(),
            "network-store-qgis",
            "datasphere_settings.json",
        )
        os.makedirs(os.path.dirname(self._path), exist_ok=True)

    def _upsert_authcfg(
        self, username: str, password: str, existing_authcfg: Optional[str]
    ) -> str:
        authm = QgsApplication.authManager()
        cfg = QgsAuthMethodConfig()
        cfg.setName(existing_authcfg or f"datasphere:{username}")
        cfg.setMethod("Basic")
        cfg.setConfig("username", username)
        cfg.setConfig("password", password)
        authm.storeAuthenticationConfig(cfg)
        return cfg.id()

    def _delete_authcfg(self, authcfg: Optional[str]) -> None:
        if not authcfg:
            return
        try:
            QgsApplication.authManager().removeAuthenticationConfig(authcfg)
        except Exception:
            pass

    def _read_all(self) -> List[DatasphereConfig]:
        try:
            with open(self._path, "r", encoding="utf-8") as f:
                data = json.load(f)
        except Exception:
            return []
        if not isinstance(data, list):
            return []
        configs: List[DatasphereConfig] = []
        for item in data:
            try:
                cfg = DatasphereConfig.from_dict(item)
                if cfg.name:
                    configs.append(cfg)
            except Exception:
                continue
        return configs

    def _write_all(self, configs: List[DatasphereConfig]) -> None:
        serialized = [asdict(c) for c in configs]
        with open(self._path, "w", encoding="utf-8") as f:
            json.dump(serialized, f, indent=2, ensure_ascii=False)

    def list(self) -> List[DatasphereConfig]:
        return self._read_all()

    def get(self, name: str) -> Optional[DatasphereConfig]:
        name = name.strip()
        for cfg in self._read_all():
            if cfg.name == name:
                return cfg
        return None

    def add_or_update(
        self,
        name: str,
        base_url: str,
        ds_id: Optional[str],
        username: Optional[str],
        password: Optional[str],
    ) -> DatasphereConfig:
        name = name.strip()
        base_url = base_url.strip()
        ds_id = ds_id.strip() if ds_id else None
        if not name or not base_url:
            raise ValueError("Name and base_url are required.")

        configs = self._read_all()
        existing = None
        for cfg in configs:
            if cfg.name == name:
                existing = cfg
                break

        authcfg = existing.authcfg if existing else None
        if username and password:
            authcfg = self._upsert_authcfg(username, password, authcfg)

        new_cfg = DatasphereConfig(
            name=name,
            base_url=base_url,
            ds_id=ds_id,
            username=username or (existing.username if existing else None),
            authcfg=authcfg,
        )

        if existing:
            configs = [new_cfg if c.name == name else c for c in configs]
        else:
            configs.append(new_cfg)
        self._write_all(configs)
        return new_cfg

    def delete(self, name: str) -> bool:
        name = name.strip()
        configs = self._read_all()
        removed = False
        keep: List[DatasphereConfig] = []
        for cfg in configs:
            if cfg.name == name:
                removed = True
                self._delete_authcfg(cfg.authcfg)
            else:
                keep.append(cfg)
        if removed:
            self._write_all(keep)
        return removed
