"""Tests for opt-in deterministic structured logging."""

from __future__ import annotations

import importlib
import io
import json
import logging

import pytest

from osm_lead_source_service.errors import ContractViolation
from osm_lead_source_service.logging_setup import configure_logging, emit_event


@pytest.fixture(autouse=True)
def clean_package_logger() -> None:
    logger = logging.getLogger("osm_lead_source_service")
    original_handlers = list(logger.handlers)
    for handler in original_handlers:
        logger.removeHandler(handler)
    yield
    for handler in list(logger.handlers):
        logger.removeHandler(handler)
    for handler in original_handlers:
        logger.addHandler(handler)


def test_package_import_does_not_configure_package_logger() -> None:
    logger = logging.getLogger("osm_lead_source_service")
    before = list(logger.handlers)
    importlib.import_module("osm_lead_source_service.logging_setup")
    assert logger.handlers == before


def test_event_name_and_message_are_separate_deterministic_json_fields() -> None:
    stream = io.StringIO()
    logger = configure_logging(json_output=True, stream=stream)

    emit_event(logger, "configuration.validated", message="Configuration is valid")

    assert stream.getvalue() == (
        '{"event":"configuration.validated","level":"INFO",'
        '"logger":"osm_lead_source_service","message":"Configuration is valid"}\n'
    )
    record = json.loads(stream.getvalue())
    assert record["event"] == "configuration.validated"
    assert record["message"] == "Configuration is valid"


def test_changing_human_message_does_not_change_event_identifier() -> None:
    stream = io.StringIO()
    logger = configure_logging(json_output=True, stream=stream)

    emit_event(logger, "configuration.validated", message="first message")
    emit_event(logger, "configuration.validated", message="second message")

    records = [json.loads(line) for line in stream.getvalue().splitlines()]
    assert [record["event"] for record in records] == [
        "configuration.validated",
        "configuration.validated",
    ]
    assert [record["message"] for record in records] == ["first message", "second message"]


@pytest.mark.parametrize("event_name", ["", " ", "Configuration.Validated", "1invalid", "bad name"])
def test_blank_or_malformed_event_names_are_rejected(event_name: str) -> None:
    logger = logging.getLogger("osm_lead_source_service")
    with pytest.raises(ContractViolation, match="event_name"):
        emit_event(logger, event_name)


def test_repeated_explicit_configuration_does_not_duplicate_output() -> None:
    stream = io.StringIO()
    logger = configure_logging(json_output=True, stream=stream)
    configure_logging(json_output=True, stream=stream)

    assert len(logger.handlers) == 1
    emit_event(logger, "configuration.validated")
    assert len(stream.getvalue().splitlines()) == 1


def test_json_logging_does_not_dump_secrets_or_record_internals() -> None:
    stream = io.StringIO()
    logger = configure_logging(json_output=True, stream=stream)
    secret = "SECRET_VALUE_SHOULD_NOT_APPEAR"

    emit_event(logger, "configuration.validated", message="safe human message")

    output = stream.getvalue()
    assert secret not in output
    assert "environ" not in output
    assert "__dict__" not in output
    assert "safe human message" in output
