"""Structured JSON logging via structlog."""
from __future__ import annotations

import logging
import sys
from contextvars import ContextVar
from typing import Any

import structlog

_job_run_id: ContextVar[str] = ContextVar("job_run_id", default="")


def bind_job_run_id(run_id: str) -> None:
    _job_run_id.set(run_id)


def _add_job_run_id(
    logger: Any, method: str, event_dict: dict[str, Any]
) -> dict[str, Any]:
    run_id = _job_run_id.get()
    if run_id:
        event_dict["job_run_id"] = run_id
    return event_dict


def _make_events_sink_processor():
    """Return a structlog processor that tees events to EventsStore.

    Imported lazily to avoid a circular import at configure_logging() call time
    (EventsStore lives in apps/web which is not always present in subprocess env).
    Falls back to a no-op if the import fails.
    """
    try:
        from apps.web.services.events_store import structlog_sink_processor
        return structlog_sink_processor
    except Exception:
        return None


def configure_logging(level: str = "INFO", enable_events_sink: bool = False) -> None:
    import os as _os
    logging.basicConfig(
        format="%(message)s",
        stream=sys.stdout,
        level=getattr(logging, level.upper(), logging.INFO),
    )
    # In subprocess env, inherit JOB_RUN_ID from parent if set
    _env_id = _os.environ.get("JOB_RUN_ID")
    if _env_id:
        bind_job_run_id(_env_id)

    processors: list[Any] = [
        structlog.contextvars.merge_contextvars,
        _add_job_run_id,
        structlog.stdlib.add_log_level,
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.StackInfoRenderer(),
        structlog.processors.format_exc_info,
    ]

    if enable_events_sink:
        sink = _make_events_sink_processor()
        if sink is not None:
            processors.append(sink)

    processors.append(structlog.processors.JSONRenderer())

    structlog.configure(
        processors=processors,
        wrapper_class=structlog.make_filtering_bound_logger(
            getattr(logging, level.upper(), logging.INFO)
        ),
        context_class=dict,
        logger_factory=structlog.PrintLoggerFactory(),
        cache_logger_on_first_use=False,
    )


def get_logger(name: str = "") -> structlog.BoundLogger:
    return structlog.get_logger(name)
