#
#   Imandra Inc.
#
#   speclogician/commands/cmd_ch_data.py
#

from __future__ import annotations

from typing import Optional

import typer

from .utils import get_state
from .runner import run_change_and_render

from ..state.change import (
    AddDocRef,
    EditDocRef,
    AddSrcCodeRef,
    EditSrcCodeRef,
    RemoveDataArtifact,
    LinkArtifactsComponents,
    RemoveArtComponentLink,
) 

app = typer.Typer(
    help="Data artifacts (documents + source code references) used to ground scenarios and traces."
)

@app.command("doc-add", help="Add a new documentation reference artifact.")
def add_doc(
    ctx: typer.Context,
    art_id: str = typer.Option(..., "--art-id", help="Artifact ID (uuid string)."),
    text: str = typer.Option(..., "--text", help="Document text or excerpt."),
    meta: Optional[str] = typer.Option(None, "--meta", help="Optional metadata (string or JSON)."),
    json_only: bool = typer.Option(False, "--json", help="Emit JSON only."),
) -> None:
    """
    Example:

      speclogician ch data doc-add --art-id D1 --text "Order book must reject negative qty" --json
    """
    state = get_state(ctx, json_mode=json_only)
    change = AddDocRef(art_id=art_id, text=text, meta=meta)
    run_change_and_render(state, change, json_only=json_only)
    state.save()


@app.command("doc-edit", help="Edit an existing documentation reference artifact.")
def edit_doc(
    ctx: typer.Context,
    art_id: str = typer.Argument(..., help="Artifact ID to edit."),
    text: Optional[str] = typer.Option(None, "--text", help="Update document text."),
    meta: Optional[str] = typer.Option(None, "--meta", help="Update metadata."),
    json_only: bool = typer.Option(False, "--json", help="Emit JSON only."),
) -> None:
    state = get_state(ctx, json_mode=json_only)
    change = EditDocRef(art_id=art_id, text=text, meta=meta)
    run_change_and_render(state, change, json_only=json_only)
    state.save()


@app.command("src-add", help="Add a new source code reference artifact.")
def add_src(
    ctx: typer.Context,
    art_id: str = typer.Option(..., "--art-id", help="Artifact ID (uuid string)."),
    src_code: str = typer.Option(..., "--src-code", help="Source code text."),
    language: Optional[str] = typer.Option(None, "--language", help="Language tag, e.g. 'py', 'java'."),
    file_path: Optional[str] = typer.Option(None, "--file-path", help="Original path (optional)."),
    iml_code: Optional[str] = typer.Option(None, "--iml-code", help="Optional associated IML excerpt."),
    meta: Optional[str] = typer.Option(None, "--meta", help="Optional metadata (string or JSON)."),
    json_only: bool = typer.Option(False, "--json", help="Emit JSON only."),
) -> None:
    state = get_state(ctx, json_mode=json_only)
    change = AddSrcCodeRef(
        art_id=art_id,
        src_code=src_code,
        language=language,
        file_path=file_path,
        iml_code=iml_code,
        meta=meta,
    )
    run_change_and_render(state, change, json_only=json_only)
    state.save()


@app.command("src-edit", help="Edit an existing source code reference artifact.")
def edit_src(
    ctx: typer.Context,
    art_id: str = typer.Argument(..., help="Artifact ID to edit."),
    src_code: Optional[str] = typer.Option(None, "--src-code", help="Update source code."),
    language: Optional[str] = typer.Option(None, "--language", help="Update language."),
    file_path: Optional[str] = typer.Option(None, "--file-path", help="Update file path."),
    iml_code: Optional[str] = typer.Option(None, "--iml-code", help="Update IML code."),
    meta: Optional[str] = typer.Option(None, "--meta", help="Update metadata."),
    json_only: bool = typer.Option(False, "--json", help="Emit JSON only."),
) -> None:
    state = get_state(ctx, json_mode=json_only)
    change = EditSrcCodeRef(
        art_id=art_id,
        src_code=src_code,
        language=language,
        file_path=file_path,
        iml_code=iml_code,
        meta=meta,
    )
    run_change_and_render(state, change, json_only=json_only)
    state.save()


@app.command("remove", help="Remove a data artifact (DocRef or SrcCodeRef) by art_id.")
def remove_data_art(
    ctx: typer.Context,
    art_id: str = typer.Argument(..., help="Artifact ID to remove."),
    json_only: bool = typer.Option(False, "--json", help="Emit JSON only."),
) -> None:
    state = get_state(ctx, json_mode=json_only)
    change = RemoveDataArtifact(art_id=art_id)
    run_change_and_render(state, change, json_only=json_only)
    state.save()


@app.command("link", help="Link an artifact to a model component (predicate or transition).")
def link_art(
    ctx: typer.Context,
    art_id: str = typer.Option(..., "--art-id", help="Artifact ID to link."),
    comp_name: str = typer.Option(..., "--comp-name", help="Component name (predicate or transition)."),
    json_only: bool = typer.Option(False, "--json", help="Emit JSON only."),
) -> None:
    """
    Examples:

      speclogician ch data link --art-id D1 --comp-name qty_ok

      speclogician ch data link --art-id S1 --comp-name on_new_order --json
    """
    state = get_state(ctx, json_mode=json_only)
    change = LinkArtifactsComponents(art_id=art_id, comp_name=comp_name)
    run_change_and_render(state, change, json_only=json_only)
    state.save()


@app.command("unlink", help="Remove a link between an artifact and a model component.")
def unlink_art(
    ctx: typer.Context,
    art_id: str = typer.Option(..., "--art-id", help="Artifact ID to unlink."),
    comp_name: str = typer.Option(..., "--comp-name", help="Component name to unlink from."),
    json_only: bool = typer.Option(False, "--json", help="Emit JSON only."),
) -> None:
    """
    Example:

      speclogician ch data unlink --art-id D1 --comp-name qty_ok --json
    """
    state = get_state(ctx, json_mode=json_only)
    change = RemoveArtComponentLink(art_id=art_id, comp_name=comp_name)
    run_change_and_render(state, change, json_only=json_only)
    state.save()
