#
#   Imandra Inc.
#
#   speclogician/presentation/models/trace_reachability.py
#

from __future__ import annotations

from typing import Literal
from pydantic import BaseModel, Field


class TraceReachabilityCountsPM(BaseModel):
    total_traces: int = 0
    total_steps: int = 0
    total_hops: int = 0
    supported_hops: int = 0
    unsupported_hops: int = 0

    scenarios_hit: int = 0
    scenarios_unhit: int = 0


class TraceReachabilityHopPM(BaseModel):
    step_from: int
    step_to: int
    src: str | None = None
    dst: str | None = None
    supported_by_graph: bool = False
    reason: str | None = None
    shortest_path: list[str] | None = None


class TraceReachabilityTracePM(BaseModel):
    trace_id: str
    trace_label: str
    trace_kind: str  # "test" | "log" | "unknown"

    num_steps: int = 0
    num_matched_steps: int = 0
    num_supported_hops: int = 0
    num_unsupported_hops: int = 0

    # DP selection; None => unmatched
    step_best: list[str | None] = Field(default_factory=list)

    # capped extras for drilldown
    unsupported_hops: list[TraceReachabilityHopPM] = Field(default_factory=list)


class TraceReachabilitySummaryPM(BaseModel):
    top_unsupported_edges: list[tuple[str, str, int]] = Field(default_factory=list)
    top_frontier_trace_endings: list[tuple[str, int]] = Field(default_factory=list)

    # optional short lists for UI
    scenarios_unhit_preview: list[str] = Field(default_factory=list)


class TraceReachabilityPM(BaseModel):
    """
    Presentation model for TraceReachabilityAnalysis.

    NOTE: ctx-aware filtering (e.g. `ctx.trace_id`) is applied in the *builder*,
    not in this schema. This model is shaped so the builder can emit either:
      - full analysis across all traces, or
      - filtered view for a single trace (list length 0/1).
    """
    kind: Literal["trace_reachability"] = "trace_reachability"

    counts: TraceReachabilityCountsPM = Field(default_factory=TraceReachabilityCountsPM)
    summary: TraceReachabilitySummaryPM = Field(default_factory=TraceReachabilitySummaryPM)

    # list view (builder may filter based on ctx.trace_id)
    traces: list[TraceReachabilityTracePM] = Field(default_factory=list)

    # optional fingerprints for “stale analysis” UI
    spec_fp: str | None = None
    artifacts_fp: str | None = None
    mapping_fp: str | None = None