#!/usr/bin/env python3
"""Validate Agrarian Unreal stat and Insights profiling markers."""

from pathlib import Path
import sys

REPO_ROOT = Path(__file__).resolve().parents[1]

STATS = [
    "STAT_AgrarianGameStateTick",
    "STAT_AgrarianSurvivalTick",
    "STAT_AgrarianSkyLightingRefresh",
    "STAT_AgrarianWeatherAudioRefresh",
    "STAT_AgrarianFoliageInstanceMutation",
    "STAT_AgrarianWeatherProviderRequest",
    "STAT_AgrarianWeatherProviderParse",
]

SOURCE_MARKERS = {
    "Source/AgrarianGame/AgrarianGameState.cpp": [
        "TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianGameStateTick)",
        "SCOPE_CYCLE_COUNTER(STAT_AgrarianGameStateTick)",
    ],
    "Source/AgrarianGame/AgrarianSurvivalComponent.cpp": [
        "TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianSurvivalTick)",
        "SCOPE_CYCLE_COUNTER(STAT_AgrarianSurvivalTick)",
    ],
    "Source/AgrarianGame/AgrarianSkyLightingController.cpp": [
        "TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianSkyLightingRefresh)",
        "SCOPE_CYCLE_COUNTER(STAT_AgrarianSkyLightingRefresh)",
    ],
    "Source/AgrarianGame/AgrarianWeatherAudioController.cpp": [
        "TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianWeatherAudioRefresh)",
        "SCOPE_CYCLE_COUNTER(STAT_AgrarianWeatherAudioRefresh)",
    ],
    "Source/AgrarianGame/AgrarianFoliagePatch.cpp": [
        "TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianFoliageClear)",
        "TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianFoliageAddTreeInstance)",
        "TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianFoliageAddShrubInstance)",
        "TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianFoliageAddGrassInstance)",
        "SCOPE_CYCLE_COUNTER(STAT_AgrarianFoliageInstanceMutation)",
    ],
    "Source/AgrarianGame/AgrarianWeatherProviderSubsystem.cpp": [
        "TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianWeatherProviderRequest)",
        "TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianWeatherProviderFallback)",
        "TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianWeatherProviderParseOpenMeteo)",
        "TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianWeatherProviderParseNoaaNws)",
        "SCOPE_CYCLE_COUNTER(STAT_AgrarianWeatherProviderRequest)",
        "SCOPE_CYCLE_COUNTER(STAT_AgrarianWeatherProviderParse)",
    ],
}


def read_text(relative_path: str) -> str:
    path = REPO_ROOT / relative_path
    if not path.exists():
        raise AssertionError(f"Missing required file: {relative_path}")
    return path.read_text(encoding="utf-8")


def require(needle: str, haystack: str, context: str) -> None:
    if needle not in haystack:
        raise AssertionError(f"Missing {needle!r} in {context}")


def main() -> int:
    errors: list[str] = []

    try:
        header = read_text("Source/AgrarianGame/AgrarianPerformanceStats.h")
        source = read_text("Source/AgrarianGame/AgrarianPerformanceStats.cpp")
        require("DECLARE_STATS_GROUP(TEXT(\"Agrarian\"), STATGROUP_Agrarian", header, "AgrarianPerformanceStats.h")
        for stat in STATS:
            require(f"DECLARE_CYCLE_STAT_EXTERN(", header, "AgrarianPerformanceStats.h")
            require(stat, header, "AgrarianPerformanceStats.h")
            require(f"DEFINE_STAT({stat});", source, "AgrarianPerformanceStats.cpp")
    except AssertionError as exc:
        errors.append(str(exc))

    for relative_path, markers in SOURCE_MARKERS.items():
        try:
            contents = read_text(relative_path)
            require("#include \"AgrarianPerformanceStats.h\"", contents, relative_path)
            require("#include \"ProfilingDebugging/CpuProfilerTrace.h\"", contents, relative_path)
            for marker in markers:
                require(marker, contents, relative_path)
        except AssertionError as exc:
            errors.append(str(exc))

    try:
        roadmap = read_text("AGRARIAN_DEVELOPMENT_ROADMAP.md")
        require("[x] Add performance profiling markers.", roadmap, "AGRARIAN_DEVELOPMENT_ROADMAP.md")
        docs = read_text("Docs/TechnicalDesignDocument.md")
        require("stat Agrarian", docs, "Docs/TechnicalDesignDocument.md")
        require("Unreal Insights", docs, "Docs/TechnicalDesignDocument.md")
    except AssertionError as exc:
        errors.append(str(exc))

    if errors:
        for error in errors:
            print(f"ERROR: {error}", file=sys.stderr)
        return 1

    print("Performance profiling markers are wired.")
    return 0


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