"""Personal Edition config shim.

The framework's ``ConfigStore`` is the source of truth; this module keeps the
old ``load_config_decrypted()`` call-site contract (an attribute-accessible
config) for the edition's not-yet-extracted built-in routers, filling in
defaults for the config slices those routers read.
"""

from __future__ import annotations

from types import SimpleNamespace
from typing import Optional

from roadmap_framework import ConfigStore

_store: Optional[ConfigStore] = None

# Defaults for every slice the built-in routers read, so attribute access never
# fails on a fresh/partial config. (The ``atlassian`` slice is owned by the Jira
# plugin; included here only so the AI context-assistant can read its cache dir.)
_DEFAULTS = {
    "scratch_base_dir": "",
    "repositories": [],
    "file_viewers": [],
    "ai_providers": [],
    "ai_proxy": {"name": "Proxy", "base_url": "", "api_key": ""},
    "ai_tasks": [],
    "whisper": {"base_url": "https://api.openai.com/v1", "api_key": "",
                "model": "whisper-1", "postprocess_provider": "",
                "postprocess_model": ""},
    "atlassian": {"deployment_type": "cloud", "base_url": "", "email": "",
                  "api_token": "", "jira_projects": [], "confluence_spaces": [],
                  "cache_dir": "", "refresh_duration": 3600},
}


def set_store(store: ConfigStore) -> None:
    global _store
    _store = store


def _merge(base: dict, overlay: dict) -> dict:
    out = dict(base)
    for k, v in overlay.items():
        out[k] = _merge(out[k], v) if isinstance(v, dict) and isinstance(out.get(k), dict) else v
    return out


def _ns(obj):
    if isinstance(obj, dict):
        return SimpleNamespace(**{k: _ns(v) for k, v in obj.items()})
    if isinstance(obj, list):
        return [_ns(v) for v in obj]
    return obj


def load_config_decrypted():
    assert _store is not None, "personal config store not initialised"
    return _ns(_merge(_DEFAULTS, _store.load_decrypted()))
