#!/usr/bin/env bash
set -Eeuo pipefail

phase="${1:-build}"
device="${2:-/dev/sr0}"
firmware_note="${3:-${FRIIDUMP_FIRMWARE_MODIFIED_NOTE:-}}"

source_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
build_root="$source_root/build-candidate21-linux"
expected_version="0.5.3.16-pf1-candidate21"
expected_commit="$(
    python3 - "$source_root/CANDIDATE.json" <<'PYEXPECTED'
import json
import re
import sys
from pathlib import Path

try:
    value = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))["candidate_implementation"]["commit"]
except (OSError, KeyError, TypeError, ValueError):
    value = ""

print(value.lower() if re.fullmatch(r"[0-9a-fA-F]{40}", value) else "")
PYEXPECTED
)"

if [[ ! "$expected_commit" =~ ^[0-9a-f]{40}$ ]]; then
    echo "Unable to resolve candidate21 implementation commit from CANDIDATE.json." >&2
    exit 1
fi

require_command() {
    local command_name="$1"
    local package_hint="$2"

    if ! command -v "$command_name" >/dev/null 2>&1; then
        echo "Missing required command: $command_name" >&2
        echo "Ubuntu package hint: sudo apt-get install -y $package_hint" >&2
        exit 1
    fi
}

require_build_dependencies() {
    require_command cmake cmake
    require_command cc build-essential
    require_command python3 python3

    if ! python3 -c 'import jsonschema' >/dev/null 2>&1; then
        echo "Missing Python module: jsonschema" >&2
        echo "Ubuntu package hint: sudo apt-get install -y python3-jsonschema" >&2
        exit 1
    fi
}

resolve_commit() {
    local git_root git_commit

    git_root="$(git -C "$source_root" rev-parse --show-toplevel 2>/dev/null || true)"
    if [[ -n "$git_root" && "$(cd -- "$git_root" && pwd -P)" == "$(cd -- "$source_root" && pwd -P)" ]]; then
        git_commit="$(git -C "$source_root" rev-parse HEAD 2>/dev/null || true)"
        if [[ ! "$git_commit" =~ ^[0-9a-fA-F]{40}$ ]]; then
            echo "Unable to resolve HEAD from the source-root Git repository." >&2
            exit 1
        fi
        if [[ "${git_commit,,}" != "$expected_commit" ]]; then
            echo "Candidate implementation commit mismatch." >&2
            echo "Expected: $expected_commit" >&2
            echo "Actual:   ${git_commit,,}" >&2
            exit 1
        fi
    fi

    printf '%s\n' "$expected_commit"
}

validate_report_directory() {
    local report_root="$1"

    python3 "$source_root/tests/validate_native_reports.py" \
        --fixtures "$report_root" \
        --schema "$source_root/tests/contracts/friidump-test-result.v1.schema.json" \
        --allow-arbitrary
}

normalize_future_source_timestamps() {
    python3 - "$source_root" <<'PYTIMESTAMPS'
import os
import sys
import time
from pathlib import Path

root = Path(sys.argv[1])
now = time.time()
normalized = 0

for path in root.rglob("*"):
    if not path.is_file():
        continue
    stat = path.stat()
    if stat.st_mtime > now + 1.0:
        os.utime(path, (stat.st_atime, now))
        normalized += 1

print(f"Future source timestamp preflight: PASS (normalized={normalized})")
PYTIMESTAMPS
}

build_phase() {
    local commit fixtures

    require_build_dependencies
    commit="$(resolve_commit)"
    normalize_future_source_timestamps

    rm -rf -- "$build_root"

    cmake -S "$source_root" -B "$build_root" \
        -DBUILD_STATIC_BINARY=ON \
        -DBUILD_NATIVE_REPORT_TESTS=ON \
        -DFRIIDUMP_BUILD_COMMIT="$commit"

    cmake --build "$build_root" --parallel

    "$build_root/src/friidump-xbox-portable-metadata-test"
    python3 "$source_root/tests/test_linux_xbox_portable_contract.py"
    python3 "$source_root/tests/test_seed_diagnostics_contract.py"
    "$build_root/src/friidump-linux-rawio-test"
    python3 "$source_root/tests/test_linux_rawio_contract.py"
    python3 "$source_root/tests/test_xbox_dvd_structure_contract.py" --source-root "$source_root"

    fixtures="$(mktemp -d)"
    trap 'rm -rf -- "$fixtures"' RETURN

    "$build_root/src/friidump-report-fixtures" "$fixtures"
    validate_report_directory "$fixtures"

    test -f "$build_root/src/redump_dat/Nintendo - GameCube.dat"
    test -f "$build_root/src/redump_dat/Nintendo - Wii.dat"
    test -f "$build_root/src/redump_dat/Microsoft - Xbox.dat"

    "$build_root/src/friidump-redump-dat-resolver-test" \
        - \
        "$build_root/src" \
        "Nintendo - GameCube.dat" \
        "$build_root/src/redump_dat/Nintendo - GameCube.dat" \
        1

    "$build_root/src/friidump-redump-dat-verify-test" \
        "$build_root/src/redump_dat/Nintendo - GameCube.dat"

    resolver_tmp="$(mktemp -d)"
    mkdir -p "$resolver_tmp/prefix/bin" \
             "$resolver_tmp/prefix/share/friidump/redump_dat" \
             "$resolver_tmp/env-dat" \
             "$resolver_tmp/explicit-dat"
    printf 'installed\n' > "$resolver_tmp/prefix/share/friidump/redump_dat/Test.dat"
    printf 'environment\n' > "$resolver_tmp/env-dat/Test.dat"
    printf 'explicit\n' > "$resolver_tmp/explicit-dat/Test.dat"

    "$build_root/src/friidump-redump-dat-resolver-test" \
        - \
        "$resolver_tmp/prefix/bin" \
        Test.dat \
        "$resolver_tmp/prefix/bin/../share/friidump/redump_dat/Test.dat" \
        1

    FRIIDUMP_REDUMP_DAT_DIR="$resolver_tmp/env-dat" \
        "$build_root/src/friidump-redump-dat-resolver-test" \
            - \
            "$resolver_tmp/prefix/bin" \
            Test.dat \
            "$resolver_tmp/env-dat/Test.dat" \
            1

    FRIIDUMP_REDUMP_DAT_DIR="$resolver_tmp/env-dat" \
        "$build_root/src/friidump-redump-dat-resolver-test" \
            "$resolver_tmp/explicit-dat" \
            "$resolver_tmp/prefix/bin" \
            Test.dat \
            "$resolver_tmp/explicit-dat/Test.dat" \
            1


    rm -rf -- "$resolver_tmp"

    set +e
    help_output="$("$build_root/src/friidump" --help 2>&1)"
    help_status=$?
    set -e

    if test "$help_status" -ne 1; then
        echo "Unexpected FriiDump --help exit status: $help_status (expected 1)." >&2
        exit 1
    fi

    grep -F "FriiDump $expected_version" <<<"$help_output"
    grep -F "FRIIDUMP_REDUMP_DAT_DIR" <<<"$help_output"
    grep -F "Linux raw-I/O requirement" <<<"$help_output"

    echo
    echo "WARNING: this Linux build does not yet carry CAP_SYS_RAWIO."
    echo "Vendor-command hardware operations will be refused until the exact"
    echo "validated executable receives cap_sys_rawio=ep. Do not run FriiDump"
    echo "itself as root. Rebuilding or replacing the executable clears the capability."
    echo "Install and verify with:"
    echo "  bash $source_root/validation/friidump-v0.5.3.16-pf1-candidate21-linux-live-validation.sh capability"
    echo
    echo "FRIIDUMP CANDIDATE21 LINUX BUILD: PASS"
}

capability_phase() {
    require_command getcap libcap2-bin
    require_command setcap libcap2-bin
    require_command sudo sudo
    ensure_build

    bash "$source_root/validation/friidump-linux-rawio-capability.sh"         install         "$build_root/src/friidump"

    bash "$source_root/validation/friidump-linux-rawio-capability.sh"         status         "$build_root/src/friidump"

    echo "FRIIDUMP CANDIDATE21 LINUX CAPABILITY: PASS"
}

ensure_build() {
    if ! test -x "$build_root/src/friidump"; then
        build_phase
    fi
}

device_model() {
    local block_name model_path

    block_name="$(basename -- "$device")"
    model_path="/sys/class/block/$block_name/device/model"

    if test -r "$model_path"; then
        tr -d '\000' < "$model_path" | xargs
    else
        printf '%s\n' ""
    fi
}

no_media_phase() {
    local output_root report_path output_path exit_code

    require_build_dependencies
    ensure_build

    output_root="$source_root/_native-report-linux-validation/$(date -u +%Y%m%dT%H%M%SZ)-no-media"
    mkdir -p "$output_root"

    echo "Remove media from $device, close the tray, wait for the drive to settle, then press Enter."
    read -r

    output_path="$output_root/no-media-placeholder.iso"
    report_path="$output_root/no-media-placeholder.iso.friidump.json"

    set +e
    (
        cd "$output_root"
        "$build_root/src/friidump" \
            -d "$device" \
            -i "no-media-placeholder.iso"
    )
    exit_code=$?
    set -e

    test -f "$report_path" || {
        echo "FAIL: expected native report was not created: $report_path" >&2
        exit 1
    }

    validate_report_directory "$output_root"

    python3 - "$report_path" "$device" "$expected_version" "$expected_commit" <<'PYREPORT'
import json
import sys
from pathlib import Path

report_path = Path(sys.argv[1])
expected_device = sys.argv[2]
expected_version = sys.argv[3]
expected_commit = sys.argv[4]

report = json.loads(report_path.read_text(encoding="utf-8"))

checks = {
    "schema": report.get("schema") == "friidump-test-result.v1",
    "version": report.get("generator", {}).get("version") == expected_version,
    "commit": report.get("generator", {}).get("build_commit") == expected_commit,
    "device": report.get("drive", {}).get("device_path") == expected_device,
    "stock_firmware": report.get("drive", {}).get("firmware_modified") is False,
    "no_modification_note": report.get("drive", {}).get("modification_note") is None,
    "test_type": report.get("run", {}).get("test_type") == "diagnostic_no_media",
    "run_result": report.get("run", {}).get("result") == "not_applicable",
    "unknown_platform": report.get("media", {}).get("platform") == "unknown",
    "seed_not_attempted": report.get("seed", {}).get("attempted") is False,
    "dump_not_attempted": report.get("dump", {}).get("attempted") is False,
    "no_output_path": report.get("dump", {}).get("output_path") is None,
    "no_hashes": all(value is None for value in report.get("hashes", {}).values()),
    "no_artifacts": report.get("artifacts") == [],
}

failed = [name for name, ok in checks.items() if not ok]
for name, ok in checks.items():
    print(f"{'PASS' if ok else 'FAIL'}: {name}")

if failed:
    raise SystemExit("No-media report contract failed: " + ", ".join(failed))
PYREPORT

    test ! -e "$output_path" || {
        echo "FAIL: no-media validation unexpectedly created an image: $output_path" >&2
        exit 1
    }

    echo "FriiDump exit code: $exit_code (nonzero is expected for no media)"
    echo "Report: $report_path"
    echo "FRIIDUMP CANDIDATE21 LINUX NO-MEDIA: PASS"
}

xbox_cancel_phase() {
    local model output_root

    require_build_dependencies
    ensure_build

    model="$(device_model)"
    if [[ "$model" != *GDR8050L* && "$model" != *GDR-8050L* ]]; then
        echo "Refusing Xbox cancellation validation on this device." >&2
        echo "Expected a GDR-8050L inquiry identity; found: ${model:-unknown}" >&2
        exit 1
    fi

    if [[ -z "$firmware_note" ]]; then
        echo "Xbox cancellation validation requires an explicit modified-firmware note." >&2
        echo "Pass it as argument 3 or set FRIIDUMP_FIRMWARE_MODIFIED_NOTE." >&2
        exit 1
    fi

    output_root="$source_root/_native-report-linux-validation/$(date -u +%Y%m%dT%H%M%SZ)-xbox-cancel"
    mkdir -p "$output_root"

    echo "Insert the Xbox disc in $device. Press Ctrl+C once after XISO progress begins."

    (
        cd "$output_root"
        "$build_root/src/friidump" \
            -d "$device" \
            -T 4 \
            -X "Red Faction II [TQ00501A].xiso" \
            --firmware-modified "$firmware_note"
    ) || true

    echo "Inspect the generated partial XISO, .friidump.json, and log under: $output_root"
}

identify_phase() {
    local block_name

    block_name="$(basename -- "$device")"

    echo "Device: $device"
    for field in vendor model rev; do
        printf '%-8s ' "$field:"
        cat "/sys/class/block/$block_name/device/$field" 2>/dev/null || echo "unavailable"
    done

    if command -v sg_inq >/dev/null 2>&1; then
        echo
        sg_inq "$device"
    else
        echo
        echo "Optional detailed inquiry: sudo apt-get install -y sg3-utils"
    fi

    echo
    stat -c 'Access: %A  Owner: %U  Group: %G' "$device"
    id

    if test -x "$build_root/src/friidump"; then
        echo
        bash "$source_root/validation/friidump-linux-rawio-capability.sh"             status             "$build_root/src/friidump" || true
    fi
}

case "$phase" in
    build) build_phase ;;
    capability) capability_phase ;;
    identify) identify_phase ;;
    no-media) no_media_phase ;;
    xbox-cancel) xbox_cancel_phase ;;
    *)
        echo "Usage: $0 {build|capability|identify|no-media|xbox-cancel} [/dev/sr0] [firmware-note]" >&2
        exit 2
        ;;
esac
