"""Folder permission configuration.

Controls which filesystem folders the agent can access.
Two modes: allow_all (unrestricted) or selective (whitelist).
"""

from __future__ import annotations

import logging
from dataclasses import dataclass, field
from pathlib import Path

from icarus.utils.toml import load_toml, save_toml

logger = logging.getLogger(__name__)

ICARUS_DIR = Path.home() / ".icarus"
"""The agent's own config directory — always accessible regardless of permissions."""


@dataclass(frozen=True)
class PermissionConfig:
    """Folder access permission configuration.

    Attributes:
        allow_all: If True, no restrictions. Agent accesses any path.
        allowed_folders: Resolved absolute paths the agent may access.
            Only checked when allow_all is False.
    """

    allow_all: bool
    allowed_folders: list[Path]
    icarus_dir: Path = field(default_factory=lambda: ICARUS_DIR)

    def is_path_allowed(self, path: str) -> bool:
        """Check whether *path* falls inside the allowed set.

        Always returns True when ``allow_all`` is set.
        ``~/.icarus/`` is always permitted (agent's own data).
        Resolves symlinks and ``..`` before checking.
        """
        if self.allow_all:
            return True
        try:
            resolved = Path(path).resolve()
        except (OSError, ValueError):
            return False
        if resolved.is_relative_to(self.icarus_dir):
            return True
        return any(resolved.is_relative_to(f) for f in self.allowed_folders)

    @staticmethod
    def load(config_dir: Path | None = None) -> PermissionConfig:
        """Load permission config from config.toml.

        Returns ``allow_all=True`` when no config file or no
        ``[permissions]`` section exists (safe default = unrestricted).
        """
        config_path = (config_dir or ICARUS_DIR) / "config.toml"
        data = load_toml(config_path)
        perms = data.get("permissions", {})

        if not perms or perms.get("allow_all", True):
            return PermissionConfig(allow_all=True, allowed_folders=[])

        raw_folders = perms.get("allowed_folders", [])
        resolved: list[Path] = []
        for raw in raw_folders:
            try:
                resolved.append(Path(raw).expanduser().resolve())
            except OSError:
                logger.warning("Skipping unresolvable path: %s", raw)
        return PermissionConfig(allow_all=False, allowed_folders=resolved)

    def save(self, config_dir: Path | None = None) -> None:
        """Persist permission config to config.toml (atomic write).

        Converts absolute paths back to ``~/``-relative for portability.
        """
        config_path = (config_dir or ICARUS_DIR) / "config.toml"
        data = load_toml(config_path)

        home = Path.home()
        portable_folders: list[str] = []
        for folder in self.allowed_folders:
            try:
                relative = folder.relative_to(home)
                portable_folders.append(f"~/{relative}")
            except ValueError:
                portable_folders.append(str(folder))

        data["permissions"] = {
            "allow_all": self.allow_all,
            "allowed_folders": portable_folders,
        }
        save_toml(config_path, data)
