from __future__ import annotations

import json
import os
import stat
from dataclasses import dataclass
from pathlib import Path


class ConfigError(Exception):
    """Raised when required configuration is missing."""


CONFIG_DIR = Path.home() / ".dattos"

_profile_override: str | None = None


@dataclass(frozen=True)
class DattosConfig:
    api_url: str
    api_key: str
    folder_id: str
    folder_name: str


def set_profile_override(profile: str | None) -> None:
    """Set the active profile override (called by --profile flag)."""
    global _profile_override
    _profile_override = profile


def get_active_profile() -> str:
    """Return the active profile name. Priority: override > env > global config > 'default'."""
    if _profile_override:
        return _profile_override
    env = os.environ.get("DATTOS_PROFILE")
    if env:
        return env
    global_cfg = _load_global_config()
    return global_cfg.get("active_profile", "default")


def get_profile_config_path(profile: str) -> Path:
    """Return the config file path for a named profile."""
    return CONFIG_DIR / "profiles" / profile / "config.json"


def _load_global_config() -> dict:
    """Load the global config (~/.dattos/config.json)."""
    path = CONFIG_DIR / "config.json"
    if path.exists():
        return json.loads(path.read_text())
    return {}


def _ensure_migrated() -> None:
    """Migrate old flat config.json to profiles/default/ if needed."""
    global_path = CONFIG_DIR / "config.json"
    if not global_path.exists():
        return

    try:
        data = json.loads(global_path.read_text())
    except (json.JSONDecodeError, OSError):
        return

    if "active_profile" in data:
        return

    if not ("api_url" in data or "api_key" in data):
        return

    profile_dir = CONFIG_DIR / "profiles" / "default"
    profile_dir.mkdir(parents=True, exist_ok=True)
    profile_path = profile_dir / "config.json"
    profile_path.write_text(json.dumps(data, indent=2))

    global_path.write_text(json.dumps({"active_profile": "default"}, indent=2))

    if os.name != "nt":
        os.chmod(profile_dir, stat.S_IRWXU)
        os.chmod(profile_path, stat.S_IRUSR | stat.S_IWUSR)


def _load_profile_config() -> dict:
    """Load config from the active profile."""
    _ensure_migrated()
    profile = get_active_profile()
    path = get_profile_config_path(profile)
    if path.exists():
        return json.loads(path.read_text())
    return {}


def get_config() -> DattosConfig:
    """Load config from env vars, falling back to profile config file."""
    file_cfg = _load_profile_config()

    profile = get_active_profile()

    api_url = os.environ.get("DATTOS_API_URL") or file_cfg.get("api_url", "")
    # Auth priority: env var > session token (keyring) > api key (keyring) > api key (file)
    from dattos_sdk.credentials import get_secret
    api_key = (
        os.environ.get("DATTOS_API_KEY")
        or get_secret(profile, "session_token")
        or get_secret(profile, "api_key")
        or file_cfg.get("api_key", "")
    )
    folder_id = os.environ.get("DATTOS_FOLDER_ID") or file_cfg.get("folder_id", "")
    folder_name = file_cfg.get("folder_name", "")

    if not api_url:
        raise ConfigError("DATTOS_API_URL is required. Set it via env var or `dattos config set api-url <url>`.")
    if not api_url.startswith("https://"):
        raise ConfigError("DATTOS_API_URL must use HTTPS. Insecure HTTP is not allowed.")
    if not api_key:
        raise ConfigError("DATTOS_API_KEY is required. Set it via env var or `dattos config set api-key <key>`.")

    return DattosConfig(
        api_url=api_url.rstrip("/"),
        api_key=api_key,
        folder_id=folder_id,
        folder_name=folder_name,
    )


def _write_profile_config(data: dict) -> None:
    """Write config to the active profile's config file."""
    profile = get_active_profile()
    profile_dir = CONFIG_DIR / "profiles" / profile
    profile_dir.mkdir(parents=True, exist_ok=True)
    path = profile_dir / "config.json"
    path.write_text(json.dumps(data, indent=2))
    if os.name != "nt":
        os.chmod(profile_dir, stat.S_IRWXU)
        os.chmod(path, stat.S_IRUSR | stat.S_IWUSR)


def save_folder(folder_id: str, folder_name: str) -> None:
    """Persist the selected folder to the active profile config."""
    cfg = _load_profile_config()
    cfg["folder_id"] = folder_id
    cfg["folder_name"] = folder_name
    _write_profile_config(cfg)


def save_config(key: str, value: str) -> None:
    """Persist a config key to the active profile config."""
    cfg = _load_profile_config()
    cfg[key] = value
    _write_profile_config(cfg)


def set_active_profile(profile: str) -> None:
    """Set the active profile in the global config."""
    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    global_path = CONFIG_DIR / "config.json"
    data = _load_global_config()
    data["active_profile"] = profile
    global_path.write_text(json.dumps(data, indent=2))
    if os.name != "nt":
        os.chmod(global_path, stat.S_IRUSR | stat.S_IWUSR)


def list_profiles() -> list[str]:
    """List all profile names."""
    profiles_dir = CONFIG_DIR / "profiles"
    if not profiles_dir.exists():
        return []
    return sorted(d.name for d in profiles_dir.iterdir() if d.is_dir())
