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

if (($# != 0)); then
  echo "ERROR code=arguments_not_supported stage=bootstrap recovery=run-the-zero-argument-command" >&2
  exit 2
fi

manifest_url="__MANIFEST_URL__"
provider_url="__PROVIDER_URL__"
minimum_python="__MINIMUM_PYTHON_VERSION__"
private_runtime_rel="__PRIVATE_RUNTIME_DIRECTORY__"
restart_seconds="__SYSTEMD_RESTART_SECONDS__"
config_root="${HOME}/.unidesk"
config_path="${config_root}/provider.yaml"
provider_root="${config_root}/unideskcprovider"
provider_path="${provider_root}/unideskcprovider.py"
service_name="unideskcprovider.service"
service_path="/etc/systemd/system/${service_name}"
download_dir="${provider_root}/.install-${$}"

fail() {
  local code="$1" stage="$2" message="$3" recovery="$4"
  printf 'ERROR code=%s stage=%s message=%q recovery=%s\n' "$code" "$stage" "$message" "$recovery" >&2
  exit 1
}

cleanup() {
  rm -rf -- "$download_dir"
}
trap cleanup EXIT

[[ -f "$config_path" ]] || fail config_missing configuration "$config_path" write-provider-yaml-first
command -v curl >/dev/null 2>&1 || fail curl_missing prerequisites "curl is required" install-curl-and-retry
command -v systemctl >/dev/null 2>&1 || fail systemd_missing prerequisites "systemd is required" use-a-systemd-linux-host
command -v sudo >/dev/null 2>&1 || fail sudo_missing prerequisites "sudo is required" install-sudo-or-run-as-root

runtime_mode="$({
  awk '
    /^[[:space:]]*pythonRuntime[[:space:]]*:/ {
      line=$0
      sub(/^[^:]*:[[:space:]]*/, "", line)
      sub(/[[:space:]]*#.*/, "", line)
      gsub(/^[[:space:]"\047]+|[[:space:]"\047]+$/, "", line)
      print tolower(line)
      count++
    }
    END { if (count > 1) exit 12 }
  ' "$config_path"
} || true)"
runtime_mode="${runtime_mode:-auto}"
case "$runtime_mode" in
  auto|system|private) ;;
  *) fail python_runtime_invalid configuration "$runtime_mode" set-pythonRuntime-to-auto-system-or-private ;;
esac

python_ok() {
  "$1" -c 'import sys; raise SystemExit(0 if sys.version_info >= tuple(map(int, sys.argv[1].split("."))) else 1)' "$minimum_python" >/dev/null 2>&1
}

yaml_ok() {
  "$1" -c 'import yaml' >/dev/null 2>&1
}

system_python=""
for candidate in python3 python; do
  if command -v "$candidate" >/dev/null 2>&1 && python_ok "$candidate"; then
    system_python="$(command -v "$candidate")"
    break
  fi
done

private_root="${config_root}/${private_runtime_rel}"
private_python="${private_root}/bin/python"
python=""
runtime_kind=""

if [[ "$runtime_mode" != private && -n "$system_python" ]] && yaml_ok "$system_python"; then
  python="$system_python"
  runtime_kind=system
elif [[ "$runtime_mode" == system ]]; then
  fail system_python_unavailable runtime "Python ${minimum_python}+ with PyYAML is required" set-pythonRuntime-to-private-or-auto
else
  if [[ -x "$private_python" ]] && python_ok "$private_python" && yaml_ok "$private_python"; then
    printf '[runtime] reuse private Python %s\n' "$private_python"
  else
    [[ -n "$system_python" ]] || fail python_unavailable runtime "Python ${minimum_python}+ is required to create the private runtime" install-python3-and-venv
    printf '[runtime] create private Python environment %s\n' "$private_root"
    rm -rf -- "$private_root"
    "$system_python" -m venv "$private_root" || fail venv_create_failed runtime "$private_root" install-python3-venv-and-retry
    pip_source=""
    for source in __PIP_SOURCES_SH__; do
      started="$(date +%s%3N)"
      if curl --fail --silent --show-error --location --max-time 5 --head "$source" >/dev/null 2>&1; then
        elapsed="$(( $(date +%s%3N) - started ))"
        printf '[network] pipSource=%s latencyMs=%s\n' "$source" "$elapsed"
        pip_source="$source"
        break
      fi
      printf '[network] pipSource=%s unavailable\n' "$source"
    done
    [[ -n "$pip_source" ]] || fail pip_source_unreachable dependency "no PyPI source is reachable" check-network-and-retry
    "$private_python" -m pip install --disable-pip-version-check --index-url "$pip_source" PyYAML
    yaml_ok "$private_python" || fail pyyaml_unavailable dependency "$private_python" check-pip-output
  fi
  python="$private_python"
  runtime_kind=private
fi

sudo install -d -m 700 -o "$USER" -g "$(id -gn)" "$config_root" "$provider_root" "$config_root/logs"
mkdir -p "$download_dir"
manifest_download="${download_dir}/update.json"
provider_download="${download_dir}/unideskcprovider.py"

printf '[download] manifest source=%s\n' "$manifest_url"
curl --fail --location --show-error --progress-bar "$manifest_url" --output "$manifest_download"
printf '[download] provider source=%s\n' "$provider_url"
curl --fail --location --show-error --progress-bar "$provider_url" --output "$provider_download"

validation="$($python - "$manifest_download" "$provider_download" "$config_path" <<'PY'
import hashlib
import importlib.util
import json
from importlib.machinery import SourceFileLoader
from pathlib import Path
import sys

manifest_path, provider_path, config_path = map(Path, sys.argv[1:])
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
payload = provider_path.read_bytes()
digest = hashlib.sha256(payload).hexdigest()
if manifest.get("schemaVersion") != 1:
    raise SystemExit("manifest schema mismatch")
if len(payload) != manifest.get("bytes") or digest != manifest.get("sha256"):
    raise SystemExit("provider bytes or SHA-256 mismatch")
source = payload.decode("utf-8")
compile(source, str(provider_path), "exec")
if 'APP_NAME = "UniDesk Windows Provider"' not in source or "class ProviderManager:" not in source:
    raise SystemExit("provider identity marker missing")
loader = SourceFileLoader("unideskcprovider_install_probe", str(provider_path))
spec = importlib.util.spec_from_loader(loader.name, loader)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
loader.exec_module(module)
config = module.ProviderConfig(config_path)
print(json.dumps({
    "id": config.id,
    "autoStart": config.auto_start,
    "version": module.APP_VERSION,
    "bytes": len(payload),
    "sha256": digest,
}, separators=(",", ":")))
PY
)" || fail provider_validation_failed artifact "$validation" inspect-provider-yaml-and-download

if [[ -f "$provider_path" ]]; then
  cp -p -- "$provider_path" "${provider_path}.install.bak"
fi
install -m 700 "$provider_download" "${provider_path}.new"
mv -f -- "${provider_path}.new" "$provider_path"

auto_start="$($python -c 'import json,sys; print("true" if json.loads(sys.argv[1])["autoStart"] else "false")' "$validation")"
unit_temp="${download_dir}/${service_name}"
cat >"$unit_temp" <<EOF
[Unit]
Description=UniDesk Native Python Provider
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=${USER}
Environment=HOME=${HOME}
WorkingDirectory=${provider_root}
ExecStart=${python} ${provider_path}
Restart=always
RestartSec=${restart_seconds}
KillMode=mixed
TimeoutStopSec=20
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target
EOF
sudo install -m 644 "$unit_temp" "$service_path"
sudo systemctl daemon-reload
if [[ "$auto_start" == true ]]; then
  sudo systemctl enable "$service_name" >/dev/null
else
  sudo systemctl disable "$service_name" >/dev/null 2>&1 || true
fi
sudo systemctl restart "$service_name"

for _ in $(seq 1 30); do
  if sudo systemctl is-active --quiet "$service_name"; then
    provider_id="$($python -c 'import json,sys; print(json.loads(sys.argv[1])["id"])' "$validation")"
    version="$($python -c 'import json,sys; print(json.loads(sys.argv[1])["version"])' "$validation")"
    printf 'OK operation=unideskcprovider.install platform=linux providerId=%s version=%s runtime=%s python=%s service=%s autoStart=%s\n' \
      "$provider_id" "$version" "$runtime_kind" "$python" "$service_name" "$auto_start"
    exit 0
  fi
  sleep 1
done

sudo systemctl status "$service_name" --no-pager --lines=20 >&2 || true
fail provider_start_failed service "$service_name" inspect-systemctl-status-and-provider-log
