"""
Tests for _warn_once utility (P2-8).

Covers:
    - First call logs WARNING
    - Second call with same key logs DEBUG
    - Different key logs WARNING again
    - Max keys bounded — after limit, all new keys get DEBUG
"""

from __future__ import annotations

import logging

import pytest

import risicare.integrations._base as base_mod
from risicare.integrations._base import _warn_once


@pytest.fixture(autouse=True)
def _reset_warned_keys():
    """Reset global _warned_keys before each test."""
    original = base_mod._warned_keys.copy()
    base_mod._warned_keys.clear()
    yield
    base_mod._warned_keys.clear()
    base_mod._warned_keys.update(original)


class TestWarnOnce:
    """Tests for the _warn_once function."""

    def test_first_call_logs_warning(self, caplog):
        """First call with a key should log at WARNING level."""
        log = logging.getLogger("test.warn_once")
        with caplog.at_level(logging.DEBUG, logger="test.warn_once"):
            _warn_once(log, "test.key.1", "Something failed: %s", "details")

        assert len(caplog.records) == 1
        assert caplog.records[0].levelno == logging.WARNING
        assert "Something failed: details" in caplog.records[0].message

    def test_second_call_logs_debug(self, caplog):
        """Second call with the same key should log at DEBUG level."""
        log = logging.getLogger("test.warn_once")
        with caplog.at_level(logging.DEBUG, logger="test.warn_once"):
            _warn_once(log, "test.key.2", "First time")
            caplog.clear()
            _warn_once(log, "test.key.2", "Second time")

        assert len(caplog.records) == 1
        assert caplog.records[0].levelno == logging.DEBUG
        assert "Second time" in caplog.records[0].message

    def test_different_keys_both_warn(self, caplog):
        """Different keys should each get their own WARNING."""
        log = logging.getLogger("test.warn_once")
        with caplog.at_level(logging.DEBUG, logger="test.warn_once"):
            _warn_once(log, "key.a", "Message A")
            _warn_once(log, "key.b", "Message B")

        warnings = [r for r in caplog.records if r.levelno == logging.WARNING]
        assert len(warnings) == 2

    def test_max_keys_bounded(self, caplog):
        """After _WARN_ONCE_MAX_KEYS, new keys should get DEBUG, not WARNING."""
        # Temporarily set a small max
        original_max = base_mod._WARN_ONCE_MAX_KEYS
        try:
            base_mod._WARN_ONCE_MAX_KEYS = 5

            # Fill up to the limit
            for i in range(6):
                base_mod._warned_keys.add(f"filler.{i}")

            log = logging.getLogger("test.warn_once")
            with caplog.at_level(logging.DEBUG, logger="test.warn_once"):
                _warn_once(log, "brand.new.key", "Should be DEBUG not WARNING")

            assert len(caplog.records) == 1
            assert caplog.records[0].levelno == logging.DEBUG
        finally:
            base_mod._WARN_ONCE_MAX_KEYS = original_max

    def test_format_string_args(self, caplog):
        """Format string with multiple args should work correctly."""
        log = logging.getLogger("test.warn_once")
        with caplog.at_level(logging.DEBUG, logger="test.warn_once"):
            _warn_once(log, "fmt.test", "Failed to patch %s v%s: %s", "langchain", "0.3", "ImportError")

        assert "Failed to patch langchain v0.3: ImportError" in caplog.records[0].message
