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

BASE_URL=""
BUILD_META=""
OUTPUT_FILE=""

usage() {
  cat <<'EOF'
Usage:
  scripts/verify_frontend_runtime.sh --base-url https://example.com --build-meta path [--output-file path]

Purpose:
  Verify that the deployed frontend runtime is serving the same asset set that
  was built during deploy, instead of relying on version bumps or manual string scans.
EOF
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --base-url)
      BASE_URL="${2:-}"
      shift 2
      ;;
    --build-meta)
      BUILD_META="${2:-}"
      shift 2
      ;;
    --output-file)
      OUTPUT_FILE="${2:-}"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "unknown argument: $1" >&2
      usage >&2
      exit 2
      ;;
  esac
done

[[ -n "${BASE_URL}" ]] || { echo "--base-url is required" >&2; exit 2; }
[[ -n "${BUILD_META}" ]] || { echo "--build-meta is required" >&2; exit 2; }
[[ -f "${BUILD_META}" ]] || { echo "build meta not found: ${BUILD_META}" >&2; exit 1; }

command -v curl >/dev/null 2>&1 || { echo "missing required command: curl" >&2; exit 1; }
command -v jq >/dev/null 2>&1 || { echo "missing required command: jq" >&2; exit 1; }
command -v python3 >/dev/null 2>&1 || { echo "missing required command: python3" >&2; exit 1; }

if [[ -z "${OUTPUT_FILE}" ]]; then
  OUTPUT_FILE="$(mktemp)"
fi

TMP_DIR="$(mktemp -d)"
trap 'rm -rf "${TMP_DIR}"' EXIT
INDEX_HTML="${TMP_DIR}/index.html"

base_url="${BASE_URL%/}"
index_code="$(
  curl -sS -L -o "${INDEX_HTML}" -w '%{http_code}' --max-time 30 \
    "${base_url}/" || true
)"

if [[ "${index_code}" != "200" ]]; then
  echo "frontend index fetch failed: status=${index_code:-curl_error}" >&2
  sed -n '1,120p' "${INDEX_HTML}" >&2 || true
  exit 1
fi

python3 - <<'PY' "${BUILD_META}" "${INDEX_HTML}" "${base_url}" "${TMP_DIR}" "${OUTPUT_FILE}"
import hashlib
import json
import os
import sys
import urllib.request
from html.parser import HTMLParser

build_meta_path, index_html_path, base_url, tmp_dir, output_path = sys.argv[1:]

class AssetParser(HTMLParser):
    def __init__(self):
        super().__init__()
        self.assets = []

    def handle_starttag(self, tag, attrs):
        attrs_map = dict(attrs)
        value = attrs_map.get("src") or attrs_map.get("href")
        if not value or not value.startswith("/assets/"):
            return
        self.assets.append(value.lstrip("/"))

with open(build_meta_path, "r", encoding="utf-8") as fh:
    build_meta = json.load(fh)

with open(index_html_path, "r", encoding="utf-8") as fh:
    runtime_index_html = fh.read()

index_parser = AssetParser()
index_parser.feed(runtime_index_html)
runtime_assets = index_parser.assets
runtime_basenames = {os.path.basename(path) for path in runtime_assets}

asset_results = []
all_ok = True
for asset in build_meta.get("assets", []):
    basename = asset["basename"]
    runtime_present = basename in runtime_basenames
    sha_ok = False
    if runtime_present:
        rel_path = next(path for path in runtime_assets if os.path.basename(path) == basename)
        fetched_path = os.path.join(tmp_dir, basename)
        with urllib.request.urlopen(f"{base_url}/{rel_path}") as resp, open(fetched_path, "wb") as out:
            out.write(resp.read())
        digest = hashlib.sha256()
        with open(fetched_path, "rb") as fh:
            while True:
                chunk = fh.read(65536)
                if not chunk:
                    break
                digest.update(chunk)
        sha_ok = digest.hexdigest() == asset["sha256"]
    asset_ok = runtime_present and sha_ok
    all_ok = all_ok and asset_ok
    asset_results.append({
        "path": asset["path"],
        "basename": basename,
        "expected_sha256": asset["sha256"],
        "runtime_present": runtime_present,
        "sha256_match": sha_ok,
    })

payload = {
    "base_url": base_url,
    "index_status": "passed",
    "runtime_asset_count": len(runtime_assets),
    "expected_asset_count": len(build_meta.get("assets", [])),
    "runtime_assets": runtime_assets,
    "assets": asset_results,
    "status": "passed" if all_ok else "failed",
}

with open(output_path, "w", encoding="utf-8") as fh:
    json.dump(payload, fh, indent=2)
    fh.write("\n")

if not all_ok:
    raise SystemExit(1)
PY

cat "${OUTPUT_FILE}"
