#!/usr/bin/env python3
import argparse
import json
import shutil
import subprocess
import sys
from pathlib import Path

from script_common import find_csproj_by_keyword, find_node_app_root, resolve_repo_root


def run_step(label: str, cmd: list[str], cwd: Path, dry_run: bool) -> int:
    print(f"\n> {label}")
    print("$", " ".join(cmd))
    if dry_run:
        return 0
    proc = subprocess.run(cmd, cwd=str(cwd), check=False)
    return proc.returncode


def has_package_script(app_root: Path, script_name: str) -> bool:
    package_json = app_root / "package.json"
    if not package_json.exists():
        return False
    try:
        data = json.loads(package_json.read_text(encoding="utf-8"))
    except Exception:
        return False
    scripts = data.get("scripts")
    if not isinstance(scripts, dict):
        return False
    value = scripts.get(script_name)
    return isinstance(value, str) and value.strip() != ""


def main() -> int:
    parser = argparse.ArgumentParser(description="Publish bundled outputs using Python script entrypoints")
    parser.add_argument("--configuration", choices=["Release", "Debug"], default="Release")
    parser.add_argument("--runtime", default="win-x64")
    parser.add_argument("--skip-sidecar", action="store_true")
    parser.add_argument("--skip-web", action="store_true")
    parser.add_argument("--skip-webgateway", action="store_true")
    parser.add_argument("--skip-tauri", action="store_true")
    parser.add_argument("--dry-run", action="store_true")
    parser.add_argument("--repo-root", default=None)
    parser.add_argument("--sidecar-project", default=None)
    parser.add_argument("--gateway-project", default=None)
    parser.add_argument("--app-root", default=None)
    parser.add_argument("--output-dir", default="output")
    args = parser.parse_args()

    repo_root = resolve_repo_root(args.repo_root)
    output_root = (repo_root / args.output_dir).resolve()
    output_root.mkdir(parents=True, exist_ok=True)

    sidecar_project = (repo_root / args.sidecar_project).resolve() if args.sidecar_project else find_csproj_by_keyword(repo_root, ["sidecar"])
    gateway_project = (repo_root / args.gateway_project).resolve() if args.gateway_project else find_csproj_by_keyword(repo_root, ["webgateway", "gateway"])
    app_root = (repo_root / args.app_root).resolve() if args.app_root else find_node_app_root(repo_root, None)
    tauri_conf = None
    if app_root is not None:
        candidate_a = app_root / "src-tauri" / "tauri.conf.json"
        candidate_b = app_root / "tauri.conf.json"
        if candidate_a.exists():
            tauri_conf = candidate_a
        elif candidate_b.exists():
            tauri_conf = candidate_b

    py = sys.executable
    if not args.skip_sidecar:
        if sidecar_project is None:
            print("Skipping sidecar: no sidecar csproj detected.")
        else:
            cmd = [py, "scripts/publish-sidecar.py", "--configuration", args.configuration, "--runtime", args.runtime]
            cmd.extend(["--project", str(sidecar_project)])
            code = run_step("Publish sidecar", cmd, repo_root, args.dry_run)
            if code != 0:
                return code

    if not args.skip_web:
        if app_root is None:
            print("Skipping web: no app root with package.json detected.")
        elif not has_package_script(app_root, "build"):
            print("Skipping web: package.json has no 'build' script.")
        else:
            cmd = [py, "scripts/publish-app.py", "--target", "web", "--configuration", args.configuration, "--app-root", str(app_root)]
            code = run_step("Build web", cmd, repo_root, args.dry_run)
            if code != 0:
                return code

    if not args.skip_webgateway:
        if gateway_project is None:
            print("Skipping web gateway: no gateway csproj detected.")
        else:
            cmd = [py, "scripts/publish-webgateway.py", "--configuration", args.configuration, "--runtime", args.runtime, "--project", str(gateway_project)]
            code = run_step("Publish web gateway", cmd, repo_root, args.dry_run)
            if code != 0:
                return code

    if not args.skip_tauri:
        if app_root is None or tauri_conf is None:
            print("Skipping tauri: tauri app not detected.")
        elif not has_package_script(app_root, "tauri"):
            print("Skipping tauri: package.json has no 'tauri' script.")
        else:
            cmd = [py, "scripts/publish-app.py", "--target", "tauri", "--configuration", args.configuration, "--tauri-bundles", "none", "--app-root", str(app_root)]
            code = run_step("Build tauri", cmd, repo_root, args.dry_run)
            if code != 0:
                return code

            target_dir = app_root / "src-tauri" / "target" / ("debug" if args.configuration == "Debug" else "release")
            exes = sorted(target_dir.glob("*.exe"), key=lambda p: p.stat().st_mtime, reverse=True)
            if exes:
                staged = output_root / exes[0].name
                if args.dry_run:
                    print(f"Would copy: {exes[0]} -> {staged}")
                else:
                    shutil.copy2(exes[0], staged)
                    print(f"Staged desktop executable: {staged}")

    print("\nPublish output workflow complete.")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
