"""Configuration persistence for porTUI."""

from __future__ import annotations

import json
from pathlib import Path

# Defaults
_DEFAULT_INTERVAL: int = 5
_DEFAULT_COLUMNS: tuple[bool, ...] = (True,) * 8
_DEFAULT_AUTO_REFRESH: bool = True
_NUM_COLUMNS: int = 8


class ConfigManager:
    """Load and save porTUI user configuration with full input validation."""

    def __init__(self, config_path: Path | None = None) -> None:
        # Resolve lazily so that Path.home() is not called at import time.
        if config_path is None:
            config_path = Path.home() / ".config" / "portui" / "config.json"
        self.config_path = config_path

    # ------------------------------------------------------------------
    # Public API
    # ------------------------------------------------------------------

    def load(self) -> dict:
        """Load config from disk.  Returns a dict with validated defaults."""
        raw: dict = {}
        try:
            if self.config_path.exists():
                with self.config_path.open() as f:
                    raw = json.load(f)
        except (json.JSONDecodeError, OSError, ValueError):
            pass  # Fall through to defaults

        return {
            "refresh_interval": self._validate_interval(raw.get("refresh_interval")),
            "visible_columns": self._validate_columns(raw.get("visible_columns")),
            "auto_refresh": self._validate_auto_refresh(raw.get("auto_refresh")),
        }

    def save(
        self,
        refresh_interval: int,
        visible_columns: tuple[bool, ...],
        auto_refresh: bool,
    ) -> None:
        """Persist config to disk.  Silently ignores OS errors."""
        try:
            self.config_path.parent.mkdir(parents=True, exist_ok=True)
            payload = {
                "refresh_interval": refresh_interval,
                "visible_columns": list(visible_columns),
                "auto_refresh": auto_refresh,
            }
            with self.config_path.open("w") as f:
                json.dump(payload, f, indent=2)
        except OSError:
            pass

    # ------------------------------------------------------------------
    # Validators
    # ------------------------------------------------------------------

    @staticmethod
    def _validate_interval(value: object) -> int:
        """Return *value* if it is a positive number, else the default."""
        try:
            v = float(value)  # type: ignore[arg-type]
            if v > 0:
                return int(v)
        except (TypeError, ValueError):
            pass
        return _DEFAULT_INTERVAL

    @staticmethod
    def _validate_columns(value: object) -> tuple[bool, ...]:
        """Return a tuple of exactly 8 bools, or the default tuple."""
        try:
            lst = list(value)  # type: ignore[arg-type]
            if len(lst) != _NUM_COLUMNS:
                return _DEFAULT_COLUMNS
            return tuple(bool(v) for v in lst)
        except (TypeError, ValueError):
            return _DEFAULT_COLUMNS

    @staticmethod
    def _validate_auto_refresh(value: object) -> bool:
        """Return *value* as a bool if it is actually a bool, else the default."""
        if isinstance(value, bool):
            return value
        return _DEFAULT_AUTO_REFRESH
