"""Unit tests for ActionRegistry."""

import pytest
import json
from pathlib import Path
from unishell.core.action_registry import (
    ActionRegistryImpl,
    ActionSchema,
    PermissionLevel,
    RiskLevel,
    RollbackStrategy
)


class TestActionRegistry:
    """Test ActionRegistry implementation."""

    def test_load_from_json(self, tmp_path):
        """Test loading action from JSON file."""
        registry = ActionRegistryImpl()
        
        action_file = tmp_path / "test_action.json"
        action_data = {
            "action_id": "test.action",
            "category": "test",
            "required_params": ["param1"],
            "permission_level": "user",
            "risk_level": "low",
            "execution": {"requires_confirmation": False},
            "rollback_strategy": "none"
        }
        action_file.write_text(json.dumps(action_data))
        
        registry.load_from_file(str(action_file))
        
        assert "test.action" in registry.list_actions()
        action = registry.get_action("test.action")
        assert action.action_id == "test.action"
        assert action.category == "test"

    def test_load_from_dict(self):
        """Test loading action from dictionary."""
        registry = ActionRegistryImpl()
        
        action_data = {
            "action_id": "dict.action",
            "category": "test",
            "required_params": ["param1", "param2"],
            "permission_level": "admin",
            "risk_level": "high",
            "execution": {"timeout": 60},
            "rollback_strategy": "automatic"
        }
        
        registry.load_from_dict(action_data)
        
        action = registry.get_action("dict.action")
        assert action is not None
        assert action.action_id == "dict.action"
        assert len(action.required_params) == 2

    def test_validate_params_success(self):
        """Test parameter validation with valid params."""
        registry = ActionRegistryImpl()
        
        registry.load_from_dict({
            "action_id": "validate.test",
            "category": "test",
            "required_params": ["param1", "param2"],
            "permission_level": "user",
            "risk_level": "low",
            "execution": {},
            "rollback_strategy": "none"
        })
        
        is_valid, missing = registry.validate_params(
            "validate.test",
            {"param1": "value1", "param2": "value2"}
        )
        
        assert is_valid is True
        assert len(missing) == 0

    def test_validate_params_missing(self):
        """Test parameter validation with missing params."""
        registry = ActionRegistryImpl()
        
        registry.load_from_dict({
            "action_id": "validate.test",
            "category": "test",
            "required_params": ["param1", "param2"],
            "permission_level": "user",
            "risk_level": "low",
            "execution": {},
            "rollback_strategy": "none"
        })
        
        is_valid, missing = registry.validate_params(
            "validate.test",
            {"param1": "value1"}
        )
        
        assert is_valid is False
        assert "param2" in missing

    def test_list_actions(self):
        """Test listing all actions."""
        registry = ActionRegistryImpl()
        
        for i in range(3):
            registry.load_from_dict({
                "action_id": f"action.{i}",
                "category": "test",
                "required_params": [],
                "permission_level": "user",
                "risk_level": "low",
                "execution": {},
                "rollback_strategy": "none"
            })
        
        actions = registry.list_actions()
        assert len(actions) == 3
        assert "action.0" in actions
        assert "action.2" in actions

    def test_get_by_category(self):
        """Test getting actions by category."""
        registry = ActionRegistryImpl()
        
        registry.load_from_dict({
            "action_id": "file.read",
            "category": "file",
            "required_params": [],
            "permission_level": "user",
            "risk_level": "low",
            "execution": {},
            "rollback_strategy": "none"
        })
        
        registry.load_from_dict({
            "action_id": "system.info",
            "category": "system",
            "required_params": [],
            "permission_level": "user",
            "risk_level": "low",
            "execution": {},
            "rollback_strategy": "none"
        })
        
        file_actions = registry.get_by_category("file")
        assert len(file_actions) == 1
        assert file_actions[0].action_id == "file.read"

    def test_action_not_found(self):
        """Test getting non-existent action."""
        registry = ActionRegistryImpl()
        
        action = registry.get_action("nonexistent")
        assert action is None
        
        is_valid, missing = registry.validate_params("nonexistent", {})
        assert is_valid is False
        assert "not found" in missing[0]


class TestActionSchema:
    """Test ActionSchema validation."""

    def test_valid_schema(self):
        """Test creating valid action schema."""
        action = ActionSchema(
            action_id="test.action",
            category="test",
            required_params=["param1"],
            permission_level=PermissionLevel.USER,
            risk_level=RiskLevel.LOW,
            execution={"requires_confirmation": True},
            rollback_strategy=RollbackStrategy.NONE
        )
        
        assert action.action_id == "test.action"
        assert action.permission_level == PermissionLevel.USER

    def test_missing_required_field(self):
        """Test schema validation with missing required field."""
        with pytest.raises(Exception):
            ActionSchema(
                action_id="test.action",
                category="test"
                # Missing required fields
            )

    def test_invalid_enum_value(self):
        """Test schema validation with invalid enum."""
        with pytest.raises(Exception):
            ActionSchema(
                action_id="test.action",
                category="test",
                required_params=[],
                permission_level="invalid_level",
                risk_level=RiskLevel.LOW,
                execution={},
                rollback_strategy=RollbackStrategy.NONE
            )


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
