#
#   Imandra Inc.
#
#   speclogician/shell/shell_view.py
#

from __future__ import annotations

import json
from cmd2 import Cmd, with_argparser
import argparse

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


def _mk_ctx(args) -> RenderCtx:
    return RenderCtx(
        compact=getattr(args, "compact", False),
        show_stats_only=getattr(args, "stats_only", False),
        show_code=not getattr(args, "no_code", False),
        show_ids=getattr(args, "ids", False),
        show_art_ids=getattr(args, "art_ids", False),
    )


class ViewShell(Cmd):
    prompt = "sl:view> "
    allow_cli_args = False

    def __init__(self, parent_shell, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.parent = parent_shell
        self.rich = console

    # ---- shared flags for all view commands ----
    def _add_common(self, p: argparse.ArgumentParser) -> None:
        p.add_argument("--idx", type=int, default=0)
        p.add_argument("--json", action="store_true")
        p.add_argument("--compact", action="store_true")
        p.add_argument("--stats-only", dest="stats_only", action="store_true")
        p.add_argument("--no-code", action="store_true")
        p.add_argument("--ids", action="store_true")
        p.add_argument("--art-ids", dest="art_ids", action="store_true")

    def _emit(self, x, *, json_only: bool) -> None:
        if json_only:
            self.rich.print_json(json.dumps(x, indent=2, default=str))
        else:
            self.rich.print(x)

    def do_back(self, _arg) -> bool:
        """Return to main shell."""
        return True

    do_exit = do_back
    do_quit = do_back

    # ----------------------
    # view state/spec/domain/artifacts/instances
    # ----------------------

    state_p = argparse.ArgumentParser()
    _ = state_p.add_argument
    # common
    # (cmd2 doesn't support easy composition; just call helper)
    # We'll patch it in __init__? easiest: do it here:
    # (but need self, so do it in method; use a helper below instead)

    @with_argparser(argparse.ArgumentParser())
    def do_state(self, args) -> None:
        """View full state instance."""
        if self.parent.state is None:
            self.perror("No state loaded.")
            return

        # build parser on the fly so we can reuse helper
        p = argparse.ArgumentParser()
        self._add_common(p)
        a = p.parse_args(args.argv)

        si = self.parent.state.instances[a.idx]
        rctx = _mk_ctx(a)
        out = present_state_instance(si, ctx=rctx, json_only=a.json)
        self._emit(out, json_only=a.json)

    @with_argparser(argparse.ArgumentParser())
    def do_spec(self, args) -> None:
        if self.parent.state is None:
            self.perror("No state loaded.")
            return
        p = argparse.ArgumentParser()
        self._add_common(p)
        a = p.parse_args(args.argv)

        si = self.parent.state.instances[a.idx]
        rctx = _mk_ctx(a)
        out = present_spec(si.spec, ctx=rctx, json_only=a.json)
        self._emit(out, json_only=a.json)

    @with_argparser(argparse.ArgumentParser())
    def do_domain(self, args) -> None:
        if self.parent.state is None:
            self.perror("No state loaded.")
            return
        p = argparse.ArgumentParser()
        self._add_common(p)
        a = p.parse_args(args.argv)

        si = self.parent.state.instances[a.idx]
        rctx = _mk_ctx(a)
        out = present_domain_model(si.spec.domain_model, ctx=rctx, json_only=a.json)
        self._emit(out, json_only=a.json)

    @with_argparser(argparse.ArgumentParser())
    def do_artifacts(self, args) -> None:
        if self.parent.state is None:
            self.perror("No state loaded.")
            return
        p = argparse.ArgumentParser()
        self._add_common(p)
        a = p.parse_args(args.argv)

        si = self.parent.state.instances[a.idx]
        rctx = _mk_ctx(a)
        out = present_artifact_container(si.art_container, ctx=rctx, json_only=a.json)
        self._emit(out, json_only=a.json)

    @with_argparser(argparse.ArgumentParser())
    def do_instances(self, args) -> None:
        if self.parent.state is None:
            self.perror("No state loaded.")
            return
        p = argparse.ArgumentParser()
        # instances view doesn’t need --idx but keep flags consistent:
        p.add_argument("--json", action="store_true")
        p.add_argument("--compact", action="store_true")
        p.add_argument("--stats-only", dest="stats_only", action="store_true")
        p.add_argument("--no-code", action="store_true")
        p.add_argument("--ids", action="store_true")
        p.add_argument("--art-ids", dest="art_ids", action="store_true")
        a = p.parse_args(args.argv)

        rctx = _mk_ctx(a)
        out = present_instances_list(self.parent.state.instances, ctx=rctx, json_only=a.json)
        self._emit(out, json_only=a.json)