#!/bin/bash
#
# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
#
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES.
# SPDX-License-Identifier: LicenseRef-NVIDIA-Proprietary
#
# data-direct wrapper — real hardware version
#
# Temporary DMS-owned bridge to the DOCA Data Direct CLI/sample while the
# native SDK backend is not wired into libdmspe. Blueprints and operators still
# use the typed DMS path:
#   dms-tool -t pci/<PF_BDF>,pf0vf0 /nvidia/data-direct enabled=true
#
# The underlying command can be overridden with DOCA_MGMT_DATA_DIRECT_BIN.

source "$(dirname "$0")/_lib.sh"
trace "$@"

OP="$1"; shift
TARGET="$1"; shift

# Accept VF/SF representor targets, with or without the optional controller
# prefix (c<H>) the DMS grammar emits for bonded/multi-controller devices, e.g.
# pci/<bdf>,pf0vf0 and pci/<bdf>,c0pf0vf0 (see target_parser.c cZpfX form).
case "$TARGET" in
    pci/*,pf*vf*|pci/*,pf*sf*|pci/*,c*pf*vf*|pci/*,c*pf*sf*) ;;
    *)
        echo "Error: data-direct requires a VF/SF representor target, got '$TARGET'" >&2
        exit 2
        ;;
esac

DD_BIN="${DOCA_MGMT_DATA_DIRECT_BIN:-doca_mgmt_data_direct}"

if ! command -v "$DD_BIN" >/dev/null 2>&1; then
    echo "Error: $DD_BIN not found; install the DOCA Data Direct tool or set DOCA_MGMT_DATA_DIRECT_BIN" >&2
    exit 127
fi

parse_bool() {
    case "$1" in
        true|1|True|TRUE|enabled|Enabled|ENABLED) echo "true" ;;
        false|0|False|FALSE|disabled|Disabled|DISABLED) echo "false" ;;
        *)
            echo "Error: invalid boolean '$1'" >&2
            return 1
            ;;
    esac
}

vf_pci_from_target() {
    case "$TARGET" in
        pci/*,pf*vf*|pci/*,c*pf*vf*)
            local parent="${TARGET%%,*}"
            parent="${parent#pci/}"
            local vf_idx="${TARGET##*vf}"
            vf_idx="${vf_idx%%[^0-9]*}"
            if [ -n "$parent" ] && [ -n "$vf_idx" ]; then
                basename "$(readlink "/sys/bus/pci/devices/${parent}/virtfn${vf_idx}" 2>/dev/null)" 2>/dev/null || true
            fi
            ;;
    esac
}

dd_get() {
    "$DD_BIN" get --rep "$TARGET" 2>&1 && return 0
    local vf_pci
    vf_pci="$(vf_pci_from_target)"
    if [ -n "$vf_pci" ]; then
        "$DD_BIN" get --vf-pci-addr "$vf_pci" 2>&1 && return 0
    fi
    return 1
}

dd_set() {
    local value="$1"
    "$DD_BIN" set --rep "$TARGET" --enabled "$value" 2>&1 && return 0
    local vf_pci
    vf_pci="$(vf_pci_from_target)"
    if [ -n "$vf_pci" ]; then
        "$DD_BIN" set --vf-pci-addr "$vf_pci" --enabled "$value" 2>&1 && return 0
    fi
    return 1
}

query_state() {
    dd_get
}

parse_enabled() {
    awk '
        BEGIN { found = 0 }
        /enabled/ || /Enabled/ {
            for (i = 1; i <= NF; i++) {
                if ($i ~ /true|false|True|False|0|1/) {
                    v = tolower($i)
                    if (v == "1") v = "true"
                    if (v == "0") v = "false"
                    print "enabled=" v
                    found = 1
                    exit
                }
                if ($i ~ /ENABLED|enabled/) {
                    print "enabled=true"
                    found = 1
                    exit
                }
                if ($i ~ /DISABLED|disabled/) {
                    print "enabled=false"
                    found = 1
                    exit
                }
            }
        }
        /Data direct:/ {
            if ($NF ~ /ENABLED|enabled/) {
                print "enabled=true"
                found = 1
                exit
            }
            if ($NF ~ /DISABLED|disabled/) {
                print "enabled=false"
                found = 1
                exit
            }
        }
        END { if (!found) exit 1 }
    '
}

case "$OP" in
    GET)
        for PARAM in "$@"; do
            case "$PARAM" in
                enabled)
                    if ! out=$(query_state 2>&1); then
                        echo "Error: $DD_BIN get --rep $TARGET failed: $out" >&2
                        exit 1
                    fi
                    if ! parsed=$(printf '%s\n' "$out" | parse_enabled); then
                        echo "Error: could not parse enabled state from $DD_BIN output: $out" >&2
                        exit 1
                    fi
                    echo "$parsed"
                    ;;
                is-supported)
                    # If the DOCA tool can query the representor successfully, the
                    # typed DMS capability is treated as supported for this target.
                    if ! out=$(query_state 2>&1); then
                        echo "is-supported=false"
                    else
                        echo "is-supported=true"
                    fi
                    ;;
                *)
                    echo "Error: unsupported data-direct GET param '$PARAM'" >&2
                    exit 2
                    ;;
            esac
        done
        ;;
    SET)
        rc=0
        for PAIR in "$@"; do
            PARAM="${PAIR%%=*}"
            VALUE="${PAIR#*=}"
            case "$PARAM" in
                enabled)
                    BOOL_VALUE=$(parse_bool "$VALUE") || exit 2
                    if ! err=$(dd_set "$BOOL_VALUE"); then
                        echo "Error: $DD_BIN set $TARGET enabled=$BOOL_VALUE failed: $err" >&2
                        rc=1
                        continue
                    fi
                    echo "enabled=${BOOL_VALUE}"
                    ;;
                *)
                    echo "Error: unsupported data-direct SET param '$PARAM'" >&2
                    rc=2
                    ;;
            esac
        done
        exit $rc
        ;;
    *)
        echo "Error: unsupported operation '$OP'" >&2
        exit 2
        ;;
esac
