"""Execution DTOs — contracts for pathway execution.

PathwayRecord is here because it references Context.
For the pure data models (PathwayEvent, PathwayStatus, PathwayMetrics),
see core.pathways.models.execution.
"""

from typing import Any

from pydantic import BaseModel, Field, model_validator

from core.common import JsonObject

# Re-export from canonical location for backward compatibility
from core.pathways.models.execution import PathwayEvent, PathwayMetrics, PathwayStatus


def _deep_serialise(value: object) -> object:
    """Recursively convert Pydantic models to dicts so the value is JSON-safe.

    Used at the PathwayRecord boundary — the single canonical place where
    typed Python objects become serialisable data for storage / audit.
    """
    if isinstance(value, BaseModel):
        return value.model_dump()
    if isinstance(value, dict):
        return {k: _deep_serialise(v) for k, v in value.items()}
    if isinstance(value, list):
        return [_deep_serialise(v) for v in value]
    return value


class PathwayRecord(BaseModel):
    """Record of a pathway execution.

    This is the **serialisation boundary** between the typed VM pipeline
    and external consumers (storage, HTTP responses, logging).

    The ``inputs`` / ``outputs`` / ``metadata`` fields are ``JsonObject``
    (JSON-serialisable dicts).  A ``model_validator`` automatically
    converts any Pydantic models found in these fields to plain dicts so
    callers never need to worry about pre-serialising.
    """

    model_config = {"extra": "allow", "arbitrary_types_allowed": True}

    id: str
    pathway_id: str
    status: PathwayStatus = PathwayStatus.PENDING
    inputs: JsonObject = Field(default_factory=dict)
    outputs: JsonObject = Field(default_factory=dict)
    provenance: JsonObject = Field(default_factory=dict)
    context: object | None = None  # Runtime type: Context (avoids circular import)
    events: list[PathwayEvent] = Field(default_factory=list)
    metrics: PathwayMetrics = Field(default_factory=PathwayMetrics)
    error: str | None = None
    metadata: JsonObject = Field(default_factory=dict)

    @model_validator(mode="before")
    @classmethod
    def _serialise_typed_fields(cls, values: Any) -> Any:
        """Auto-serialise Pydantic objects in dict fields at construction."""
        if isinstance(values, dict):
            for key in ("inputs", "outputs", "provenance", "metadata"):
                raw = values.get(key)
                if raw is not None:
                    values[key] = _deep_serialise(raw)
        return values

    @property
    def success(self) -> bool:
        """Check if execution completed successfully."""
        return self.status == PathwayStatus.COMPLETED


__all__ = [
    "PathwayEvent",
    "PathwayMetrics",
    "PathwayRecord",
    "PathwayStatus",
]
