#
#   Imandra Inc.
#
#   speclogician/presentation/preview/fixtures/predicate.py
#

from __future__ import annotations

from datetime import datetime, timezone
from speclogician.presentation.ctx import RenderCtx
from speclogician.presentation.models.predicate import (
    PredicatePM,
    TransitionPM,
    LinkedArtifactsPM,
)
from speclogician.modeling.predicates import PredicateType
from speclogician.utils import IMLValidity


NOW = datetime(2026, 1, 9, 10, 12, tzinfo=timezone.utc)


# -----------------------------------------------------------------------------
# Shared helpers
# -----------------------------------------------------------------------------

def _minimal_links() -> LinkedArtifactsPM:
    return LinkedArtifactsPM()


def _typical_links() -> LinkedArtifactsPM:
    return LinkedArtifactsPM(
        total=4,
        test_traces=2,
        log_traces=1,
        doc_refs=1,
        src_code_refs=0,
        unresolved_ids=0,
        art_ids=["tt-1", "tt-2", "log-1", "doc-1"],
    )


def _edge_links() -> LinkedArtifactsPM:
    return LinkedArtifactsPM(
        total=12,
        test_traces=5,
        log_traces=3,
        doc_refs=2,
        src_code_refs=1,
        unresolved_ids=1,
        art_ids=[f"art-{i}" for i in range(12)],
    )


# -----------------------------------------------------------------------------
# PredicatePM variants
# -----------------------------------------------------------------------------

def _predicate_minimal() -> PredicatePM:
    return PredicatePM(
        kind="state_predicate",
        comp_id="pred-min",
        name="",
        last_updated=NOW,
        pred_type=PredicateType.STATE,
        signature="",
        src_code="",
        iml="",
        is_iml_valid=IMLValidity.UNKNOWN,
        iml_error=None,
        links=_minimal_links(),
    )


def _predicate_typical() -> PredicatePM:
    return PredicatePM(
        kind="state_predicate",
        comp_id="pred-001",
        name="pred_eq_ten",
        last_updated=NOW,
        pred_type=PredicateType.STATE,
        signature="state -> bool",
        src_code="s.x = 10",
        iml="let pred_eq_ten (s: state) = s.x = 10",
        is_iml_valid=IMLValidity.VALID,
        iml_error=None,
        links=_typical_links(),
    )


def _predicate_edge() -> PredicatePM:
    return PredicatePM(
        kind="action_predicate",
        comp_id="pred-edge-999",
        name="pred_complex_action_condition_with_long_name",
        last_updated=NOW,
        pred_type=PredicateType.ACTION,
        signature="state -> action -> bool",
        src_code="a.qty > s.max_qty &&\n(a.price > 0 || a.kind = Market)",
        iml=(
            "let pred_complex_action_condition_with_long_name (s: state) (a: action) =\n"
            "  a.qty > s.max_qty && (a.price > 0 || a.kind = Market)"
        ),
        is_iml_valid=IMLValidity.INVALID,
        iml_error="Type error: cannot compare int and option<int> in expression a.price > 0",
        links=_edge_links(),
    )


def make_predicate_pm(ctx: RenderCtx, variant: str = "typical") -> PredicatePM:
    v = (variant or "typical").strip().lower()
    if v == "minimal":
        return _predicate_minimal()
    if v == "edge":
        return _predicate_edge()
    return _predicate_typical()

def render_predicate(pm: PredicatePM, ctx: RenderCtx):
    from speclogician.presentation.renderers.predicate import render_predicate
    return render_predicate(pm, ctx=ctx)

# -----------------------------------------------------------------------------
# TransitionPM variants
# -----------------------------------------------------------------------------

def _transition_minimal() -> TransitionPM:
    return TransitionPM(
        kind="transition",
        comp_id="trans-min",
        name="",
        last_updated=NOW,
        signature="",
        src_code="",
        iml="",
        is_iml_valid=IMLValidity.UNKNOWN,
        iml_error=None,
        links=_minimal_links(),
    )


def _transition_typical() -> TransitionPM:
    return TransitionPM(
        kind="transition",
        comp_id="trans-001",
        name="step1",
        last_updated=NOW,
        signature="state -> action -> state",
        src_code="{ x = s.x + a }",
        iml="let step1 (s: state) (a: action) : state =\n  { x = s.x + a }",
        is_iml_valid=IMLValidity.VALID,
        iml_error=None,
        links=_typical_links(),
    )


def _transition_edge() -> TransitionPM:
    return TransitionPM(
        kind="transition",
        comp_id="trans-edge-888",
        name="step_with_very_long_and_descriptive_name",
        last_updated=NOW,
        signature="state -> action -> state",
        src_code="{ x = if a > 0 then s.x + a else false }",
        iml=(
            "let step_with_very_long_and_descriptive_name (s: state) (a: action) : state =\n"
            "  { x = if a > 0 then s.x + a else false }"
        ),
        is_iml_valid=IMLValidity.INVALID,
        iml_error="Type error: expected int, got bool in field x",
        links=_edge_links(),
    )


def make_transition_pm(ctx: RenderCtx, variant: str = "typical") -> TransitionPM:
    v = (variant or "typical").strip().lower()
    if v == "minimal":
        return _transition_minimal()
    if v == "edge":
        return _transition_edge()
    return _transition_typical()

def render_transition(pm: TransitionPM, ctx: RenderCtx):
    from speclogician.presentation.renderers.predicate import render_transition
    return render_transition(pm, ctx=ctx)