"""Tests for Authorization service."""

import pytest
from pathlib import Path
from unittest.mock import patch, mock_open

from styrene_bond_rpc.auth import AuthorizationService


@pytest.fixture
def auth_config() -> str:
    """Sample authorization configuration YAML."""
    return """
identities:
  - hash: "admin_hash_123"
    name: "Admin User"
    permissions:
      - status
      - exec
      - reboot
      - update_config

  - hash: "monitor_hash_456"
    name: "Monitor User"
    permissions:
      - status

  - hash: "operator_hash_789"
    name: "Operator"
    permissions:
      - status
      - exec
"""


class TestAuthorizationServiceInitialization:
    """Test authorization service initialization."""

    def test_load_config_from_file(self, tmp_path, auth_config) -> None:
        """AuthorizationService should load config from file."""
        config_file = tmp_path / "auth.yaml"
        config_file.write_text(auth_config)

        auth_service = AuthorizationService(str(config_file))

        assert auth_service is not None
        assert len(auth_service._identities) == 3

    def test_load_config_missing_file(self, tmp_path) -> None:
        """AuthorizationService should handle missing config file."""
        config_file = tmp_path / "nonexistent.yaml"

        # Should not raise exception
        auth_service = AuthorizationService(str(config_file))

        # Should have no identities loaded
        assert len(auth_service._identities) == 0

    def test_load_config_invalid_yaml(self, tmp_path) -> None:
        """AuthorizationService should handle invalid YAML gracefully."""
        config_file = tmp_path / "invalid.yaml"
        config_file.write_text("invalid: yaml: content: :\n")

        # Should not raise exception
        auth_service = AuthorizationService(str(config_file))

        assert len(auth_service._identities) == 0


class TestAuthorizationChecks:
    """Test authorization permission checks."""

    def test_admin_can_execute_all_commands(self, tmp_path, auth_config) -> None:
        """Admin user should be authorized for all commands."""
        config_file = tmp_path / "auth.yaml"
        config_file.write_text(auth_config)

        auth_service = AuthorizationService(str(config_file))

        assert auth_service.is_authorized("admin_hash_123", "status")
        assert auth_service.is_authorized("admin_hash_123", "exec")
        assert auth_service.is_authorized("admin_hash_123", "reboot")
        assert auth_service.is_authorized("admin_hash_123", "update_config")

    def test_monitor_can_only_check_status(self, tmp_path, auth_config) -> None:
        """Monitor user should only be authorized for status."""
        config_file = tmp_path / "auth.yaml"
        config_file.write_text(auth_config)

        auth_service = AuthorizationService(str(config_file))

        assert auth_service.is_authorized("monitor_hash_456", "status")
        assert not auth_service.is_authorized("monitor_hash_456", "exec")
        assert not auth_service.is_authorized("monitor_hash_456", "reboot")
        assert not auth_service.is_authorized("monitor_hash_456", "update_config")

    def test_operator_has_limited_permissions(self, tmp_path, auth_config) -> None:
        """Operator should have status and exec permissions."""
        config_file = tmp_path / "auth.yaml"
        config_file.write_text(auth_config)

        auth_service = AuthorizationService(str(config_file))

        assert auth_service.is_authorized("operator_hash_789", "status")
        assert auth_service.is_authorized("operator_hash_789", "exec")
        assert not auth_service.is_authorized("operator_hash_789", "reboot")
        assert not auth_service.is_authorized("operator_hash_789", "update_config")

    def test_unknown_identity_denied(self, tmp_path, auth_config) -> None:
        """Unknown identity should be denied all commands."""
        config_file = tmp_path / "auth.yaml"
        config_file.write_text(auth_config)

        auth_service = AuthorizationService(str(config_file))

        assert not auth_service.is_authorized("unknown_hash", "status")
        assert not auth_service.is_authorized("unknown_hash", "exec")
        assert not auth_service.is_authorized("unknown_hash", "reboot")


class TestGetPermissions:
    """Test get_permissions method."""

    def test_get_permissions_for_admin(self, tmp_path, auth_config) -> None:
        """Should return all permissions for admin."""
        config_file = tmp_path / "auth.yaml"
        config_file.write_text(auth_config)

        auth_service = AuthorizationService(str(config_file))

        permissions = auth_service.get_permissions("admin_hash_123")

        assert "status" in permissions
        assert "exec" in permissions
        assert "reboot" in permissions
        assert "update_config" in permissions

    def test_get_permissions_for_monitor(self, tmp_path, auth_config) -> None:
        """Should return only status permission for monitor."""
        config_file = tmp_path / "auth.yaml"
        config_file.write_text(auth_config)

        auth_service = AuthorizationService(str(config_file))

        permissions = auth_service.get_permissions("monitor_hash_456")

        assert permissions == ["status"]

    def test_get_permissions_for_unknown_identity(self, tmp_path, auth_config) -> None:
        """Should return empty list for unknown identity."""
        config_file = tmp_path / "auth.yaml"
        config_file.write_text(auth_config)

        auth_service = AuthorizationService(str(config_file))

        permissions = auth_service.get_permissions("unknown_hash")

        assert permissions == []


class TestConfigReload:
    """Test configuration reload functionality."""

    def test_reload_config(self, tmp_path) -> None:
        """Should reload configuration from file."""
        config_file = tmp_path / "auth.yaml"

        # Initial config
        config_file.write_text("""
identities:
  - hash: "user1"
    name: "User 1"
    permissions: [status]
""")

        auth_service = AuthorizationService(str(config_file))
        assert len(auth_service._identities) == 1

        # Update config
        config_file.write_text("""
identities:
  - hash: "user1"
    name: "User 1"
    permissions: [status]
  - hash: "user2"
    name: "User 2"
    permissions: [status, exec]
""")

        # Reload
        auth_service.reload_config()
        assert len(auth_service._identities) == 2
