#
#   Imandra Inc.
#
#   speclogician/cli/view_cmd.py
#

from __future__ import annotations

import json
from typing import Optional
import typer

from speclogician.presentation.ctx import RenderCtx
from speclogician.presentation.api import (
    present_state_instance,
    present_spec,
    present_domain_model,
    present_artifact_container,
    present_state_diff,
    present_instances_list,
    present_trace_reachability,
)

from .utils import get_state

app = typer.Typer(help="View components of the current state (rich or JSON).")


def _mk_ctx(
    *,
    compact: bool,
    show_stats_only: bool,
    show_code: bool,
    show_ids: bool,
    show_art_ids: bool,
    trace_id: str | None = None,
) -> RenderCtx:
    return RenderCtx(
        compact=compact,
        show_stats_only=show_stats_only,
        show_code=show_code,
        show_ids=show_ids,
        show_art_ids=show_art_ids,
        trace_id=trace_id,
    )

def _emit(obj: object, *, json_only: bool) -> None:
    if json_only:
        typer.echo(json.dumps(obj, indent=2, default=str))
    else:
        from speclogician.utils import console
        console.print(obj)


# ---------------------------
# view state (full)
# ---------------------------

@app.command("state")
def view_state(
    ctx: typer.Context,
    json_only: bool = typer.Option(False, "--json", help="Emit JSON only"),
    compact: bool = typer.Option(False, "--compact"),
    show_stats_only: bool = typer.Option(False, "--stats-only"),
    show_code: bool = typer.Option(True, "--code/--no-code"),
    show_ids: bool = typer.Option(False, "--ids"),
    show_art_ids: bool = typer.Option(False, "--art-ids"),
) -> None:
    st = get_state(ctx)
    si = st.curr_state()


    rctx = _mk_ctx(
        compact=compact,
        show_stats_only=show_stats_only,
        show_code=show_code,
        show_ids=show_ids,
        show_art_ids=show_art_ids,
    )

    out = present_state_instance(si, ctx=rctx, json_only=json_only)
    _emit(out, json_only=json_only)


# ---------------------------
# view trace reachability
# ---------------------------

@app.command("trace-reachability")
def view_trace_reachability_cmd(
    ctx: typer.Context,
    trace: Optional[str] = typer.Option(None, "--trace", help="Filter to a single trace id"),
    json_only: bool = typer.Option(False, "--json"),
    compact: bool = typer.Option(False, "--compact"),
    show_stats_only: bool = typer.Option(False, "--stats-only"),
    show_code: bool = typer.Option(True, "--code/--no-code"),
    show_ids: bool = typer.Option(False, "--ids"),
    show_art_ids: bool = typer.Option(False, "--art-ids"),
) -> None:
    st = get_state(ctx)
    si = st.curr_state()

    if si.trace_reachability is None:
        raise typer.BadParameter("No trace_reachability available on this instance.")

    rctx = _mk_ctx(
        compact=compact,
        show_stats_only=show_stats_only,
        show_code=show_code,
        show_ids=show_ids,
        show_art_ids=show_art_ids,
        trace_id=trace,  # NEW
    )

    # you’ll add this entrypoint in presentation/api.py
    out = present_trace_reachability(si.trace_reachability, art_cont=si.art_container, ctx=rctx, json_only=json_only)
    _emit(out, json_only=json_only)


# ---------------------------
# view spec
# ---------------------------

@app.command("spec")
def view_spec_cmd(
    ctx: typer.Context,
    json_only: bool = typer.Option(False, "--json"),
    compact: bool = typer.Option(False, "--compact"),
    show_stats_only: bool = typer.Option(False, "--stats-only"),
    show_code: bool = typer.Option(True, "--code/--no-code"),
    show_ids: bool = typer.Option(False, "--ids"),
    show_art_ids: bool = typer.Option(False, "--art-ids"),
) -> None:
    st = get_state(ctx)
    si = st.curr_state()

    rctx = _mk_ctx(compact=compact, show_stats_only=show_stats_only, show_code=show_code, show_ids=show_ids, show_art_ids=show_art_ids)
    out = present_spec(si.spec, ctx=rctx, json_only=json_only)
    _emit(out, json_only=json_only)


# ---------------------------
# view domain model
# ---------------------------

@app.command("domain")
def view_domain_cmd(
    ctx: typer.Context,
    json_only: bool = typer.Option(False, "--json"),
    compact: bool = typer.Option(False, "--compact"),
    show_stats_only: bool = typer.Option(False, "--stats-only"),
    show_code: bool = typer.Option(True, "--code/--no-code"),
    show_ids: bool = typer.Option(False, "--ids"),
    show_art_ids: bool = typer.Option(False, "--art-ids"),
) -> None:
    st = get_state(ctx)
    si = st.curr_state()

    rctx = _mk_ctx(compact=compact, show_stats_only=show_stats_only, show_code=show_code, show_ids=show_ids, show_art_ids=show_art_ids)
    out = present_domain_model(si.spec.domain_model, ctx=rctx, json_only=json_only)
    _emit(out, json_only=json_only)


# ---------------------------
# view artifacts container
# ---------------------------

@app.command("artifacts")
def view_artifacts_cmd(
    ctx: typer.Context,
    json_only: bool = typer.Option(False, "--json"),
    compact: bool = typer.Option(False, "--compact"),
    show_stats_only: bool = typer.Option(False, "--stats-only"),
    show_code: bool = typer.Option(True, "--code/--no-code"),
    show_ids: bool = typer.Option(False, "--ids"),
    show_art_ids: bool = typer.Option(False, "--art-ids"),
) -> None:
    st = get_state(ctx)
    si = st.curr_state()

    rctx = _mk_ctx(compact=compact, show_stats_only=show_stats_only, show_code=show_code, show_ids=show_ids, show_art_ids=show_art_ids)
    out = present_artifact_container(si.art_container, ctx=rctx, json_only=json_only)
    _emit(out, json_only=json_only)


# ---------------------------
# view diff
# ---------------------------

@app.command("diff")
def view_diff_cmd(
    ctx: typer.Context,
    json_only: bool = typer.Option(False, "--json"),
    compact: bool = typer.Option(False, "--compact"),
    show_stats_only: bool = typer.Option(False, "--stats-only"),
    show_code: bool = typer.Option(True, "--code/--no-code"),
    show_ids: bool = typer.Option(False, "--ids"),
    show_art_ids: bool = typer.Option(False, "--art-ids"),
) -> None:
    st = get_state(ctx)
    si = st.curr_state()

    if si.state_diff is None:
        raise typer.BadParameter("No state_diff available on this instance.")

    rctx = _mk_ctx(compact=compact, show_stats_only=show_stats_only, show_code=show_code, show_ids=show_ids, show_art_ids=show_art_ids)
    out = present_state_diff(si.state_diff, ctx=rctx, json_only=json_only)
    _emit(out, json_only=json_only)


# ---------------------------
# view list of instances
# ---------------------------

@app.command("instances")
def view_instances_cmd(
    ctx: typer.Context,
    json_only: bool = typer.Option(False, "--json"),
    compact: bool = typer.Option(False, "--compact"),
    show_stats_only: bool = typer.Option(False, "--stats-only"),
    show_code: bool = typer.Option(True, "--code/--no-code"),
    show_ids: bool = typer.Option(False, "--ids"),
    show_art_ids: bool = typer.Option(False, "--art-ids"),
) -> None:
    st = get_state(ctx)
    rctx = _mk_ctx(compact=compact, show_stats_only=show_stats_only, show_code=show_code, show_ids=show_ids, show_art_ids=show_art_ids)
    out = present_instances_list(st.instances, ctx=rctx, json_only=json_only)
    _emit(out, json_only=json_only)