#
#   Imandra Inc.
#
#   codelogician/commands/server/cmd_metamodel.py


from __future__ import annotations

import json
from typing import Any

import httpx
import typer

app = typer.Typer(
    name='metamodel',
    help='CLI for CodeLogician metamodel server endpoints.',
)
cache_app = typer.Typer(name='cache', help='Metamodel cache endpoints.')
app.add_typer(cache_app)


# -------------------------
# Helpers
# -------------------------


def _print_json(data: Any) -> None:
    typer.echo(json.dumps(data, indent=2, ensure_ascii=False))


def _handle_http_error(resp: httpx.Response) -> None:
    try:
        payload = resp.json()
    except Exception:
        payload = None

    if isinstance(payload, dict) and 'detail' in payload:
        raise typer.BadParameter(f'HTTP {resp.status_code}: {payload["detail"]}')
    raise typer.BadParameter(f'HTTP {resp.status_code}: {resp.text}')


def _get(
    base_url: str,
    path: str,
    *,
    params: dict[str, Any] | None = None,
    timeout: float,
) -> Any:
    url = base_url.rstrip('/') + path
    with httpx.Client(timeout=timeout) as client:
        resp = client.get(url, params=params)
    if resp.status_code >= 400:
        _handle_http_error(resp)
    return resp.json()


def _cfg(ctx: typer.Context) -> dict[str, Any]:
    """
    Read configuration from root Typer context.
    """
    root = ctx.find_root()
    assert isinstance(root.obj, dict)
    return root.obj


# -------------------------
# Commands
# -------------------------


@app.command('latest')
def metamodel_latest(ctx: typer.Context) -> None:
    """GET /metamodel — latest metamodel JSON."""
    cfg = _cfg(ctx)
    data = _get(cfg['base_url'], '/metamodel', timeout=cfg['timeout'])
    _print_json(data) if cfg['json_out'] else typer.echo(data)


@app.command('summary')
def metamodel_summary(ctx: typer.Context) -> None:
    """GET /metamodel/summary — summary JSON."""
    cfg = _cfg(ctx)
    data = _get(cfg['base_url'], '/metamodel/summary', timeout=cfg['timeout'])
    _print_json(data) if cfg['json_out'] else typer.echo(data)


@app.command('list')
def metamodel_list(
    ctx: typer.Context,
    listby: str = typer.Option(
        'alphabet',
        '--listby',
        help='Sort/group criteria: alphabet | frm_status | upstream | opaques | failed_vgs | ...',
    ),
) -> None:
    """GET /metamodel/list?listby=..."""
    cfg = _cfg(ctx)
    data = _get(
        cfg['base_url'],
        '/metamodel/list',
        params={'listby': listby},
        timeout=cfg['timeout'],
    )
    _print_json(data) if cfg['json_out'] else typer.echo(data)


@app.command('vgs')
def metamodel_vgs(ctx: typer.Context) -> None:
    """GET /metamodel/vgs — verification goals."""
    cfg = _cfg(ctx)
    data = _get(cfg['base_url'], '/metamodel/vgs', timeout=cfg['timeout'])
    _print_json(data) if cfg['json_out'] else typer.echo(data)


@app.command('decomps')
def metamodel_decomps(ctx: typer.Context) -> None:
    """GET /metamodel/decomps — decompositions."""
    cfg = _cfg(ctx)
    data = _get(cfg['base_url'], '/metamodel/decomps', timeout=cfg['timeout'])
    _print_json(data) if cfg['json_out'] else typer.echo(data)


@app.command('opaques')
def metamodel_opaques(ctx: typer.Context) -> None:
    """GET /metamodel/opaques — opaque functions."""
    cfg = _cfg(ctx)
    data = _get(cfg['base_url'], '/metamodel/opaques', timeout=cfg['timeout'])
    _print_json(data) if cfg['json_out'] else typer.echo(data)


# -------------------------
# Cache subcommands
# -------------------------


@cache_app.command('indices')
def cache_indices(ctx: typer.Context) -> None:
    """GET /metamodel/cache/indices"""
    cfg = _cfg(ctx)
    data = _get(cfg['base_url'], '/metamodel/cache/indices', timeout=cfg['timeout'])
    _print_json(data) if cfg['json_out'] else typer.echo(data)


@cache_app.command('get')
def cache_get(
    ctx: typer.Context,
    idx: int = typer.Argument(..., help='Cache index to fetch.'),
) -> None:
    """GET /metamodel/cache/by_index/{idx}"""
    cfg = _cfg(ctx)
    data = _get(
        cfg['base_url'],
        f'/metamodel/cache/by_index/{idx}',
        timeout=cfg['timeout'],
    )
    _print_json(data) if cfg['json_out'] else typer.echo(data)


if __name__ == '__main__':
    app()
