"""Shared test fixtures for Curadise Agent tests."""

from __future__ import annotations

import asyncio
import tempfile
from pathlib import Path
from typing import TYPE_CHECKING
from unittest.mock import AsyncMock, MagicMock

import pytest

from curadise_agent.config.schema import (
    AgentConfig,
    AuthConfig,
    BufferConfig,
    CollectorConfig,
    CollectorsConfig,
    ExecutorConfig,
    HeartbeatConfig,
    LoggingConfig,
    RetryConfig,
    ServerConfig,
    StateConfig,
)
from curadise_agent.models.api.command import CommandRequest, CommandType
from curadise_agent.models.domain.metric import DomainMetric, MetricType
from curadise_agent.state.manager import StateManager
from curadise_agent.state.storage import StateStorage
from curadise_agent.transport.buffer import RingBuffer

if TYPE_CHECKING:
    from collections.abc import Generator


@pytest.fixture
def temp_dir() -> Generator[Path, None, None]:
    """Create a temporary directory for tests."""
    with tempfile.TemporaryDirectory() as tmpdir:
        yield Path(tmpdir)


@pytest.fixture
def server_config() -> ServerConfig:
    """Create a test server configuration."""
    return ServerConfig(
        url="https://test.curadise.local",
        timeout=30.0,
        verify_ssl=False,
    )


@pytest.fixture
def auth_config() -> AuthConfig:
    """Create a test auth configuration."""
    return AuthConfig()


@pytest.fixture
def buffer_config() -> BufferConfig:
    """Create a test buffer configuration."""
    return BufferConfig(
        max_size=1000,
        flush_interval=5.0,
        batch_size=100,
    )


@pytest.fixture
def retry_config() -> RetryConfig:
    """Create a test retry configuration."""
    return RetryConfig(
        max_attempts=3,
        initial_delay=0.1,
        max_delay=1.0,
    )


@pytest.fixture
def heartbeat_config() -> HeartbeatConfig:
    """Create a test heartbeat configuration."""
    return HeartbeatConfig(
        interval=30.0,
        timeout=10.0,
    )


@pytest.fixture
def collector_config() -> CollectorConfig:
    """Create a test collector configuration."""
    return CollectorConfig(
        enabled=True,
        interval=60.0,
        timeout=30.0,
    )


@pytest.fixture
def collectors_config(collector_config: CollectorConfig) -> CollectorsConfig:
    """Create a test collectors configuration."""
    return CollectorsConfig(
        system=collector_config,
        http=CollectorConfig(enabled=False),
    )


@pytest.fixture
def executor_config() -> ExecutorConfig:
    """Create a test executor configuration."""
    return ExecutorConfig(
        enabled=True,
        allowlist=["echo *", "ls *"],
        denylist=["rm *"],
        require_signature=False,
    )


@pytest.fixture
def logging_config() -> LoggingConfig:
    """Create a test logging configuration."""
    return LoggingConfig(
        level="DEBUG",
        format="console",
    )


@pytest.fixture
def state_config(temp_dir: Path) -> StateConfig:
    """Create a test state configuration."""
    return StateConfig(directory=temp_dir)


@pytest.fixture
def agent_config(
    server_config: ServerConfig,
    auth_config: AuthConfig,
    buffer_config: BufferConfig,
    retry_config: RetryConfig,
    heartbeat_config: HeartbeatConfig,
    collectors_config: CollectorsConfig,
    executor_config: ExecutorConfig,
    logging_config: LoggingConfig,
    state_config: StateConfig,
) -> AgentConfig:
    """Create a complete test agent configuration."""
    return AgentConfig(
        server=server_config,
        auth=auth_config,
        buffer=buffer_config,
        retry=retry_config,
        heartbeat=heartbeat_config,
        collectors=collectors_config,
        executor=executor_config,
        logging=logging_config,
        state=state_config,
        tags={"env": "test"},
    )


@pytest.fixture
def state_storage(temp_dir: Path) -> StateStorage:
    """Create a test state storage."""
    return StateStorage(directory=temp_dir)


@pytest.fixture
def state_manager(state_storage: StateStorage) -> StateManager:
    """Create a test state manager."""
    return StateManager(storage=state_storage)


@pytest.fixture
def ring_buffer() -> RingBuffer[DomainMetric]:
    """Create a test ring buffer."""
    return RingBuffer(max_size=100)


@pytest.fixture
def sample_metric() -> DomainMetric:
    """Create a sample metric for testing."""
    return DomainMetric(
        name="test.metric",
        value=42.0,
        metric_type=MetricType.GAUGE,
        unit="count",
        tags={"host": "test-host"},
        collector="test",
    )


@pytest.fixture
def sample_metrics() -> list[DomainMetric]:
    """Create a list of sample metrics."""
    return [
        DomainMetric(
            name=f"test.metric.{i}",
            value=float(i),
            metric_type=MetricType.GAUGE,
            collector="test",
        )
        for i in range(10)
    ]


@pytest.fixture
def sample_command() -> CommandRequest:
    """Create a sample command for testing."""
    return CommandRequest(
        id="cmd-001",
        command="echo",
        args=["hello", "world"],
        command_type=CommandType.SHELL,
        timeout=30.0,
    )


@pytest.fixture
def mock_transport() -> AsyncMock:
    """Create a mock transport client."""
    transport = AsyncMock()
    transport.start = AsyncMock()
    transport.stop = AsyncMock()
    transport.send_batch = AsyncMock(return_value=True)
    transport.send_heartbeat = AsyncMock(return_value={"acknowledged": True})
    transport.fetch_commands = AsyncMock(return_value=[])
    transport.register = AsyncMock(
        return_value={
            "agent_id": "agent-123",
            "access_token": "test-token",
        }
    )
    transport.stats = MagicMock(
        requests_sent=0,
        requests_successful=0,
        requests_failed=0,
        bytes_sent=0,
        bytes_received=0,
        batches_sent=0,
        metrics_sent=0,
        last_success_time=None,
        last_failure_time=None,
    )
    transport.circuit_state = "closed"
    transport.is_connected = True
    return transport


@pytest.fixture
def event_loop_policy():
    """Use uvloop if available, otherwise default."""
    try:
        import uvloop

        return uvloop.EventLoopPolicy()
    except ImportError:
        return asyncio.DefaultEventLoopPolicy()
