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

REPORT_FILE="/tmp/ods-preflight-report.json"
TIER="${TIER:-1}"
RAM_GB="${RAM_GB:-0}"
DISK_GB="${DISK_GB:-0}"
GPU_BACKEND="${GPU_BACKEND:-nvidia}"
GPU_VRAM_MB="${GPU_VRAM_MB:-0}"
GPU_NAME="${GPU_NAME:-Unknown}"
PLATFORM_ID="${PLATFORM_ID:-linux}"
COMPOSE_OVERLAYS="${COMPOSE_OVERLAYS:-}"
SCRIPT_DIR="${SCRIPT_DIR:-$(pwd)}"
STRICT="false"
ENV_MODE="false"

while [[ $# -gt 0 ]]; do
    case "$1" in
        --report)
            REPORT_FILE="${2:-$REPORT_FILE}"
            shift 2
            ;;
        --tier)
            TIER="${2:-$TIER}"
            shift 2
            ;;
        --ram-gb)
            RAM_GB="${2:-$RAM_GB}"
            shift 2
            ;;
        --disk-gb)
            DISK_GB="${2:-$DISK_GB}"
            shift 2
            ;;
        --gpu-backend)
            GPU_BACKEND="${2:-$GPU_BACKEND}"
            shift 2
            ;;
        --gpu-vram-mb)
            GPU_VRAM_MB="${2:-$GPU_VRAM_MB}"
            shift 2
            ;;
        --gpu-name)
            GPU_NAME="${2:-$GPU_NAME}"
            shift 2
            ;;
        --platform-id)
            PLATFORM_ID="${2:-$PLATFORM_ID}"
            shift 2
            ;;
        --compose-overlays)
            COMPOSE_OVERLAYS="${2:-$COMPOSE_OVERLAYS}"
            shift 2
            ;;
        --script-dir)
            SCRIPT_DIR="${2:-$SCRIPT_DIR}"
            shift 2
            ;;
        --strict)
            STRICT="true"
            shift
            ;;
        --env)
            ENV_MODE="true"
            shift
            ;;
        *)
            echo "Unknown argument: $1" >&2
            exit 1
            ;;
    esac
done

ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
PYTHON_CMD="python3"
if [[ -f "$ROOT_DIR/lib/python-cmd.sh" ]]; then
    . "$ROOT_DIR/lib/python-cmd.sh"
    PYTHON_CMD="$(ods_detect_python_cmd)"
elif command -v python >/dev/null 2>&1; then
    PYTHON_CMD="python"
fi

"$PYTHON_CMD" - "$REPORT_FILE" "$TIER" "$RAM_GB" "$DISK_GB" "$GPU_BACKEND" "$GPU_VRAM_MB" "$GPU_NAME" "$PLATFORM_ID" "$COMPOSE_OVERLAYS" "$SCRIPT_DIR" "$ENV_MODE" "$STRICT" <<'PY'
import json
import pathlib
import sys
from datetime import datetime, timezone

(
    report_file,
    tier,
    ram_gb,
    disk_gb,
    gpu_backend,
    gpu_vram_mb,
    gpu_name,
    platform_id,
    compose_overlays,
    script_dir,
    env_mode,
    strict_mode,
) = sys.argv[1:]

env_mode = env_mode == "true"
strict_mode = strict_mode == "true"

try:
    ram_gb = int(float(ram_gb))
except Exception:
    ram_gb = 0
try:
    disk_gb = int(float(disk_gb))
except Exception:
    disk_gb = 0
try:
    gpu_vram_mb = int(float(gpu_vram_mb))
except Exception:
    gpu_vram_mb = 0

tier_key = str(tier).upper()
tier_rank_map = {
    "0": 0,
    "CLOUD": 0,
    "1": 1,
    "2": 2,
    "3": 3,
    "4": 4,
    "T0": 0,
    "T1": 1,
    "T2": 2,
    "T3": 3,
    "T4": 4,
    "SH_COMPACT": 3,
    "SH_LARGE": 4,
}
tier_rank = tier_rank_map.get(tier_key, 1)

min_ram_map = {
    "0": 4,
    "CLOUD": 4,
    "T0": 4,
    "1": 16,
    "2": 32,
    "3": 48,
    "4": 64,
    "SH_COMPACT": 64,
    "SH_LARGE": 96,
}
min_disk_map = {
    "0": 15,
    # Cloud mode skips local GGUF downloads and local llama-server model
    # storage. It still needs room for core Docker images, configs, logs, and
    # optional services, but it should not inherit the 50GB local-model default.
    "CLOUD": 25,
    "T0": 15,
    "1": 30,
    "2": 50,
    "3": 80,
    "4": 150,
    "SH_COMPACT": 80,
    "SH_LARGE": 120,
}
min_ram = min_ram_map.get(tier_key, 16)
min_disk = min_disk_map.get(tier_key, 50)

checks = []

def add_check(check_id, status, message, action):
    checks.append(
        {
            "id": check_id,
            "status": status,
            "message": message,
            "action": action,
        }
    )

# Platform support check
if platform_id in {"linux", "wsl"}:
    add_check(
        "platform-support",
        "pass",
        f"Platform '{platform_id}' is currently supported by install-core.sh.",
        "",
    )
elif platform_id in {"macos", "windows"}:
    add_check(
        "platform-support",
        "warn",
        f"Platform '{platform_id}' is supported via installer MVP path (not full parity yet).",
        "Continue with platform installer and follow generated doctor report recommendations.",
    )
else:
    add_check(
        "platform-support",
        "blocker",
        f"Platform '{platform_id}' is not yet supported by install-core.sh.",
        "Use Linux/WSL path for now or run platform-specific installer once implemented.",
    )

# Compose overlay existence check
overlays = [o.strip() for o in compose_overlays.split(",") if o.strip()]
if overlays:
    missing = [o for o in overlays if not (pathlib.Path(script_dir) / o).exists()]
    if missing:
        add_check(
            "compose-overlays",
            "blocker",
            f"Compose overlays are missing: {', '.join(missing)}.",
            "Restore missing compose files or update capability profile overlay mapping.",
        )
    else:
        add_check(
            "compose-overlays",
            "pass",
            f"Compose overlays resolved: {', '.join(overlays)}.",
            "",
        )
else:
    add_check(
        "compose-overlays",
        "warn",
        "No compose overlays supplied from capability profile.",
        "Ensure CAP_COMPOSE_OVERLAYS is populated; installer will use legacy fallback.",
    )

# RAM and disk checks
if ram_gb >= min_ram:
    add_check(
        "memory",
        "pass",
        f"RAM {ram_gb}GB meets tier {tier_key} recommendation ({min_ram}GB).",
        "",
    )
else:
    add_check(
        "memory",
        "warn",
        f"RAM {ram_gb}GB is below tier {tier_key} recommendation ({min_ram}GB).",
        f"Use a lower tier or increase memory to at least {min_ram}GB.",
    )

if disk_gb >= min_disk:
    add_check(
        "disk",
        "pass",
        f"Disk {disk_gb}GB meets tier {tier_key} recommendation ({min_disk}GB).",
        "",
    )
else:
    add_check(
        "disk",
        "blocker",
        f"Disk {disk_gb}GB is below required minimum for tier {tier_key} ({min_disk}GB).",
        f"Free at least {min_disk - disk_gb}GB or choose a smaller tier.",
    )

# GPU checks
gpu_backend = (gpu_backend or "").lower()
if gpu_backend == "amd":
    add_check(
        "gpu-backend",
        "pass",
        f"AMD backend selected ({gpu_name}).",
        "",
    )
elif gpu_backend == "nvidia":
    if gpu_name.strip().lower() in {"none", ""} or gpu_vram_mb <= 0:
        add_check(
            "gpu-vram",
            "warn",
            "NVIDIA backend selected but no NVIDIA GPU VRAM was detected.",
            "Install/verify NVIDIA drivers or switch to a supported AMD path.",
        )
    elif tier_rank >= 2 and gpu_vram_mb < 10000:
        add_check(
            "gpu-vram",
            "warn",
            f"NVIDIA VRAM {gpu_vram_mb}MB is below recommended floor for tier {tier_key}.",
            "Use tier 1 or a GPU with at least 12GB VRAM for better performance.",
        )
    else:
        add_check(
            "gpu-vram",
            "pass",
            f"NVIDIA backend selected ({gpu_name}, {gpu_vram_mb}MB VRAM).",
            "",
        )
elif gpu_backend == "apple":
    add_check(
        "gpu-backend",
        "warn",
        "Apple backend selected (experimental path).",
        "Use macOS installer preflight + doctor and run reduced profile set until Tier A parity is complete.",
    )
elif gpu_backend == "cpu":
    if platform_id in {"windows", "macos"}:
        add_check(
            "gpu-backend",
            "warn",
            "CPU fallback selected on non-Linux platform.",
            "Use reduced model/profile defaults; expect slower inference.",
        )
    else:
        add_check(
            "gpu-backend",
            "warn",
            "CPU fallback selected.",
            "Install/verify GPU drivers for best performance or continue with small models.",
        )
else:
    add_check(
        "gpu-backend",
        "warn",
        f"Unknown backend '{gpu_backend}'.",
        "Verify capability profile and hardware detection output.",
    )

blockers = [c for c in checks if c["status"] == "blocker"]
warnings = [c for c in checks if c["status"] == "warn"]

report = {
    "version": "1",
    "generated_at": datetime.now(timezone.utc).isoformat(),
    "inputs": {
        "tier": tier_key,
        "ram_gb": ram_gb,
        "disk_gb": disk_gb,
        "gpu_backend": gpu_backend,
        "gpu_vram_mb": gpu_vram_mb,
        "gpu_name": gpu_name,
        "platform_id": platform_id,
        "compose_overlays": overlays,
        "script_dir": script_dir,
    },
    "summary": {
        "checks": len(checks),
        "blockers": len(blockers),
        "warnings": len(warnings),
        "can_proceed": len(blockers) == 0,
    },
    "checks": checks,
}

report_path = pathlib.Path(report_file)
report_path.parent.mkdir(parents=True, exist_ok=True)
report_path.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8")

if env_mode:
    def out(key, value):
        safe = str(value).replace("\\", "\\\\").replace('"', '\\"')
        print(f'{key}="{safe}"')

    out("PREFLIGHT_REPORT_FILE", str(report_path))
    out("PREFLIGHT_CHECK_COUNT", report["summary"]["checks"])
    out("PREFLIGHT_BLOCKERS", report["summary"]["blockers"])
    out("PREFLIGHT_WARNINGS", report["summary"]["warnings"])
    out("PREFLIGHT_CAN_PROCEED", str(report["summary"]["can_proceed"]).lower())

if strict_mode and blockers:
    raise SystemExit(1)
PY
