#!/usr/bin/env python3
"""Verify package-smoke wrappers report the expected package readiness matrix."""

from __future__ import annotations

import json
import re
import sys
from pathlib import Path


EXPECTED_PACKAGE_KINDS = [
    "windows-appx",
    "android-standard-apk",
    "android-quest-apk",
    "android-focus-apk",
    "apple-bundle",
    "linux-app",
    "webgl",
]

EXPECTED_CMAKE_PACKAGE_TARGETS = [
    "panopainter_package_readiness",
    "panopainter_windows_app_package_smoke",
    "panopainter_windows_appx_package_readiness",
    "panopainter_apple_bundle_package_readiness",
    "panopainter_android_standard_native_package",
    "panopainter_android_standard_apk_package_readiness",
    "panopainter_android_quest_apk_package_readiness",
    "panopainter_android_focus_apk_package_readiness",
    "panopainter_android_vr_native_package_configure",
    "panopainter_android_native_package_smoke",
    "panopainter_linux_app_package_readiness",
    "panopainter_webgl_package_readiness",
    "panopainter_linux_webgl_package_readiness",
]


def repo_root() -> Path:
    return Path(__file__).resolve().parents[2]


def powershell_package_kinds(root: Path) -> list[str]:
    script = (root / "scripts" / "automation" / "package-smoke.ps1").read_text(encoding="utf-8")
    match = re.search(r"\[string\[\]\]\$PackageKinds\s*=\s*@\((.*?)\n\s*\)", script, re.S)
    if not match:
        raise RuntimeError("Could not find PackageKinds default in package-smoke.ps1")
    return sorted(re.findall(r'"([^"]+)"', match.group(1)))


def shell_package_kinds(root: Path) -> list[str]:
    script = (root / "scripts" / "automation" / "package-smoke.sh").read_text(encoding="utf-8")
    match = re.search(r'package_kinds="([^"]+)"', script)
    if match:
        return sorted(set(filter(None, (value.strip() for value in match.group(1).split(",")))))

    quoted_kinds = sorted(set(re.findall(r'"kind":"([^"]+)"', script)))
    escaped_kinds = sorted(set(re.findall(r'\\"kind\\":\\"([^\\"]+)\\"', script)))
    if quoted_kinds or escaped_kinds:
        return sorted(set(quoted_kinds).union(escaped_kinds))
    raise RuntimeError("Could not find package kinds defaults in package-smoke.sh")


def count_regex(root: Path, patterns: dict[str, str]) -> dict[str, int]:
    counts: dict[str, int] = {}
    for script_name, pattern in patterns.items():
        text = (root / "scripts" / "automation" / script_name).read_text(encoding="utf-8")
        counts[script_name] = len(re.findall(pattern, text))
    return counts


def main() -> int:
    root = repo_root()
    expected = sorted(EXPECTED_PACKAGE_KINDS)
    ps_kinds = powershell_package_kinds(root)
    sh_kinds = shell_package_kinds(root)
    script_texts = {
        "package-smoke.ps1": (root / "scripts" / "automation" / "package-smoke.ps1").read_text(encoding="utf-8"),
        "package-smoke.sh": (root / "scripts" / "automation" / "package-smoke.sh").read_text(encoding="utf-8"),
    }
    debt_counts = count_regex(root, {
        "package-smoke.ps1": r'debt\s*=\s*"DEBT-0011"',
        "package-smoke.sh": r'\\"debt\\":\\"DEBT-0011\\"',
    })
    status_tokens = ("blocked", "compile-only", "validated")
    status_modes = {
        name: [token for token in status_tokens if f'"{token}"' in text]
        for name, text in script_texts.items()
    }
    status_mode_present = {
        name: {
            token: f'"{token}"' in script_texts[name]
            for token in ("blocked", "compile-only")
        }
        for name in ("package-smoke.ps1", "package-smoke.sh")
    }
    readiness_alignment = count_regex(root, {
        "package-smoke.ps1": r'androidNativeValidation',
        "package-smoke.sh": r'androidNativeValidation',
    })
    readiness_mode_counts = {
        "package-smoke.ps1": (root / "scripts" / "automation" / "package-smoke.ps1").read_text(encoding="utf-8").count("ReadinessOnly"),
        "package-smoke.sh": (root / "scripts" / "automation" / "package-smoke.sh").read_text(encoding="utf-8").count("readiness_only"),
    }
    retained_android_native_counts = count_regex(root, {
        "package-smoke.ps1": r"retained-native-cmake-check",
        "package-smoke.sh": r"retained-native-cmake-check",
    })
    retained_platform_cmake_counts = count_regex(root, {
        "package-smoke.ps1": r"retained-(linux|webgl)-cmake",
        "package-smoke.sh": r"retained-(linux|webgl)-cmake",
    })
    cmake_package_module = (root / "cmake" / "PanoPainterPackageTargets.cmake").read_text(encoding="utf-8")
    root_cmake = (root / "CMakeLists.txt").read_text(encoding="utf-8")

    missing = {
        "package-smoke.ps1": [kind for kind in expected if kind not in ps_kinds],
        "package-smoke.sh": [kind for kind in expected if kind not in sh_kinds],
    }
    unexpected = {
        "package-smoke.ps1": [kind for kind in ps_kinds if kind not in expected],
        "package-smoke.sh": [kind for kind in sh_kinds if kind not in expected],
    }
    debt_thresholds = {
        "package-smoke.ps1": 1,
        "package-smoke.sh": len(expected),
    }
    debt_complete = {name: count >= debt_thresholds[name] for name, count in debt_counts.items()}
    status_gate_complete = {
        "package-smoke.ps1": status_mode_present["package-smoke.ps1"]["blocked"] and status_mode_present["package-smoke.ps1"]["compile-only"],
        "package-smoke.sh": status_mode_present["package-smoke.sh"]["blocked"] and status_mode_present["package-smoke.sh"]["compile-only"],
    }
    readiness_mode_present = {name: count > 0 for name, count in readiness_mode_counts.items()}
    retained_android_native_complete = {
        name: count >= 3 for name, count in retained_android_native_counts.items()
    }
    retained_platform_cmake_complete = {
        name: count >= 2 for name, count in retained_platform_cmake_counts.items()
    }
    cmake_package_targets_present = {
        target: target in cmake_package_module for target in EXPECTED_CMAKE_PACKAGE_TARGETS
    }
    cmake_package_module_included = "include(PanoPainterPackageTargets)" in root_cmake

    ok = (
        all(not values for values in missing.values())
        and all(not values for values in unexpected.values())
        and all(debt_complete.values())
        and all(status_gate_complete.values())
        and all(readiness_alignment.values())
        and all(readiness_mode_present.values())
        and all(retained_android_native_complete.values())
        and all(retained_platform_cmake_complete.values())
        and all(cmake_package_targets_present.values())
        and cmake_package_module_included
    )

    print(json.dumps({
        "ok": ok,
        "expectedPackageKinds": expected,
        "packageKinds": {
            "package-smoke.ps1": ps_kinds,
            "package-smoke.sh": sh_kinds,
        },
        "missing": missing,
        "unexpected": unexpected,
        "debtComplete": debt_complete,
        "statusModes": status_modes,
        "statusModePresent": status_mode_present,
        "readinessAlignment": readiness_alignment,
        "readinessModePresent": readiness_mode_present,
        "retainedAndroidNativeComplete": retained_android_native_complete,
        "retainedPlatformCmakeComplete": retained_platform_cmake_complete,
        "cmakePackageTargetsPresent": cmake_package_targets_present,
        "cmakePackageModuleIncluded": cmake_package_module_included,
    }, separators=(",", ":")))
    return 0 if ok else 1


if __name__ == "__main__":
    sys.exit(main())
