#!/bin/bash

# Artifact command handler — `libreportal artifact <sub>`
# ---------------------------------------------------------------------------
# Dispatched automatically by cli_initialize.sh (category -> cliHandleArtifactCommands).
#
# The unified distribution primitive. The READ side (`index`/`applied`) fetches +
# verifies the team-signed artifact index (hotfixes today; apps/themes/components
# later — all one envelope) and lists what's available/applied; it changes nothing,
# so — like `updater check` — it runs directly. The state-changing `apply`/`revert`
# verbs route through the TASK system (snapshot → bounded declarative ops →
# auto-rollback → History), never a mutating API. See docs/roadmap/updates-and-
# distribution.md and cli_artifact_apply.sh.

cliHandleArtifactCommands()
{
    local sub="$initial_command2"
    local id="$initial_command3"

    # Lazy-loader gap: ensure the read primitives + apply pipeline are defined.
    # These are new files; the array/manifest regen self-heals them on deploy,
    # but this covers the window before that. Source CHECKED — a missing/corrupt
    # file must surface a clear error, not degrade to a bare "command not found".
    if ! declare -F lpFetchIndex >/dev/null 2>&1; then
        local _f
        for _f in source/fetch.sh source/artifacts.sh; do
            if [[ ! -f "$install_scripts_dir/$_f" ]] || ! source "$install_scripts_dir/$_f"; then
                isError "artifact: failed to load the read pipeline ($_f) — try: libreportal regen"; return 1
            fi
        done
    fi
    if ! declare -F artifactApply >/dev/null 2>&1; then
        local _af="cli/commands/artifact/cli_artifact_apply.sh"
        if [[ ! -f "$install_scripts_dir/$_af" ]] || ! source "$install_scripts_dir/$_af"; then
            isError "artifact: failed to load the apply pipeline ($_af) — try: libreportal regen"; return 1
        fi
    fi

    case "$sub" in
        ""|"index"|"list")
            artifactListIndex
            ;;
        "applied")
            artifactListApplied
            ;;
        "apply")
            if [[ -z "$id" ]]; then isError "Usage: libreportal artifact apply <id>"; return 1; fi
            if [[ "$LIBREPORTAL_TASK_EXEC" == "1" ]]; then
                artifactApply "$id"
            else
                cliTaskRun "libreportal artifact apply $id" "artifact_apply" "$id" ""
            fi
            ;;
        "revert"|"rollback")
            if [[ -z "$id" ]]; then isError "Usage: libreportal artifact revert <id>"; return 1; fi
            if [[ "$LIBREPORTAL_TASK_EXEC" == "1" ]]; then
                artifactRevert "$id"
            else
                cliTaskRun "libreportal artifact revert $id" "artifact_revert" "$id" ""
            fi
            ;;
        "apply-auto")
            # Decide + enqueue (gated by CFG_HOTFIX_AUTO); each apply is its own task.
            artifactApplyAuto
            ;;
        *)
            cliShowArtifactHelp
            ;;
    esac
}

# List the applied hotfixes (read-only) from the per-id applied records.
artifactListApplied()
{
    isHeader "Applied hotfixes"
    local dir; dir="${containers_dir%/}/libreportal/frontend/data/updater/generated/applied"
    if ! compgen -G "$dir/*.json" >/dev/null 2>&1; then
        isSuccessful "0 hotfixes applied."
        return 0
    fi
    local n=0 f id title app
    for f in "$dir"/*.json; do
        n=$((n+1))
        if command -v jq >/dev/null 2>&1; then
            id="$(jq -r '.id' "$f" 2>/dev/null)"; title="$(jq -r '.title // ""' "$f" 2>/dev/null)"; app="$(jq -r '.app // ""' "$f" 2>/dev/null)"
            echo "  • $id${app:+ [$app]} — $title"
        else
            echo "  • $(basename "$f" .json)"
        fi
    done
    isSuccessful "$n hotfix(es) applied. Revert with: libreportal artifact revert <id>"
}

# Fetch + verify the signed index and print a human summary. Read-only.
artifactListIndex()
{
    isHeader "Artifact index ($(lpReleaseChannel))"

    local json
    if ! lpFetchIndexInto json; then
        isError "Could not fetch or verify the artifact index from $(lpArtifactIndexUrl)."
        isNotice "Nothing is published yet, or the channel is unreachable. (This is expected before the first index ships.)"
        return 1
    fi

    local serial generated_at
    serial="$(_lpJsonNum "$json" index_serial)"
    generated_at="$(lpIndexTop generated_at "$json")"
    # Report the ACTUAL signature state — never claim "verified" when the feed was
    # only accepted because signing isn't activated (dev/placeholder key).
    if [[ "$LP_INDEX_SIGSTATE" == "verified" ]]; then
        isNotice "Signed + verified.  serial=${serial:-?}  generated=${generated_at:-?}"
    else
        isNotice "UNSIGNED (signing not activated — dev/placeholder key).  serial=${serial:-?}  generated=${generated_at:-?}"
    fi

    local ids; ids="$(lpIndexArtifactIds "$json")"
    if [[ -z "$ids" ]]; then
        isSuccessful "0 artifacts available — the index is empty (nothing to apply)."
        return 0
    fi

    local n=0 id obj title type sev
    while IFS= read -r id; do
        [[ -z "$id" ]] && continue
        n=$((n + 1))
        obj="$(lpArtifactById "$json" "$id")"
        if [[ -n "$obj" ]]; then
            title="$(_lpJsonStr "$obj" title)"
            type="$(_lpJsonStr "$obj" type)"
            sev="$(_lpJsonStr "$obj" severity)"
            echo "  • [${type:-?}/${sev:-info}] $id — ${title:-}"
        else
            echo "  • $id"
        fi
    done <<< "$ids"

    isSuccessful "$n artifact(s) available."
}
