"""SP18 — ``setup_logging`` entry-point tests.

Covers level resolution, handler attachment, env-var overrides, and
the idempotent re-setup behavior used by the FastAPI lifespan and
the CLI's ``main()``.
"""
from __future__ import annotations

import logging
import os
from pathlib import Path

import pytest

from cyclone.logging_config import (
    CycloneDevFormatter,
    JsonFormatter,
    PiiScrubber,
    setup_logging,
)


@pytest.fixture(autouse=True)
def _reset_root_logger():
    """Strip our handlers + filters before each test so setup runs clean."""
    root = logging.getLogger()
    for h in list(root.handlers):
        root.removeHandler(h)
    for flt in list(root.filters):
        if isinstance(flt, PiiScrubber):
            root.removeFilter(flt)
    yield
    for h in list(root.handlers):
        root.removeHandler(h)
    for flt in list(root.filters):
        if isinstance(flt, PiiScrubber):
            root.removeFilter(flt)


def test_setup_respects_level_string():
    setup_logging(level="DEBUG", json_format=True)
    assert logging.getLogger().level == logging.DEBUG
    setup_logging(level="WARNING", json_format=True)
    assert logging.getLogger().level == logging.WARNING


def test_setup_attaches_rotating_file_handler(tmp_path: Path):
    log_file = tmp_path / "cyclone.log"
    setup_logging(level="INFO", log_file=str(log_file), json_format=True)
    root = logging.getLogger()
    assert len(root.handlers) == 1
    h = root.handlers[0]
    # RotatingFileHandler has ``baseFilename`` attr.
    assert hasattr(h, "baseFilename")
    assert Path(h.baseFilename).name == "cyclone.log"


def test_setup_defaults_to_json_formatter():
    setup_logging(level="INFO")
    root = logging.getLogger()
    assert isinstance(root.handlers[0].formatter, JsonFormatter)


def test_setup_dev_toggle_uses_dev_formatter():
    setup_logging(level="INFO", json_format=False)
    root = logging.getLogger()
    assert isinstance(root.handlers[0].formatter, CycloneDevFormatter)


def test_setup_idempotent_re_setup_replaces_handlers():
    """Re-calling setup_logging clears the previous handler(s)."""
    setup_logging(level="INFO", json_format=True)
    setup_logging(level="DEBUG", json_format=False)
    root = logging.getLogger()
    assert len(root.handlers) == 1
    assert isinstance(root.handlers[0].formatter, CycloneDevFormatter)
    assert root.level == logging.DEBUG


def test_setup_quietens_noisy_third_party_loggers():
    setup_logging(level="DEBUG", json_format=True)
    for noisy in ("urllib3", "paramiko", "sqlalchemy.engine"):
        assert logging.getLogger(noisy).level >= logging.WARNING


def test_setup_attaches_pii_scrubber_by_default():
    setup_logging(level="INFO", json_format=True)
    root = logging.getLogger()
    assert any(isinstance(f, PiiScrubber) for f in root.filters)


def test_setup_honors_scrub_pii_false():
    setup_logging(level="INFO", json_format=True, scrub_pii=False)
    root = logging.getLogger()
    # Scrubber is still attached but disabled.
    scrubbers = [f for f in root.filters if isinstance(f, PiiScrubber)]
    assert len(scrubbers) == 1
    assert scrubbers[0]._enabled is False  # noqa: SLF001


def test_setup_honors_env_var_no_pii_scrub(monkeypatch):
    monkeypatch.setenv("CYCLONE_LOG_NO_PII_SCRUB", "1")
    setup_logging(level="INFO", json_format=True)
    scrubbers = [f for f in logging.getLogger().filters if isinstance(f, PiiScrubber)]
    assert scrubbers and scrubbers[0]._enabled is False  # noqa: SLF001


def test_setup_emits_json_to_stderr_by_default(caplog):
    """Records emitted after setup flow through JsonFormatter."""
    setup_logging(level="INFO", json_format=True)
    logger = logging.getLogger("cyclone.test_setup")
    logger.info("hello %s", "world", extra={"x": 1})
    # Cyclone attaches the handler to root, not the named logger; caplog
    # won't capture unless we propagate (which is the default).
    # Just assert the handler is on root and would format correctly.
    root = logging.getLogger()
    h = root.handlers[0]
    record = logger.makeRecord(
        name="cyclone.test_setup", level=logging.INFO, fn="t.py", lno=1,
        msg="hello %s", args=("world",), exc_info=None,
    )
    record.x = 1
    formatted = h.formatter.format(record)
    import json as _json
    parsed = _json.loads(formatted)
    assert parsed["msg"] == "hello world"
    assert parsed["extra"]["x"] == 1
