"""
Pytest fixtures for Proxilion tests.

Provides common fixtures used across all test modules.
"""

from __future__ import annotations

from datetime import datetime, timezone
from pathlib import Path

import pytest

from proxilion import AgentContext, Proxilion, UserContext
from proxilion.audit.events import AuditEventData, AuditEventV2, EventType
from proxilion.audit.hash_chain import GENESIS_HASH, HashChain
from proxilion.audit.logger import AuditLogger, LoggerConfig, RotationPolicy
from proxilion.policies.registry import PolicyRegistry
from proxilion.security.circuit_breaker import CircuitBreaker, CircuitBreakerRegistry
from proxilion.security.idor_protection import IDORProtector
from proxilion.security.rate_limiter import SlidingWindowRateLimiter, TokenBucketRateLimiter
from proxilion.types import ToolCallRequest
from proxilion.validation.schema import ParameterSchema, SchemaValidator, ToolSchema

# ============================================================================
# User Context Fixtures
# ============================================================================


@pytest.fixture
def basic_user() -> UserContext:
    """Create a basic user context for testing."""
    return UserContext(
        user_id="user_123",
        roles=["user"],
        session_id="session_abc",
        attributes={"department": "engineering"},
    )


@pytest.fixture
def admin_user() -> UserContext:
    """Create an admin user context for testing."""
    return UserContext(
        user_id="admin_456",
        roles=["admin", "user"],
        session_id="session_def",
        attributes={"department": "engineering", "clearance": "high"},
    )


@pytest.fixture
def analyst_user() -> UserContext:
    """Create an analyst user context for testing."""
    return UserContext(
        user_id="analyst_789",
        roles=["analyst", "user"],
        session_id="session_ghi",
        attributes={"department": "data_science"},
    )


@pytest.fixture
def guest_user() -> UserContext:
    """Create a guest user context with minimal permissions."""
    return UserContext(
        user_id="guest_000",
        roles=["guest"],
        session_id=None,
        attributes={},
    )


# ============================================================================
# Agent Context Fixtures
# ============================================================================


@pytest.fixture
def basic_agent() -> AgentContext:
    """Create a basic agent context for testing."""
    return AgentContext(
        agent_id="agent_001",
        capabilities=["search", "read"],
        trust_score=0.8,
    )


# ============================================================================
# Tool Call Request Fixtures
# ============================================================================


@pytest.fixture
def search_tool_request() -> ToolCallRequest:
    """Create a search tool call request."""
    return ToolCallRequest(
        tool_name="search",
        arguments={"query": "test query", "limit": 10},
        timestamp=datetime.now(timezone.utc),
    )


# ============================================================================
# Policy Fixtures
# ============================================================================


@pytest.fixture
def policy_registry() -> PolicyRegistry:
    """Create a fresh policy registry."""
    return PolicyRegistry()


# ============================================================================
# Proxilion Instance Fixtures
# ============================================================================


@pytest.fixture
def proxilion_simple() -> Proxilion:
    """Create a Proxilion instance with simple engine."""
    return Proxilion(
        policy_engine="simple",
        enable_circuit_breaker=False,
    )


@pytest.fixture
def proxilion_with_audit(tmp_path: Path) -> Proxilion:
    """Create a Proxilion instance with audit logging."""
    audit_path = tmp_path / "audit.jsonl"
    return Proxilion(
        policy_engine="simple",
        audit_log_path=str(audit_path),
        enable_circuit_breaker=False,
    )


# ============================================================================
# Schema Validation Fixtures
# ============================================================================


@pytest.fixture
def schema_validator() -> SchemaValidator:
    """Create a schema validator."""
    return SchemaValidator()


@pytest.fixture
def calculator_schema() -> ToolSchema:
    """Create a calculator tool schema."""
    return ToolSchema(
        name="calculator",
        description="Performs mathematical operations",
        parameters={
            "operation": ParameterSchema(
                name="operation",
                type="str",
                description="The operation to perform",
                constraints={"enum": ["add", "subtract", "multiply", "divide"]},
            ),
            "a": ParameterSchema(
                name="a",
                type="float",
                description="First operand",
            ),
            "b": ParameterSchema(
                name="b",
                type="float",
                description="Second operand",
            ),
        },
        required_parameters=["operation", "a", "b"],
        risk_level="low",
    )


@pytest.fixture
def file_read_schema() -> ToolSchema:
    """Create a file read tool schema with path validation."""
    return ToolSchema(
        name="file_read",
        description="Read contents of a file",
        parameters={
            "path": ParameterSchema(
                name="path",
                type="str",
                description="Path to the file",
                constraints={"allow_path_traversal": False},
            ),
        },
        required_parameters=["path"],
        risk_level="medium",
    )


@pytest.fixture
def database_query_schema() -> ToolSchema:
    """Create a database query tool schema."""
    return ToolSchema(
        name="database_query",
        description="Execute a database query",
        parameters={
            "query": ParameterSchema(
                name="query",
                type="str",
                description="SQL query to execute",
                sensitive=True,
            ),
            "database": ParameterSchema(
                name="database",
                type="str",
                description="Target database",
                constraints={"enum": ["main", "analytics", "logs"]},
            ),
        },
        required_parameters=["query"],
        risk_level="high",
    )


# ============================================================================
# Security Control Fixtures
# ============================================================================


@pytest.fixture
def rate_limiter() -> TokenBucketRateLimiter:
    """Create a token bucket rate limiter."""
    return TokenBucketRateLimiter(
        capacity=10,
        refill_rate=1.0,  # 1 token per second
    )


@pytest.fixture
def sliding_window_limiter() -> SlidingWindowRateLimiter:
    """Create a sliding window rate limiter."""
    return SlidingWindowRateLimiter(
        max_requests=10,
        window_seconds=60.0,
    )


@pytest.fixture
def circuit_breaker() -> CircuitBreaker:
    """Create a circuit breaker."""
    return CircuitBreaker(
        failure_threshold=3,
        reset_timeout=5.0,
        half_open_max=1,
    )


@pytest.fixture
def circuit_breaker_registry() -> CircuitBreakerRegistry:
    """Create a circuit breaker registry."""
    return CircuitBreakerRegistry(
        default_config={
            "failure_threshold": 3,
            "reset_timeout": 5.0,
        }
    )


@pytest.fixture
def idor_protector() -> IDORProtector:
    """Create an IDOR protector with sample scopes."""
    protector = IDORProtector()
    # Register some sample scopes
    protector.register_scope("user_123", "document", {"doc_1", "doc_2", "doc_3"})
    protector.register_scope("user_123", "project", {"proj_a", "proj_b"})
    protector.register_scope("admin_456", "document", {"doc_1", "doc_2", "doc_3", "doc_4", "doc_5"})
    return protector


# ============================================================================
# Audit Logging Fixtures
# ============================================================================


@pytest.fixture
def hash_chain() -> HashChain:
    """Create a fresh hash chain."""
    return HashChain()


@pytest.fixture
def temp_audit_dir(tmp_path: Path) -> Path:
    """Create a temporary directory for audit logs."""
    audit_dir = tmp_path / "audit"
    audit_dir.mkdir()
    return audit_dir


@pytest.fixture
def audit_logger(temp_audit_dir: Path) -> AuditLogger:
    """Create an audit logger with temporary directory."""
    config = LoggerConfig(
        log_path=temp_audit_dir / "audit.jsonl",
        rotation=RotationPolicy.NONE,
    )
    return AuditLogger(config)


@pytest.fixture
def sample_audit_event(
    basic_user: UserContext, search_tool_request: ToolCallRequest
) -> AuditEventV2:
    """Create a sample audit event."""
    data = AuditEventData(
        event_type=EventType.AUTHORIZATION_GRANTED,
        user_id=basic_user.user_id,
        user_roles=basic_user.roles,
        session_id=basic_user.session_id,
        user_attributes=basic_user.attributes,
        agent_id=None,
        agent_capabilities=[],
        agent_trust_score=None,
        tool_name=search_tool_request.tool_name,
        tool_arguments=search_tool_request.arguments,
        tool_timestamp=search_tool_request.timestamp,
        authorization_allowed=True,
        authorization_reason="Policy allowed",
        policies_evaluated=["SearchPolicy"],
        authorization_metadata={},
    )
    event = AuditEventV2(
        data=data,
        previous_hash=GENESIS_HASH,
    )
    event.compute_hash()
    return event
