"""Persistent config store — replaces .env for installed-app users.

Reads and writes ``{data_root}/config/local/settings.json``.
For desktop installer users who don't have a ``.env`` file, this is the
primary config source.  For developers, ``.env`` takes priority.

Priority order (highest wins):
  1. Environment variable (e.g. ``OPENAI_API_KEY``)
  2. ``settings.json`` in data root
  3. Pydantic default

Secrets (API keys) are stored in the JSON file.  On desktop, the keyring
library can optionally be used (future enhancement).
"""

from __future__ import annotations

import json
import logging
from pathlib import Path
from typing import Any

logger = logging.getLogger(__name__)

# Fields stored in settings.json — maps JSON key to env var name
_FIELD_MAP: dict[str, str] = {
    "user_name": "VASTIAN_USER_NAME",
    "llm_provider": "VASTIAN_LLM_PROVIDER",
    "openai_api_key": "OPENAI_API_KEY",
    "anthropic_api_key": "ANTHROPIC_API_KEY",
    "default_model": "VASTIAN_DEFAULT_MODEL",
    "fast_model": "VASTIAN_FAST_MODEL",
    "user_tier": "VASTIAN_USER_TIER",
    "port": "VASTIAN_PORT",
    "ollama_base_url": "OLLAMA_BASE_URL",
    "ollama_model": "OLLAMA_MODEL",
    "log_level": "VASTIAN_LOG_LEVEL",
    "mcp_api_key": "VASTIAN_MCP_KEY",
    # Mercury Banking — only from settings.json (user's local installation)
    "mercury_api_token": "MERCURY_API_TOKEN",
    "mercury_account_id": "MERCURY_ACCOUNT_ID",
    "mercury_account_name": "MERCURY_ACCOUNT_NAME",
    "mercury_ro_1": "MERCURY_READONLY_ACCOUNT_1",
    "mercury_ro_2": "MERCURY_READONLY_ACCOUNT_2",
    "mercury_ro_3": "MERCURY_READONLY_ACCOUNT_3",
    "mercury_ro_4": "MERCURY_READONLY_ACCOUNT_4",
    "mercury_ro_5": "MERCURY_READONLY_ACCOUNT_5",
    "mercury_ro_6": "MERCURY_READONLY_ACCOUNT_6",
    "mercury_ro_7": "MERCURY_READONLY_ACCOUNT_7",
    "mercury_ro_8": "MERCURY_READONLY_ACCOUNT_8",
    "mercury_ro_9": "MERCURY_READONLY_ACCOUNT_9",
    "mercury_rn_1": "MERCURY_READONLY_NAME_1",
    "mercury_rn_2": "MERCURY_READONLY_NAME_2",
    "mercury_rn_3": "MERCURY_READONLY_NAME_3",
    "mercury_rn_4": "MERCURY_READONLY_NAME_4",
    "mercury_rn_5": "MERCURY_READONLY_NAME_5",
    "mercury_rn_6": "MERCURY_READONLY_NAME_6",
    "mercury_rn_7": "MERCURY_READONLY_NAME_7",
    "mercury_rn_8": "MERCURY_READONLY_NAME_8",
    "mercury_rn_9": "MERCURY_READONLY_NAME_9",
}

_DEFAULTS: dict[str, Any] = {
    "user_name": "",
    "llm_provider": "",
    "openai_api_key": "",
    "anthropic_api_key": "",
    "default_model": "gpt-4o",
    "fast_model": "gpt-4o-mini",
    "user_tier": "admin",
    "port": 4545,
    "ollama_base_url": "http://localhost:11434",
    "ollama_model": "",
    "log_level": "INFO",
}


def _settings_path(data_root: Path) -> Path:
    return data_root / "config" / "local" / "settings.json"


def load_settings_json(data_root: Path) -> dict[str, Any]:
    """Load settings.json from the data root.  Returns empty dict if missing."""
    path = _settings_path(data_root)
    if not path.exists():
        return {}
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
        return data if isinstance(data, dict) else {}
    except Exception:
        logger.warning("Failed to read settings.json at %s", path, exc_info=True)
        return {}


def save_settings_json(data_root: Path, settings: dict[str, Any]) -> None:
    """Write settings to settings.json in the data root."""
    path = _settings_path(data_root)
    path.parent.mkdir(parents=True, exist_ok=True)
    # Merge with existing
    existing = load_settings_json(data_root)
    existing.update(settings)
    path.write_text(
        json.dumps(existing, indent=2, ensure_ascii=False) + "\n",
        encoding="utf-8",
    )
    logger.info("Saved settings.json at %s", path)


def get_config_value(key: str, data_root: Path | None = None) -> Any:
    """Get a config value with priority: env var > settings.json > default.

    If ``data_root`` is None, only checks env vars and defaults.
    """
    import os

    # 1. Environment variable
    env_key = _FIELD_MAP.get(key, "")
    if env_key:
        val = os.environ.get(env_key)
        if val is not None and val != "":
            return val

    # 2. settings.json
    if data_root is not None:
        stored = load_settings_json(data_root)
        if key in stored and stored[key] not in (None, ""):
            return stored[key]

    # 3. Default
    return _DEFAULTS.get(key, "")


def set_config_value(key: str, value: Any, data_root: Path) -> None:
    """Set a config value in settings.json."""
    save_settings_json(data_root, {key: value})


def is_configured(data_root: Path) -> bool:
    """Check if the system has been configured (has an API key or Ollama) AND user has completed setup (name set)."""
    import os

    stored = load_settings_json(data_root)
    has_user_name = bool((stored.get("user_name") or "").strip())
    # Require user_name — setup wizard collects this; without it, treat as not configured
    if not has_user_name:
        return False

    # Check env vars
    if os.environ.get("OPENAI_API_KEY") or os.environ.get("ANTHROPIC_API_KEY"):
        return True

    # Check settings.json
    if stored.get("openai_api_key") or stored.get("anthropic_api_key"):
        return True
    return bool(stored.get("llm_provider") == "ollama" and stored.get("ollama_model"))


def apply_settings_to_env(data_root: Path) -> int:
    """Load settings.json and set any missing env vars from it.

    This bridges the gap: Settings class reads from env vars, and this
    function populates env vars from settings.json for values not already set.

    Returns the number of env vars set.
    """
    import os

    stored = load_settings_json(data_root)
    count = 0
    for json_key, env_key in _FIELD_MAP.items():
        if (
            json_key in stored
            and stored[json_key] not in (None, "")
            and not os.environ.get(env_key)
        ):
            os.environ[env_key] = str(stored[json_key])
            count += 1
    return count
