"""Public logger core for Phase 2 (no transports)."""

from __future__ import annotations

from vedatrace._engine import Engine
from vedatrace.config import VedaTraceConfig
from vedatrace.models import LogLevel, Metadata, LogRecord
from vedatrace.safe import safe_call


def merge_metadata(parent: Metadata, child: Metadata, call: Metadata) -> Metadata:
    """Merge metadata with precedence parent < child < call."""

    merged: Metadata = dict(parent)
    merged.update(dict(child))
    merged.update(dict(call))
    return merged


class Logger:
    """Logger facade with non-throwing public methods."""

    def __init__(
        self,
        config: VedaTraceConfig,
        engine: Engine,
        *,
        default_metadata: Metadata | None = None,
        service: str | None = None,
        _owns_engine: bool = True,
        _parent_metadata: Metadata | None = None,
    ) -> None:
        self._config = config
        self._engine = engine
        self._parent_metadata: Metadata = (
            {} if _parent_metadata is None else dict(_parent_metadata)
        )
        self._default_metadata: Metadata = (
            {} if default_metadata is None else dict(default_metadata)
        )
        self._service = config.service if service is None else service
        self._owns_engine = _owns_engine

    def debug(self, message: str, metadata: Metadata | None = None) -> None:
        safe_call(
            lambda: self._emit_record(LogLevel.DEBUG, message, metadata),
            on_error=self._config.on_error,
            default=None,
        )

    def info(self, message: str, metadata: Metadata | None = None) -> None:
        safe_call(
            lambda: self._emit_record(LogLevel.INFO, message, metadata),
            on_error=self._config.on_error,
            default=None,
        )

    def warning(self, message: str, metadata: Metadata | None = None) -> None:
        safe_call(
            lambda: self._emit_record(LogLevel.WARNING, message, metadata),
            on_error=self._config.on_error,
            default=None,
        )

    def error(self, message: str, metadata: Metadata | None = None) -> None:
        safe_call(
            lambda: self._emit_record(LogLevel.ERROR, message, metadata),
            on_error=self._config.on_error,
            default=None,
        )

    def fatal(self, message: str, metadata: Metadata | None = None) -> None:
        safe_call(
            lambda: self._emit_record(LogLevel.FATAL, message, metadata),
            on_error=self._config.on_error,
            default=None,
        )

    def flush(self) -> None:
        safe_call(
            self._engine.flush,
            on_error=self._config.on_error,
            default=None,
        )

    def close(self) -> None:
        safe_call(
            self._close,
            on_error=self._config.on_error,
            default=None,
        )

    def child(
        self,
        default_metadata: Metadata | None = None,
        *,
        service: str | None = None,
    ) -> "Logger":
        child_parent_metadata = merge_metadata(
            parent=self._parent_metadata,
            child=self._default_metadata,
            call={},
        )
        return Logger(
            self._config,
            self._engine,
            default_metadata=default_metadata,
            service=self._service if service is None else service,
            _owns_engine=False,
            _parent_metadata=child_parent_metadata,
        )

    def _emit_record(
        self,
        level: LogLevel,
        message: str,
        metadata: Metadata | None,
    ) -> None:
        call_metadata: Metadata = {} if metadata is None else dict(metadata)
        resolved_metadata = merge_metadata(
            parent=self._parent_metadata,
            child=self._default_metadata,
            call=call_metadata,
        )
        record = LogRecord.create(
            level=level,
            message=message,
            service=self._service,
            metadata=resolved_metadata,
        )
        self._engine.emit(record)

    def _close(self) -> None:
        if not self._owns_engine:
            return None
        self._engine.close()
        return None
