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

from __future__ import annotations
from speclogician.presentation.ctx import RenderCtx
from speclogician.presentation.models.trace import (
    TraceIMLValidityPM,
    TraceCorePM,
    TestTracePM,
    LogTracePM,
)
from speclogician.presentation.renderers.trace import (
    render_test_trace,
    render_log_trace,
)


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

def minimal_iml_validity() -> TraceIMLValidityPM:
    return TraceIMLValidityPM(iml_valid="unknown", err=None)

def typical_iml_validity_valid() -> TraceIMLValidityPM:
    return TraceIMLValidityPM(iml_valid="valid", err=None)

def typical_iml_validity_invalid() -> TraceIMLValidityPM:
    return TraceIMLValidityPM(
        iml_valid="invalid",
        err="Parse error: expected ')' at line 1, col 12",
    )

def edge_iml_validity_invalid_long() -> TraceIMLValidityPM:
    return TraceIMLValidityPM(
        iml_valid="invalid",
        err=(
            "Type error: cannot unify int and bool in expression "
            "`if s.x > 0 then 1 else false` (line 42, col 3). "
            "Hint: check predicate body and variable bindings."
        ),
    )

def minimal_trace_core() -> TraceCorePM:
    return TraceCorePM(
        art_id="00000000-0000-0000-0000-000000000000",
        given="",
        when=None,
        then=None,
        time="",
        iml_validity=minimal_iml_validity(),
    )

def typical_trace_core_ok(*, art_id: str = "11111111-1111-1111-1111-111111111111") -> TraceCorePM:
    return TraceCorePM(
        art_id=art_id,
        given="{ x = 10 }",
        when="{ a = 2 }",
        then="{ x = 12 }",
        time="2026-01-09T10:12:00Z",
        iml_validity=typical_iml_validity_valid(),
    )

def typical_trace_core_invalid(*, art_id: str = "22222222-2222-2222-2222-222222222222") -> TraceCorePM:
    return TraceCorePM(
        art_id=art_id,
        given="{ x = 10 }",
        when="{ a = 2 }",
        then="{ x = 12 }",
        time="2026-01-09T10:13:00Z",
        iml_validity=typical_iml_validity_invalid(),
    )

def edge_trace_core_long(*, art_id: str = "99999999-9999-9999-9999-999999999999") -> TraceCorePM:
    # Deliberately long / multi-line / weird to stress renderers
    return TraceCorePM(
        art_id=art_id,
        given=(
            "{ x = 10; notes = \"a very long string value that will wrap in tables\"; "
            "nested = { y = 1234567890; z = -42 } }"
        ),
        when="{ a = 2; meta = \"multiline\\nwith newlines\\nand spaces\\n\" }",
        then="{ x = 12; result = Some \"OK\"; debug = \"a\" ^ \"b\" ^ \"c\" }",
        time="2026-01-09T10:12:00.123456Z",
        iml_validity=edge_iml_validity_invalid_long(),
    )

# -----------------------------------------------------------------------------
# TestTracePM fixtures
# -----------------------------------------------------------------------------

def minimal_test_trace_pm() -> TestTracePM:
    return TestTracePM(
        core=minimal_trace_core(),
        name="",
        filepath="",
        language=None,
        contents=None,
    )

def typical_test_trace_pm(*, with_contents: bool = False, invalid: bool = False) -> TestTracePM:
    core = typical_trace_core_invalid() if invalid else typical_trace_core_ok()
    return TestTracePM(
        core=core,
        name="Two parent orders, one rejected",
        filepath="tests/risk/OrderValidationSpec.groovy",
        language="groovy",
        contents=(
            "given: '...'\nwhen: '...'\nthen: '...'\n"
            if with_contents
            else None
        ),
    )

def edge_test_trace_pm() -> TestTracePM:
    return TestTracePM(
        core=edge_trace_core_long(),
        name="test_" + ("really_long_name_" * 6) + "end",
        filepath=("very/long/path/" * 8) + "OrderValidationSpec.groovy",
        language="groovy",
        contents=(
            "given: \"A very long test body that includes code\"\n"
            + ("// line\n" * 60)
            + "then: \"assert something\"\n"
        ),
    )

# -----------------------------------------------------------------------------
# LogTracePM fixtures
# -----------------------------------------------------------------------------

def minimal_log_trace_pm() -> LogTracePM:
    return LogTracePM(
        core=minimal_trace_core(),
        filename="",
        contents=None,
    )

def typical_log_trace_pm(*, with_contents: bool = False, invalid: bool = False) -> LogTracePM:
    core = typical_trace_core_invalid() if invalid else typical_trace_core_ok(
        art_id="33333333-3333-3333-3333-333333333333"
    )
    return LogTracePM(
        core=core,
        filename="prod_2026-01-09_FIX.log",
        contents=("8=FIX.4.4|9=...|35=D|..." if with_contents else None),
    )

def edge_log_trace_pm() -> LogTracePM:
    return LogTracePM(
        core=edge_trace_core_long(art_id="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"),
        filename="prod_" + ("2026-01-09_" * 5) + "huge_FIX.log",
        contents=("8=FIX.4.4|9=...|35=D|...\n" * 200),
    )

# -----------------------------------------------------------------------------
# Fixture entrypoints for PreviewSpec(make=...)
# -----------------------------------------------------------------------------

def make_test_trace_pm(ctx: RenderCtx, variant: str) -> TestTracePM:
    """
    Entry point used by PreviewSpec(make=...).

    Variants:
      - typical: valid + includes original contents
      - minimal: smallest possible (no code blocks / metadata)
      - edge: long values + invalid + lots of contents
    """
    v = (variant or "").strip().lower()
    if v == "typical":
        # typical should exercise code rendering; include original contents
        return typical_test_trace_pm(with_contents=True, invalid=False)
    if v == "minimal":
        return minimal_test_trace_pm()
    if v == "edge":
        return edge_test_trace_pm()
    raise ValueError(f"Unknown variant: {variant!r}")


def make_log_trace_pm(ctx: RenderCtx, variant: str) -> LogTracePM:
    """
    Entry point used by PreviewSpec(make=...).

    Variants:
      - typical: valid + includes log contents
      - minimal: smallest possible
      - edge: long values + invalid + lots of contents
    """
    v = (variant or "").strip().lower()
    if v == "typical":
        return typical_log_trace_pm(with_contents=True, invalid=False)
    if v == "minimal":
        return minimal_log_trace_pm()
    if v == "edge":
        return edge_log_trace_pm()
    raise ValueError(f"Unknown variant: {variant!r}")

def render_test(pm: TestTracePM, ctx: RenderCtx):
    return render_test_trace(pm, ctx=ctx)


def render_log(pm: LogTracePM, ctx: RenderCtx):
    return render_log_trace(pm, ctx=ctx)