#!/usr/bin/env python
"""
Build system for tactical-shooter GDExtension simulation core.

Targets a shared library (.so/.dll/.dylib) loadable by Godot 4.

Dependencies:
  - godot-cpp submodule (git submodule update --init)
  - scons (pip install scons)
  - C++17 capable compiler (gcc >= 11, clang >= 14, MSVC 2022)

Usage:
  scons                    # debug build
  scons target=release     # release build (optimized, no debug symbols)
  scons target=template_release  # same as release
  scons target=template_debug    # debug build with optimization
  scons -j$(nproc)         # parallel build

Platform detection is automatic (linux, windows, macos).
Architecture detection is automatic (x86_64, arm64).
"""

import os
import sys
import platform

# ---- Environment Setup -------------------------------------------------------

EnsureSConsVersion(4, 0)

env = SConscript("godot-cpp/SConstruct")

# ---- Platform / Architecture / Target detection ------------------------------

# Add our custom options
opts = Variables([], ARGUMENTS)
opts.Add(
    EnumVariable("target", "Build target", "template_debug",
                 ("editor", "template_debug", "template_release"))
)
opts.Add(BoolVariable("verbose", "Enable verbose output", False))
opts.Add(
    PathVariable("gdextension_dir", "Output directory for .gdextension + binary",
                 "gdextension", PathVariable.PathIsDirCreate)
)
opts.Update(env)
Help(opts.GenerateHelpText(env))

# Derive target name from platform
target_platform = env["platform"]
if target_platform == "linux":
    lib_name = "libsimulation.so"
elif target_platform == "windows":
    lib_name = "libsimulation.dll"
elif target_platform == "macos":
    lib_name = "libsimulation.dylib"
else:
    lib_name = f"libsimulation.{target_platform}"

# Build directory mirrors target/platform structure
build_dir = os.path.join("build", env["platform"], env["target"])

# ---- Compiler Flags ----------------------------------------------------------

env.Append(CPPPATH=["src/"])

if env["target"] == "template_release":
    env.Append(CCFLAGS=["-O3", "-DNDEBUG", "-fomit-frame-pointer"])
elif env["target"] == "template_debug":
    env.Append(CCFLAGS=["-O2", "-g", "-DDEBUG_ENABLED"])
else:  # editor
    env.Append(CCFLAGS=["-O2", "-g", "-DDEBUG_ENABLED", "-DEDITOR_ENABLED"])

# Warnings as errors (strict)
env.Append(CCFLAGS=[
    "-Wall", "-Wextra",
    "-Wno-unused-parameter",    # godot-cpp callbacks have many unused params
    "-Wno-missing-field-initializers",
])

# C++17 required by godot-cpp
env.Append(CXXFLAGS=["-std=c++17"])

# ---- Sources ----------------------------------------------------------------

sources = Glob("src/*.cpp")

# ---- Build Targets ----------------------------------------------------------

# Object files go to build directory
VariantDir(build_dir, "src", duplicate=False)
build_objects = [os.path.join(build_dir, os.path.basename(s)) for s in sources]

# Final library in gdextension/bin/<target_platform>/
output_dir = os.path.join(env["gdextension_dir"], "bin", target_platform)
output_path = os.path.join(output_dir, lib_name)

lib = env.SharedLibrary(target=output_path, source=build_objects)

# Alias so `scons build` works
env.Alias("build", lib)
Default(lib)

# ---- Verbose mode -----------------------------------------------------------

if not env["verbose"]:
    env.SetDefault(COMSTR_COMPILEPROGRESS="[{.TaskComplete}/{.TaskCount}] Compiling $TARGET")
    env.SetDefault(LINKCOMSTR="[Link] $TARGET")
    env.SetDefault(SHCCCOMSTR="[CC] $TARGET")
    env.SetDefault(SHCXXCOMSTR="[CXX] $TARGET")
    env.SetDefault(SHLINKCOMSTR="[Link] $TARGET")

# ---- Clean -------------------------------------------------------------------

Clean(lib, build_dir)
