"""Tests for metric collectors."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from curadise_agent.collectors.base import DomainCollector
from curadise_agent.collectors.it.system import SystemCollector
from curadise_agent.collectors.registry import CollectorRegistry
from curadise_agent.models.domain.metric import DomainMetric, MetricType

if TYPE_CHECKING:
    from curadise_agent.config.schema import CollectorConfig


class TestDomainCollector:
    """Tests for base DomainCollector."""

    class MockCollector(DomainCollector):
        """Mock collector for testing."""

        def __init__(self, metrics: list[DomainMetric] | None = None, **kwargs):
            super().__init__(**kwargs)
            self._metrics = metrics or []

        async def collect(self) -> list[DomainMetric]:
            return self._metrics

    def test_collector_properties(self, collector_config: CollectorConfig) -> None:
        """Test collector property accessors."""
        collector = self.MockCollector(name="test", config=collector_config)

        assert collector.name == "test"
        assert collector.enabled
        assert collector.interval == 60.0
        assert collector.timeout == 30.0

    def test_enable_disable(self, collector_config: CollectorConfig) -> None:
        """Test enable/disable functionality."""
        collector = self.MockCollector(name="test", config=collector_config)

        collector.disable()
        assert not collector.enabled

        collector.enable()
        assert collector.enabled

    async def test_run_success(self) -> None:
        """Test successful collection run."""
        metrics = [DomainMetric(name="test.metric", value=1.0, metric_type=MetricType.GAUGE)]
        collector = self.MockCollector(name="test", metrics=metrics)

        result = await collector.run()

        assert result.success
        assert len(result.metrics) == 1
        assert result.metrics[0].collector == "test"

        stats = collector.stats
        assert stats.total_collections == 1
        assert stats.successful_collections == 1
        assert stats.failed_collections == 0

    async def test_run_disabled(self, collector_config: CollectorConfig) -> None:
        """Test running disabled collector."""
        collector = self.MockCollector(name="test", config=collector_config)
        collector.disable()

        result = await collector.run()

        assert not result.success
        assert result.error == "Collector disabled"

    async def test_run_with_tags(self) -> None:
        """Test that default tags are added to metrics."""
        metrics = [DomainMetric(name="test.metric", value=1.0, metric_type=MetricType.GAUGE)]
        collector = self.MockCollector(
            name="test",
            metrics=metrics,
            tags={"env": "test", "host": "localhost"},
        )

        result = await collector.run()

        assert result.success
        assert result.metrics[0].tags["env"] == "test"
        assert result.metrics[0].tags["host"] == "localhost"


class TestSystemCollector:
    """Tests for SystemCollector."""

    @pytest.fixture
    def collector(self, collector_config: CollectorConfig) -> SystemCollector:
        return SystemCollector(name="system", config=collector_config)

    async def test_collect_cpu_metrics(self, collector: SystemCollector) -> None:
        """Test CPU metrics collection."""
        result = await collector.run()

        assert result.success
        metric_names = [m.name for m in result.metrics]

        assert "system.cpu.usage_percent" in metric_names
        assert "system.cpu.count" in metric_names

    async def test_collect_memory_metrics(self, collector: SystemCollector) -> None:
        """Test memory metrics collection."""
        result = await collector.run()

        metric_names = [m.name for m in result.metrics]

        assert "system.memory.total_bytes" in metric_names
        assert "system.memory.used_bytes" in metric_names
        assert "system.memory.usage_percent" in metric_names

    async def test_collect_disk_metrics(self, collector: SystemCollector) -> None:
        """Test disk metrics collection."""
        result = await collector.run()

        # At least some disk metrics should be present
        disk_metrics = [m for m in result.metrics if m.name.startswith("system.disk")]
        assert len(disk_metrics) > 0

    async def test_collect_network_metrics(self, collector: SystemCollector) -> None:
        """Test network metrics collection."""
        result = await collector.run()

        metric_names = [m.name for m in result.metrics]

        assert "system.network.bytes_sent_total" in metric_names
        assert "system.network.bytes_recv_total" in metric_names


class TestCollectorRegistry:
    """Tests for CollectorRegistry."""

    def test_register_class(self) -> None:
        """Test registering a collector class."""
        registry = CollectorRegistry()
        registry.register_class("test", TestDomainCollector.MockCollector)

        assert "test" in registry.registered_types

    def test_create_collector(self) -> None:
        """Test creating a collector instance."""
        registry = CollectorRegistry()
        registry.register_class("test", TestDomainCollector.MockCollector)

        collector = registry.create_collector("my-test", "test")

        assert collector.name == "my-test"
        assert "my-test" in registry.active_collectors

    def test_create_unknown_collector(self) -> None:
        """Test error when creating unknown collector type."""
        from curadise_agent.errors import ConfigurationError

        registry = CollectorRegistry()

        with pytest.raises(ConfigurationError, match="Unknown collector type"):
            registry.create_collector("test", "unknown")

    def test_get_enabled_collectors(self, collector_config: CollectorConfig) -> None:
        """Test getting only enabled collectors."""
        registry = CollectorRegistry()
        registry.register_class("test", TestDomainCollector.MockCollector)

        registry.create_collector("enabled", "test", config=collector_config)
        c2 = registry.create_collector("disabled", "test", config=collector_config)
        c2.disable()

        enabled = registry.get_enabled_collectors()
        assert len(enabled) == 1
        assert enabled[0].name == "enabled"
