"""Opt-in structured logging helpers.

Importing this module does not change global logging state.  Call
``configure_logging`` explicitly from an application boundary when logging is
needed.
"""

from __future__ import annotations

import json
import logging
import re
import sys
from typing import TextIO

from .errors import ContractViolation

_PACKAGE_LOGGER_NAME = "osm_lead_source_service"
_DEFAULT_EVENT_NAME = "log"
_EVENT_NAME_PATTERN = re.compile(r"^[a-z][a-z0-9_.-]*$")
_HANDLER_MARKER = "_osm_lead_source_handler"


def _validate_event_name(event_name: str) -> str:
    if not isinstance(event_name, str):
        raise ContractViolation("event_name must be a string")
    normalized = event_name.strip()
    if not normalized or _EVENT_NAME_PATTERN.fullmatch(normalized) is None:
        raise ContractViolation("event_name must match ^[a-z][a-z0-9_.-]*$ and may not be blank")
    return normalized


class JsonFormatter(logging.Formatter):
    """Render a log record as one deterministic JSON object."""

    def format(self, record: logging.LogRecord) -> str:
        payload = {
            "event": getattr(record, "_osm_event_name", _DEFAULT_EVENT_NAME),
            "level": record.levelname,
            "logger": record.name,
        }
        message = getattr(record, "_osm_event_message", None)
        if message is not None:
            payload["message"] = message
        return json.dumps(payload, sort_keys=True, separators=(",", ":"))


def emit_event(
    logger: logging.Logger,
    event_name: str,
    *,
    level: int = logging.INFO,
    message: str | None = None,
) -> None:
    """Emit a stable event identifier with an optional human-readable message."""

    normalized_event_name = _validate_event_name(event_name)
    if message is not None and not isinstance(message, str):
        raise ContractViolation("message must be a string or None")
    logger.log(
        level,
        message if message is not None else normalized_event_name,
        extra={
            "_osm_event_name": normalized_event_name,
            "_osm_event_message": message,
        },
    )


def configure_logging(
    level: str = "INFO", *, json_output: bool = False, stream: TextIO | None = None
) -> logging.Logger:
    """Configure and return the package logger at an explicit application boundary."""

    logger = logging.getLogger(_PACKAGE_LOGGER_NAME)
    logger.setLevel(level.upper())

    for handler in list(logger.handlers):
        if getattr(handler, _HANDLER_MARKER, False):
            logger.removeHandler(handler)

    handler = logging.StreamHandler(stream or sys.stderr)
    setattr(handler, _HANDLER_MARKER, True)
    if json_output:
        handler.setFormatter(JsonFormatter())
    else:
        handler.setFormatter(logging.Formatter("%(levelname)s %(name)s %(message)s"))
    logger.addHandler(handler)
    logger.propagate = False
    return logger


__all__ = ["JsonFormatter", "configure_logging", "emit_event"]
