#!/usr/bin/env python3
"""Update upstream lock and regenerate SDK artifacts."""

from __future__ import annotations

import hashlib
import json
import re
import subprocess
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
OMNI = ROOT / "refs/libs/omni"
DOCS = ROOT / "refs/libs/sidero-docs"
LOCK = ROOT / "upstream.lock"
CLI_DOC = DOCS / "cli.md"
API_VERSION_FILE = OMNI / "internal/version/api.go"
RESOURCES_ROOT = OMNI / "client/pkg/omni/resources"


def git_output(repo: Path, *args: str) -> str:
    return subprocess.check_output(["git", "-C", str(repo), *args], text=True).strip()


def hash_files(paths: list[Path]) -> str:
    h = hashlib.sha256()
    for path in sorted(paths):
        h.update(path.read_bytes())
    return h.hexdigest()


def extract_api_version() -> int:
    text = API_VERSION_FILE.read_text(encoding="utf-8")
    match = re.search(r"const\s+API\s+uint32\s*=\s*(\d+)", text)
    if not match:
        raise RuntimeError("failed to parse backend API version")
    return int(match.group(1))


def latest_tag() -> str:
    return git_output(OMNI, "tag", "--sort=-version:refname").splitlines()[0]


def cli_manifest_hash() -> str:
    headings = []
    for line in CLI_DOC.read_text(encoding="utf-8").splitlines():
        if line.startswith("## omnictl"):
            headings.append(line.strip())
    digest = hashlib.sha256("\n".join(headings).encode("utf-8")).hexdigest()
    return digest


def proto_hash() -> str:
    protos = [
        OMNI / "client/api/omni/resources/resources.proto",
        OMNI / "client/api/omni/management/management.proto",
        OMNI / "client/api/omni/oidc/oidc.proto",
        OMNI / "frontend/src/api/omni/auth/auth.proto",
        OMNI / "client/api/omni/specs/omni.proto",
        OMNI / "client/api/omni/specs/infra.proto",
        OMNI / "client/api/omni/specs/auth.proto",
        OMNI / "client/api/omni/specs/virtual.proto",
        OMNI / "client/api/omni/specs/siderolink.proto",
        OMNI / "client/api/omni/specs/system.proto",
        OMNI / "client/api/omni/specs/ephemeral.proto",
        OMNI / "client/api/omni/specs/oidc.proto",
    ]
    return hash_files(protos)


def crd_catalog_source_hash() -> str:
    go_files = list(RESOURCES_ROOT.rglob("*.go"))
    return hash_files(go_files)


def run_script(script: str) -> None:
    subprocess.check_call(["python", str(ROOT / "scripts" / script)], cwd=ROOT)


def main() -> None:
    run_script("generate_methods.py")
    run_script("generate_models.py")
    run_script("generate_crd_catalog.py")

    lock_payload = {
        "omni_tag": latest_tag(),
        "omni_commit": git_output(OMNI, "rev-parse", "HEAD"),
        "backend_api_version": extract_api_version(),
        "sidero_docs_commit": git_output(DOCS, "rev-parse", "HEAD"),
        "proto_descriptor_hash": proto_hash(),
        "cli_manifest_hash": cli_manifest_hash(),
        "crd_catalog_source_hash": crd_catalog_source_hash(),
    }

    LOCK.write_text(json.dumps(lock_payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
    print(f"updated {LOCK}")


if __name__ == "__main__":
    main()
