from __future__ import annotations

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

from .constants import CONFIG_DIR
from .exceptions import ConfigError

logger = logging.getLogger(__name__)

DEFAULTS: dict[str, Any] = {
    "browser": "auto",
    "lang": "en",
    "region": None,
    "max_results": 10,
    "json_output": False,
    "rate_limit": 2.0,
    "max_tabs": 5,
    "timeout": 30,
}

TYPE_MAP: dict[str, type] = {
    "browser": str,
    "lang": str,
    "region": str,
    "max_results": int,
    "json_output": bool,
    "rate_limit": float,
    "max_tabs": int,
    "timeout": int,
}


class Config:
    def __init__(self, config_dir: Path | None = None) -> None:
        self._dir = Path(config_dir) if config_dir else CONFIG_DIR
        self._dir.mkdir(parents=True, exist_ok=True)
        self._file = self._dir / "config.json"
        self._overrides: dict[str, Any] = self._load()

    def _load(self) -> dict[str, Any]:
        if not self._file.exists():
            return {}
        try:
            return json.loads(self._file.read_text())
        except (json.JSONDecodeError, OSError) as exc:
            logger.warning("Corrupt config at %s, using defaults: %s", self._file, exc)
            return {}

    def _save(self) -> None:
        self._file.write_text(json.dumps(self._overrides, indent=2) + "\n")

    def get(self, key: str) -> Any:
        if key not in DEFAULTS:
            raise ConfigError(f"Unknown config key: {key}")
        return self._overrides.get(key, DEFAULTS[key])

    def set(self, key: str, value: Any) -> None:
        if key not in DEFAULTS:
            raise ConfigError(f"Unknown config key: {key}")
        expected = TYPE_MAP[key]
        try:
            if expected is bool:
                if isinstance(value, str):
                    value = value.lower() in ("true", "1", "yes")
                else:
                    value = bool(value)
            else:
                value = expected(value)
        except (ValueError, TypeError) as exc:
            raise ConfigError(f"Cannot coerce {value!r} to {expected.__name__} for key {key!r}") from exc
        self._overrides[key] = value
        self._save()

    def show(self) -> dict[str, Any]:
        return {**DEFAULTS, **self._overrides}
