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

echo "== ci/bootstrap.sh =="

need_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "ERROR: missing cmd: $1"; exit 1; }; }
need_cmd find
need_cmd bash
need_cmd python3
need_cmd curl

# -----------------------
# 0) Provide default envs (avoid "unbound variable" under set -u)
# -----------------------
export CI_PROJECT_DIR="${CI_PROJECT_DIR:-$(pwd)}"
export HOME="${HOME:-/root}"

# GitHub Actions compatibility vars used by untestd scripts
export GITHUB_WORKSPACE="${GITHUB_WORKSPACE:-$CI_PROJECT_DIR}"
export GITHUB_REPOSITORY="${GITHUB_REPOSITORY:-${CI_PROJECT_PATH:-unknown/unknown}}"
export GITHUB_REF="${GITHUB_REF:-${CI_COMMIT_REF_NAME:-}}"
export GITHUB_SHA="${GITHUB_SHA:-${CI_COMMIT_SHA:-}}"
export GITHUB_EVENT_NAME="${GITHUB_EVENT_NAME:-gitlab}"
export GITHUB_EVENT_PATH="${GITHUB_EVENT_PATH:-/dev/null}"

# OS flags expected by install scripts
# Use true/false strings or 1/0 depends on scripts; here use 0/1.
: "${OS_IS_WINDOWS:=0}"
: "${OS_IS_MACOS:=0}"
: "${OS_IS_LINUX:=1}"
export OS_IS_WINDOWS OS_IS_MACOS OS_IS_LINUX

# -----------------------
# 1) create enhanced get.py in repo
# -----------------------
CORE_TOOLS_DIR="/root/Arduino/hardware/Kendryte/K230/tools"
CORE_GET="${CORE_TOOLS_DIR}/get.py"

mkdir -p "${CI_PROJECT_DIR}/tools"
ln -sf "${CI_PROJECT_DIR}/tools/untestd/get.py" "${CI_PROJECT_DIR}/tools/get.py" || true
ln -sf "${CI_PROJECT_DIR}/package" "${CI_PROJECT_DIR}/tools/package" || true

# -----------------------
# 1.5) template compat: ensure stable template exists
# -----------------------
if [ ! -f "${CI_PROJECT_DIR}/package/package_k230_index.template.json" ] && \
   [ -f "${CI_PROJECT_DIR}/package/package_k230_dev_index.template.json" ]; then
  echo "INFO: stable template missing; alias dev template -> package_k230_index.template.json"
  cp -f "${CI_PROJECT_DIR}/package/package_k230_dev_index.template.json" \
        "${CI_PROJECT_DIR}/package/package_k230_index.template.json"
fi

echo "INFO: package templates:"
ls -la "${CI_PROJECT_DIR}/package/"package_k230*_index*.json 2>/dev/null || true


cat > "${CI_PROJECT_DIR}/tools/get_enhanced.py" << 'EOF'
#!/usr/bin/env python3
import sys, os, tarfile, zipfile, shutil, re, subprocess

HOST_FORCE_CURL = "kendryte-download.canaan-creative.com"

script_dir = os.path.dirname(os.path.abspath(__file__))
original_get_path = os.path.join(script_dir, "untestd", "get.py")
if not os.path.exists(original_get_path):
    print("ERROR: Could not find original get.py at:", original_get_path)
    sys.exit(1)

untestd_dir = os.path.dirname(original_get_path)

def unpack_enhanced(filename, destination):
    print(f"Extracting {filename} ...")
    if filename.endswith("tar.gz"):
        tfile = tarfile.open(filename, "r:gz")
        tfile.extractall(destination)
        dirname = tfile.getnames()[0]
    elif filename.endswith("tar.bz2"):
        tfile = tarfile.open(filename, "r:bz2")
        tfile.extractall(destination)
        dirname = tfile.getnames()[0]
    elif filename.endswith("zip"):
        zfile = zipfile.ZipFile(filename)
        zfile.extractall(destination)
        dirname = zfile.namelist()[0]
    else:
        raise NotImplementedError(f"Unsupported archive type: {filename}")

    m = re.match(r"^([a-z][^\\-]*\\-*)+", dirname)
    if m:
        rename_to = m.group(0).strip("-")
        if rename_to and rename_to != dirname:
            print(f"Renaming {dirname} to {rename_to} ...")
            if os.path.isdir(rename_to):
                shutil.rmtree(rename_to)
            shutil.move(dirname, rename_to)

def curl_download(url: str, out_path: str):
    os.makedirs(os.path.dirname(out_path) or ".", exist_ok=True)
    print(f"Downloading via curl (resume+retry): {url}")
    cmd = [
        "curl","-fL","-C","-",
        "--retry","10","--retry-delay","3","--retry-connrefused",
        "--connect-timeout","20","--max-time","0",
        "--speed-time","30","--speed-limit","10240",
        "--http1.1",
        "-A","Mozilla/5.0",
        "-e","https://kendryte-download.canaan-creative.com/",
        "-o", out_path,
        url
    ]
    try:
        subprocess.check_call(cmd)
    except subprocess.CalledProcessError as e:
        try:
            if os.path.exists(out_path):
                os.remove(out_path)
        except Exception:
            pass
        raise e

sys.path.insert(0, untestd_dir)

try:
    import get as get_mod
    get_mod.unpack = unpack_enhanced

    if hasattr(get_mod, "download_file_with_progress"):
        _orig = get_mod.download_file_with_progress
        def patched(url, file_path, *args, **kwargs):
            if isinstance(url, str) and HOST_FORCE_CURL in url:
                curl_download(url, file_path)
                return
            return _orig(url, file_path, *args, **kwargs)
        get_mod.download_file_with_progress = patched

    try:
        import urllib.request
        _urlretrieve = urllib.request.urlretrieve
        def urlretrieve_patched(url, filename=None, reporthook=None, data=None):
            if isinstance(url, str) and HOST_FORCE_CURL in url and filename:
                curl_download(url, filename)
                return (filename, None)
            return _urlretrieve(url, filename, reporthook, data)
        urllib.request.urlretrieve = urlretrieve_patched
    except Exception:
        pass

    if hasattr(get_mod, "main"):
        get_mod.main()
    else:
        exec(open(original_get_path).read(), {"__name__": "__main__", "__file__": original_get_path})

except Exception as e:
    msg = repr(e)
    if HOST_FORCE_CURL in msg:
        print("ERROR: curl-based download failed for", HOST_FORCE_CURL, "-> aborting (no urllib fallback).")
        raise
    print("DEBUG: fallback exec due to:", msg)
    code = open(original_get_path, "r").read()
    patched = code.replace("def unpack(", "def unpack_original(")
    exec_globals = {
        "__name__": "__main__",
        "__file__": original_get_path,
        "unpack": unpack_enhanced,
        "tarfile": tarfile,
        "zipfile": zipfile,
        "shutil": shutil,
        "re": re,
        "os": os,
        "sys": sys,
        "subprocess": subprocess,
    }
    exec(patched, exec_globals)
EOF

chmod +x "${CI_PROJECT_DIR}/tools/get_enhanced.py"
ln -sf "${CI_PROJECT_DIR}/tools/get_enhanced.py" "${CI_PROJECT_DIR}/tools/get.py"
echo "INFO: repo get.py => $(readlink -f "${CI_PROJECT_DIR}/tools/get.py" || true)"

# -----------------------
# 2) functions: patch core-side get.py + toolchain setup
# -----------------------
patch_core_get_py() {
  if [ ! -e "$CORE_GET" ]; then
    echo "INFO: core get.py not present yet: $CORE_GET (skip for now)"
    return 0
  fi

  local SRC="${CI_PROJECT_DIR}/tools/get_enhanced.py"

  # Resolve real paths (handle symlinks); readlink -f exists on Ubuntu
  local SRC_REAL DST_REAL
  SRC_REAL="$(readlink -f "$SRC" 2>/dev/null || echo "$SRC")"
  DST_REAL="$(readlink -f "$CORE_GET" 2>/dev/null || echo "$CORE_GET")"

  if [ "$SRC_REAL" = "$DST_REAL" ]; then
    echo "INFO: core get.py already points to enhanced get.py (same file), skip copy."
    return 0
  fi

  # If core get.py is a symlink, replace it with a real file to avoid confusion
  if [ -L "$CORE_GET" ]; then
    echo "INFO: core get.py is a symlink, replacing with a real file"
    rm -f "$CORE_GET"
  fi

  cp -f "$SRC" "$CORE_GET"
  chmod +x "$CORE_GET"
  echo "INFO: patched core get.py: $CORE_GET"
}


setup_toolchain_path_and_links() {
  local PLATFORM_DIR="/root/Arduino/hardware/Kendryte/K230"
  local PLATFORM_LOCAL="${PLATFORM_DIR}/platform.local.txt"

  local REAL_GPP
  REAL_GPP="$(find /root/Arduino/tools -type f -path "*/bin/riscv64-unknown-linux-musl-g++" | head -n 1 || true)"
  if [ -z "$REAL_GPP" ]; then
    echo "ERROR: riscv64-unknown-linux-musl-g++ not found under /root/Arduino/tools"
    find /root/Arduino/tools -maxdepth 6 -type f -name "*riscv64*musl*g++*" -print || true
    exit 1
  fi

  local REAL_TOOLCHAIN_DIR
  REAL_TOOLCHAIN_DIR="$(dirname "$(dirname "$REAL_GPP")")"
  echo "INFO: Detected toolchain dir: $REAL_TOOLCHAIN_DIR"

  mkdir -p "$PLATFORM_DIR"
  cat > "$PLATFORM_LOCAL" <<EOF
tools.riscv-musl-gcc.path=${REAL_TOOLCHAIN_DIR}
EOF
  echo "INFO: wrote $PLATFORM_LOCAL"
  cat "$PLATFORM_LOCAL"

  ln -sf "$REAL_GPP" /bin/riscv64-unknown-linux-musl-g++ || true
  local REAL_GCC
  REAL_GCC="$(find /root/Arduino/tools -type f -path "*/bin/riscv64-unknown-linux-musl-gcc" | head -n 1 || true)"
  if [ -n "$REAL_GCC" ]; then
    ln -sf "$REAL_GCC" /bin/riscv64-unknown-linux-musl-gcc || true
  fi

  /bin/riscv64-unknown-linux-musl-g++ --version || true
}

export -f patch_core_get_py
export -f setup_toolchain_path_and_links

echo "OK: bootstrap prepared (env + repo get.py enhanced)."
