"""Tests for folder permission config."""

from __future__ import annotations

from pathlib import Path

import pytest

from icarus.config.permissions import PermissionConfig
from icarus.utils.toml import load_toml


class TestIsPathAllowed:
    """Test the core permission check logic."""

    def test_allow_all_permits_any_path(self, tmp_path):
        config = PermissionConfig(allow_all=True, allowed_folders=[])
        assert config.is_path_allowed(str(tmp_path / "anything" / "at" / "all"))

    def test_selective_allows_whitelisted_folder(self, tmp_path):
        folder = tmp_path / "projects"
        folder.mkdir()
        config = PermissionConfig(allow_all=False, allowed_folders=[folder])
        assert config.is_path_allowed(str(folder / "my-app" / "src" / "main.py"))

    def test_selective_blocks_non_whitelisted(self, tmp_path):
        allowed = tmp_path / "projects"
        allowed.mkdir()
        secret = tmp_path / "secret"
        secret.mkdir()
        config = PermissionConfig(allow_all=False, allowed_folders=[allowed])
        assert not config.is_path_allowed(str(secret / "passwords.txt"))

    def test_icarus_dir_always_allowed(self, tmp_path, monkeypatch):
        icarus_dir = tmp_path / ".icarus"
        icarus_dir.mkdir()
        monkeypatch.setattr("icarus.config.permissions.ICARUS_DIR", icarus_dir)
        config = PermissionConfig(allow_all=False, allowed_folders=[])
        assert config.is_path_allowed(str(icarus_dir / "config.toml"))

    def test_path_traversal_blocked(self, tmp_path):
        allowed = tmp_path / "projects"
        allowed.mkdir()
        secret = tmp_path / "secret"
        secret.mkdir()
        config = PermissionConfig(allow_all=False, allowed_folders=[allowed])
        traversal = str(allowed / ".." / "secret" / "file.txt")
        assert not config.is_path_allowed(traversal)

    def test_symlink_resolved(self, tmp_path):
        allowed = tmp_path / "projects"
        allowed.mkdir()
        secret = tmp_path / "secret"
        secret.mkdir()
        (secret / "data.txt").write_text("sensitive")
        link = allowed / "sneaky"
        link.symlink_to(secret)
        config = PermissionConfig(allow_all=False, allowed_folders=[allowed])
        assert not config.is_path_allowed(str(link / "data.txt"))

    def test_unresolvable_path_denied(self):
        config = PermissionConfig(allow_all=False, allowed_folders=[Path("/tmp")])
        assert not config.is_path_allowed("/tmp/\x00bad")

    def test_multiple_allowed_folders(self, tmp_path):
        docs = tmp_path / "Documents"
        docs.mkdir()
        projects = tmp_path / "projects"
        projects.mkdir()
        config = PermissionConfig(
            allow_all=False,
            allowed_folders=[docs, projects],
        )
        assert config.is_path_allowed(str(docs / "report.pdf"))
        assert config.is_path_allowed(str(projects / "app" / "main.py"))
        assert not config.is_path_allowed(str(tmp_path / "secret" / "key"))

    def test_is_path_allowed_custom_icarus_dir(self):
        custom_dir = Path("/srv/icarus/users/alice")
        config = PermissionConfig(
            allow_all=False,
            allowed_folders=[Path("/data/alice")],
            icarus_dir=custom_dir,
        )
        assert config.is_path_allowed(str(custom_dir / "memory" / "notes.md"))
        assert not config.is_path_allowed(str(Path.home() / ".icarus" / "config.toml"))


class TestPermissionConfigLoadSave:
    """Test config persistence round-trip."""

    def test_load_missing_config_returns_allow_all(self, tmp_path):
        config = PermissionConfig.load(config_dir=tmp_path)
        assert config.allow_all is True
        assert config.allowed_folders == []

    def test_load_empty_permissions_section_returns_allow_all(self, tmp_path):
        config_path = tmp_path / "config.toml"
        config_path.write_text("[permissions]\n")
        config = PermissionConfig.load(config_dir=tmp_path)
        assert config.allow_all is True

    def test_load_selective_config(self, tmp_path):
        config_path = tmp_path / "config.toml"
        home = Path.home()
        config_path.write_text(
            '[permissions]\n'
            'allow_all = false\n'
            'allowed_folders = ["~/Documents", "~/projects"]\n'
        )
        config = PermissionConfig.load(config_dir=tmp_path)
        assert config.allow_all is False
        assert (home / "Documents").resolve() in config.allowed_folders
        assert (home / "projects").resolve() in config.allowed_folders

    def test_save_then_load_round_trip(self, tmp_path):
        home = Path.home()
        original = PermissionConfig(
            allow_all=False,
            allowed_folders=[
                (home / "Documents").resolve(),
                (home / "projects").resolve(),
            ],
        )
        original.save(config_dir=tmp_path)
        loaded = PermissionConfig.load(config_dir=tmp_path)
        assert loaded.allow_all is False
        assert set(loaded.allowed_folders) == set(original.allowed_folders)

    def test_save_preserves_other_config_sections(self, tmp_path):
        config_path = tmp_path / "config.toml"
        config_path.write_text('[models]\ndefault = "anthropic:claude-sonnet-4-5"\n')

        config = PermissionConfig(allow_all=False, allowed_folders=[Path("/tmp/test")])
        config.save(config_dir=tmp_path)

        data = load_toml(config_path)
        assert data["models"]["default"] == "anthropic:claude-sonnet-4-5"
        assert data["permissions"]["allow_all"] is False

    def test_save_converts_absolute_to_tilde(self, tmp_path):
        home = Path.home()
        config = PermissionConfig(
            allow_all=False,
            allowed_folders=[(home / "Documents").resolve()],
        )
        config.save(config_dir=tmp_path)

        data = load_toml(tmp_path / "config.toml")
        folders = data["permissions"]["allowed_folders"]
        assert any("~/" in f for f in folders), f"Expected ~/..., got {folders}"
