"""Tests for CoreMetricsProvider."""

from unittest.mock import MagicMock

from fastpluggy.core.core_metrics import CoreMetricsProvider
from fastpluggy.core.metrics import MetricsProvider, MetricsResult
from fastpluggy.core.plugin_state import PluginState


def _make_fp(*, loaded_count=3, enabled_count=5, failed_count=1,
             load_time_ms=123.4, plugin_load_times=None,
             events_dispatched=42, listener_count=7):
    """Build a mock FastPluggy with the given metrics values."""
    fp = MagicMock()

    # Build module states
    modules = {}
    for i in range(loaded_count):
        ps = MagicMock(spec=PluginState)
        ps.loaded = True
        ps.enabled = True
        modules[f"loaded_{i}"] = ps
    for i in range(failed_count):
        ps = MagicMock(spec=PluginState)
        ps.loaded = False
        ps.enabled = True
        modules[f"failed_{i}"] = ps
    # Add disabled plugins to reach enabled_count
    disabled_needed = enabled_count - loaded_count - failed_count
    for i in range(max(0, disabled_needed)):
        ps = MagicMock(spec=PluginState)
        ps.loaded = False
        ps.enabled = False
        modules[f"disabled_{i}"] = ps

    fp.module_manager.modules = modules
    fp.module_manager._plugin_load_times = plugin_load_times or {}
    fp._load_time_ms = load_time_ms
    fp.events.events_dispatched = events_dispatched
    fp.events.listener_count.return_value = listener_count

    return fp


class TestCoreMetricsProvider:
    def test_implements_protocol(self):
        fp = _make_fp()
        provider = CoreMetricsProvider(fp)
        assert isinstance(provider, MetricsProvider)

    def test_returns_metrics_result(self):
        fp = _make_fp()
        result = CoreMetricsProvider(fp).get_metrics()
        assert isinstance(result, MetricsResult)

    def test_plugin_counts(self):
        fp = _make_fp(loaded_count=4, failed_count=2)
        result = CoreMetricsProvider(fp).get_metrics()

        by_name = {g.name: g for g in result.gauges if not g.labels}
        assert by_name["plugins_loaded"].value == 4
        assert by_name["plugins_failed"].value == 2
        # enabled = loaded + failed (all have enabled=True)
        assert by_name["plugins_enabled"].value == 6

    def test_load_time(self):
        fp = _make_fp(load_time_ms=567.8)
        result = CoreMetricsProvider(fp).get_metrics()
        by_name = {g.name: g for g in result.gauges if not g.labels}
        assert by_name["load_time_ms"].value == 567.8

    def test_per_plugin_load_times(self):
        times = {"auth_user": 50.0, "metrics": 30.0}
        fp = _make_fp(plugin_load_times=times)
        result = CoreMetricsProvider(fp).get_metrics()

        plugin_metrics = [g for g in result.gauges if g.name == "plugin_load_time_ms"]
        assert len(plugin_metrics) == 2
        labels = {g.labels["plugin"]: g.value for g in plugin_metrics}
        assert labels == {"auth_user": 50.0, "metrics": 30.0}

    def test_event_listeners_count(self):
        fp = _make_fp(listener_count=12)
        result = CoreMetricsProvider(fp).get_metrics()
        by_name = {g.name: g for g in result.gauges if not g.labels}
        assert by_name["event_listeners_count"].value == 12

    def test_events_dispatched_counter(self):
        fp = _make_fp(events_dispatched=99)
        result = CoreMetricsProvider(fp).get_metrics()
        assert len(result.counters) == 1
        c = result.counters[0]
        assert c.name == "events_dispatched_total"
        assert c.value == 99
        assert c.type == "counter"

    def test_metric_names_no_fp_prefix(self):
        """Metric names must NOT start with fp_ — the router adds the prefix."""
        fp = _make_fp()
        result = CoreMetricsProvider(fp).get_metrics()
        for entry in result.all_entries:
            assert not entry.name.startswith("fp_"), f"{entry.name} should not start with fp_"

    def test_gauge_types(self):
        fp = _make_fp()
        result = CoreMetricsProvider(fp).get_metrics()
        for g in result.gauges:
            assert g.type == "gauge"
