# #region test_logger [TYPE Module] [C:3] [SEMANTICS test, logger, logging, unit]
# @BRIEF Unit tests for logger module
# @LAYER Infrastructure
# @RELATION BINDS_TO -> [LoggerModule]
from pathlib import Path
import sys

# Add src to path
sys.path.append(str(Path(__file__).parent.parent.parent.parent / "src"))
import logging
import pytest

from src.core.config_models import LoggingConfig
from src.core.logger import belief_scope, configure_logger, get_task_log_level, logger, should_log_task_level


def _marker(record):
    """Get decision audit marker from a log record (set via extra dict)."""
    return getattr(record, 'marker', None)


@pytest.fixture(autouse=True)
def reset_logger_state():
    """Reset logger state before each test to avoid cross-test contamination."""
    config = LoggingConfig(
        level="INFO",
        task_log_level="INFO",
        enable_belief_state=True
    )
    configure_logger(config)
    # Also reset the logger level for caplog to work correctly
    logging.getLogger("superset_tools_app").setLevel(logging.DEBUG)
    yield
    # Reset after test too
    config = LoggingConfig(
        level="INFO",
        task_log_level="INFO",
        enable_belief_state=True
    )
    configure_logger(config)
# #region test_belief_scope_logs_reason_reflect_at_debug [TYPE Function]
# @RELATION BINDS_TO -> [test_logger]
# @BRIEF Test that belief_scope generates [REASON] and [REFLECT] logs at DEBUG level.
# @PRE  belief_scope is available. caplog fixture is used. Logger configured to DEBUG.
# @POST  Logs are verified to contain REASON and REFLECT markers at DEBUG level.
def test_belief_scope_logs_reason_reflect_at_debug(caplog):
    """Test that belief_scope generates [REASON] and [REFLECT] logs at DEBUG level."""
    # Configure logger to DEBUG level
    config = LoggingConfig(
        level="DEBUG",
        task_log_level="DEBUG",
        enable_belief_state=True
    )
    configure_logger(config)

    caplog.set_level("DEBUG")
    with belief_scope("TestFunction"):
        logger.info("Doing something important")
    # Check that the logs contain the expected patterns
    log_records = list(caplog.records)
    log_messages = [record.message for record in log_records]
    assert any(_marker(r) == "REASON" and "TestFunction" in r.getMessage() for r in log_records), "REASON log not found"
    assert any("Doing something important" in msg for msg in log_messages), "Inline info log not found"
    assert any(_marker(r) == "REFLECT" for r in log_records), "REFLECT log not found"

    # Reset to INFO
    config = LoggingConfig(level="INFO", task_log_level="INFO", enable_belief_state=True)
    configure_logger(config)
# #endregion test_belief_scope_logs_reason_reflect_at_debug
# #region test_belief_scope_error_handling [TYPE Function]
# @RELATION BINDS_TO -> [test_logger]
# @BRIEF Test that belief_scope logs EXPLORE on exception.
# @PRE  belief_scope is available. caplog fixture is used. Logger configured to DEBUG.
# @POST  Logs are verified to contain EXPLORE marker.
def test_belief_scope_error_handling(caplog):
    """Test that belief_scope logs EXPLORE on exception."""
    # Configure logger to DEBUG level
    config = LoggingConfig(
        level="DEBUG",
        task_log_level="DEBUG",
        enable_belief_state=True
    )
    configure_logger(config)

    caplog.set_level("DEBUG")
    with pytest.raises(ValueError), belief_scope("FailingFunction"):
        raise ValueError("Something went wrong")
    log_records = list(caplog.records)
    assert any(_marker(r) == "REASON" and "FailingFunction" in r.getMessage() for r in log_records), "REASON log not found"
    assert any(
        _marker(r) == "EXPLORE" and "Something went wrong" in (getattr(r, 'error', '') or '')
        for r in log_records
    ), "EXPLORE log not found"
    # REFLECT should not be logged on failure

    # Reset to INFO
    config = LoggingConfig(level="INFO", task_log_level="INFO", enable_belief_state=True)
    configure_logger(config)
# #endregion test_belief_scope_error_handling
# #region test_belief_scope_success_reflect [TYPE Function]
# @RELATION BINDS_TO -> [test_logger]
# @BRIEF Test that belief_scope logs REFLECT on success.
# @PRE  belief_scope is available. caplog fixture is used. Logger configured to DEBUG.
# @POST  Logs are verified to contain REFLECT marker.
def test_belief_scope_success_reflect(caplog):
    """Test that belief_scope logs REFLECT on success."""
    # Configure logger to DEBUG level
    config = LoggingConfig(
        level="DEBUG",
        task_log_level="DEBUG",
        enable_belief_state=True
    )
    configure_logger(config)

    caplog.set_level("DEBUG")
    with belief_scope("SuccessFunction"):
        pass
    log_records = list(caplog.records)
    assert any(_marker(r) == "REFLECT" for r in log_records), "REFLECT log not found"

# #endregion test_belief_scope_success_reflect
# #region test_belief_scope_not_visible_at_info [TYPE Function]
# @RELATION BINDS_TO -> [test_logger]
# @BRIEF Test that belief_scope REFLECT logs are NOT visible at INFO level.
# @PRE  belief_scope is available. caplog fixture is used.
# @POST  REASON is visible at INFO (uses info()); REFLECT is not (uses debug()).
def test_belief_scope_not_visible_at_info(caplog):
    """Test that belief_scope REFLECT logs are NOT visible at INFO level.

    NOTE: Decision audit protocol: belief_scope uses cot_log(level='DEBUG')
    for both REASON (entry) and REFLECT (exit). At INFO level, neither
    should appear in caplog. The inline logger.info() IS visible because
    it goes through superset_tools_app at INFO.
    """
    caplog.set_level("INFO")
    with belief_scope("InfoLevelFunction"):
        logger.info("Doing something important")
    log_records = list(caplog.records)
    log_messages = [record.message for record in log_records]
    # Inline INFO log should be visible
    assert any("Doing something important" in msg for msg in log_messages), "INFO log not found"
    # REASON uses DEBUG level in decision audit → NOT visible at INFO
    assert not any(_marker(r) == "REASON" for r in log_records), "REASON is DEBUG-level, should NOT be visible at INFO"
    # REFLECT uses DEBUG level → NOT visible at INFO level
    assert not any(_marker(r) == "REFLECT" for r in log_records), "REFLECT is DEBUG-level, should NOT be visible at INFO"
# #endregion test_belief_scope_not_visible_at_info
# #region test_task_log_level_default [TYPE Function]
# @RELATION BINDS_TO -> [test_logger]
# @BRIEF Test that default task log level is INFO.
# @PRE  None.
# @POST  Default level is INFO.
def test_task_log_level_default():
    """Test that default task log level is INFO (after reset fixture)."""
    level = get_task_log_level()
    assert level == "INFO"
# #endregion test_task_log_level_default
# #region test_should_log_task_level [TYPE Function]
# @RELATION BINDS_TO -> [test_logger]
# @BRIEF Test that should_log_task_level correctly filters log levels.
# @PRE  None.
# @POST  Filtering works correctly for all level combinations.
def test_should_log_task_level():
    """Test that should_log_task_level correctly filters log levels."""
    # Default level is INFO
    assert should_log_task_level("ERROR") is True, "ERROR should be logged at INFO threshold"
    assert should_log_task_level("WARNING") is True, "WARNING should be logged at INFO threshold"
    assert should_log_task_level("INFO") is True, "INFO should be logged at INFO threshold"
    assert should_log_task_level("DEBUG") is False, "DEBUG should NOT be logged at INFO threshold"
# #endregion test_should_log_task_level
# #region test_configure_logger_task_log_level [TYPE Function]
# @RELATION BINDS_TO -> [test_logger]
# @BRIEF Test that configure_logger updates task_log_level.
# @PRE  LoggingConfig is available.
# @POST  task_log_level is updated correctly.
def test_configure_logger_task_log_level():
    """Test that configure_logger updates task_log_level."""
    config = LoggingConfig(
        level="DEBUG",
        task_log_level="DEBUG",
        enable_belief_state=True
    )
    configure_logger(config)

    assert get_task_log_level() == "DEBUG", "task_log_level should be DEBUG"
    assert should_log_task_level("DEBUG") is True, "DEBUG should be logged at DEBUG threshold"
# #endregion test_configure_logger_task_log_level
# #region test_enable_belief_state_flag [TYPE Function]
# @RELATION BINDS_TO -> [test_logger]
# @BRIEF Test that enable_belief_state flag controls belief_scope logging.
# @PRE  LoggingConfig is available. caplog fixture is used.
# @POST  belief_scope explicit REASON logs are controlled by the flag; REFLECT always logged.
def test_enable_belief_state_flag(caplog):
    """Test that enable_belief_state flag controls belief_scope REASON entry logging."""
    # Disable belief state
    config = LoggingConfig(
        level="DEBUG",
        task_log_level="DEBUG",
        enable_belief_state=False
    )
    configure_logger(config)

    caplog.set_level("DEBUG")

    with belief_scope("DisabledFunction"):
        logger.info("Doing something")

    log_records = list(caplog.records)
    log_messages = [record.message for record in log_records]

    # "Entering DisabledFunction" (explicit logger.reason()) should NOT be logged when disabled
    assert not any("Entering" in msg for msg in log_messages), "REASON entry should not be logged when disabled"
    # REFLECT should still be logged (internal tracking, not gated by _enable_belief_state)
    assert any(_marker(r) == "REFLECT" for r in log_records), "REFLECT should still be logged"
# #endregion test_enable_belief_state_flag
# #region test_belief_scope_missing_anchor [TYPE Function]
# @RELATION BINDS_TO -> [test_logger]
# @BRIEF Test @PRE condition: anchor_id must be provided
def test_belief_scope_missing_anchor():
    """Test that belief_scope enforces anchor_id to be provided."""
    import pytest

    from src.core.logger import belief_scope
    with pytest.raises(TypeError), belief_scope():
        pass
# #endregion test_belief_scope_missing_anchor
# #region test_configure_logger_post_conditions [TYPE Function]
# @RELATION BINDS_TO -> [test_logger]
# @BRIEF Test @POST condition: Logger level, handlers, belief state flag, and task log level are updated.
def test_configure_logger_post_conditions(tmp_path):
    """Test that configure_logger satisfies all @POST conditions."""
    import logging
    from logging.handlers import RotatingFileHandler

    from src.core.config_models import LoggingConfig
    import src.core.logger as logger_module
    from src.core.logger import configure_logger, get_task_log_level, logger
    log_file = tmp_path / "test.log"
    config = LoggingConfig(
        level="WARNING",
        task_log_level="DEBUG",
        enable_belief_state=False,
        file_path=str(log_file)
    )

    configure_logger(config)

    # 1. Logger level is updated
    assert logger.level == logging.WARNING

    # 2. Handlers are updated (file handler removed old ones, added new one)
    file_handlers = [h for h in logger.handlers if isinstance(h, RotatingFileHandler)]
    assert len(file_handlers) == 1
    import pathlib
    assert pathlib.Path(file_handlers[0].baseFilename) == log_file.resolve()

    # 3. Formatter is set to CotJsonFormatter (replaced BeliefFormatter)
    from src.core.logger import CotJsonFormatter
    for handler in logger.handlers:
        assert isinstance(handler.formatter, CotJsonFormatter)

    # 4. Global states
    assert logger_module._enable_belief_state is False
    assert get_task_log_level() == "DEBUG"
# #endregion test_configure_logger_post_conditions
# #endregion test_logger
