"""Layer 2 — Wrap real operations in spans + show the no-op-safe shape.

Realistic use of operation_span: each L2 use case (the function
the CLI / GUI invokes) is wrapped in a span with a stable name
and structured attributes. Logging emitted inside the span will
auto-carry trace_id + span_id when OTel is configured (rule LG-03).
"""

from __future__ import annotations

import logging
import os
import tempfile
import time
from pathlib import Path

import mgf.common
from mgf.common.observability import operation_span
from mgf.common.settings import LoggingSettings, MgfSettings


def fetch_widget(LOG: logging.Logger, widget_id: str) -> dict[str, str]:
    """A simulated use case wrapped in a span.

    Span name follows ``<subject>.<verb>`` (per rule §7.3 of
    LOGGING.md). Attributes use snake_case keys.
    """
    with operation_span("widget.fetch", widget_id=widget_id):
        LOG.info("fetching widget", extra={"widget_id": widget_id})
        # Pretend to do work.
        time.sleep(0.005)
        result = {"id": widget_id, "name": f"widget-{widget_id}"}
        # IMPORTANT: `name` is reserved by Python's LogRecord (it's the
        # logger name). Using it in `extra={...}` raises KeyError. Use
        # a distinct field name like `widget_name`.
        LOG.info(
            "fetched widget",
            extra={"widget_id": widget_id, "widget_name": result["name"]},
        )
        return result


def main() -> None:
    with tempfile.TemporaryDirectory() as tmp:
        os.environ["XDG_STATE_HOME"] = tmp

        # bootstrap() wires identity + logging + OTel in one call.
        # No-op OTel without OTEL_EXPORTER_OTLP_ENDPOINT — the example
        # still runs cleanly. With endpoint set, every span below
        # emits to the collector.
        with mgf.common.bootstrap(
            app_name="example-practical-otel",
            app_version="0.1.0",
            settings=MgfSettings(
                logging=LoggingSettings(
                    level="INFO", format="json", file=Path(tmp) / "demo.log",
                ),
            ),
        ):
            LOG = logging.getLogger(__name__)

            # Wrap every use case in a span. The wrapping shape is the
            # same regardless of whether OTel is active — code stays
            # uniform across dev (no OTel) and prod (OTLP exporter).
            for widget_id in ("w-1", "w-2", "w-3"):
                fetch_widget(LOG, widget_id)

            # Spans nest naturally; the parent-child relationship is
            # tracked by the OTel SDK (or harmlessly ignored when no-op).
            with operation_span("batch.summary", count=3):
                LOG.info("batch complete", extra={"widgets_fetched": 3})

            print("\nNote: OTLP_EXPORTER_OTLP_ENDPOINT is unset, so spans were no-op.")
            print("Set it (and install [observability]) to see real trace export.")


if __name__ == "__main__":
    main()
