#! /usr/bin/env python

import os
import sys
import typing
import pathlib
import subprocess

import waves

# Comments used in tutorial code snippets: marker-1

# Accept command line options with fall back default values
AddOption(
    "--build-dir",
    dest="variant_dir_base",
    default="build",
    nargs=1,
    type="string",
    action="store",
    metavar="DIR",
    help="SCons build (variant) root directory. Relative or absolute path. (default: '%default')",
)
AddOption(
    "--unconditional-build",
    dest="unconditional_build",
    default=False,
    action="store_true",
    help="Boolean flag to force building of conditionally ignored targets. (default: '%default')",
)
AddOption(
    "--print-build-failures",
    dest="print_build_failures",
    default=False,
    action="store_true",
    help="Print task *.stdout target file(s) on build failures. (default: '%default')",
)
# Python optparse appends to the default list instead of overriding. Must implement default/override ourselves.
default_abaqus_commands = [
    "/apps/abaqus/Commands/abq2024",
    "/usr/projects/ea/abaqus/Commands/abq2024",
    "abq2024",
    "abaqus",
]
AddOption(
    "--abaqus-command",
    dest="abaqus_command",
    nargs=1,
    type="string",
    action="append",
    metavar="COMMAND",
    help=f"Override for the Abaqus command. Repeat to specify more than one (default: {default_abaqus_commands})",
)
default_cubit_commands = [
    "/apps/Cubit-16.12/cubit",
    "/usr/projects/ea/Cubit/Cubit-16.12/cubit",
    "cubit",
]
AddOption(
    "--cubit-command",
    dest="cubit_command",
    nargs=1,
    type="string",
    action="append",
    metavar="COMMAND",
    help=f"Override for the Cubit command. Repeat to specify more than one (default: {default_cubit_commands})",
)

# Comments used in tutorial code snippets: marker-2

# Inherit user's full environment and set project variables
env = waves.scons_extensions.WAVESEnvironment(
    ENV=os.environ.copy(),
    variant_dir_base=pathlib.Path(GetOption("variant_dir_base")),
    unconditional_build=GetOption("unconditional_build"),
    print_build_failures=GetOption("print_build_failures"),
    abaqus_commands=GetOption("abaqus_command"),
    cubit_commands=GetOption("cubit_command"),
)

# Conditionally print failed task *.stdout files
env.PrintBuildFailures(print_stdout=env["print_build_failures"])

# Comments used in tutorial code snippets: marker-3

# Find required programs for conditional target ignoring and absolute path for use in target actions
env["ABAQUS_PROGRAM"] = env.AddProgram(
    env["abaqus_commands"] if env["abaqus_commands"] is not None else default_abaqus_commands
)
env["CUBIT_PROGRAM"] = env.AddCubit(
    env["cubit_commands"] if env["cubit_commands"] is not None else default_cubit_commands
)
env["FIERRO_IMPLICIT_PROGRAM"] = env.AddProgram(["fierro-parallel-implicit"])


# Sierra requires a separate construction environment
def return_modulepath(modules: typing.Iterable[str]) -> pathlib.Path:
    """Return parent path of first found module or the current working directory"""
    return next((pathlib.Path(path).parent for path in modules if pathlib.Path(path).exists()), pathlib.Path("."))


sierra_modules = [
    "/projects/aea_compute/modulefiles/sierra/5.21.6",
]
sierra_modulefile_parent = return_modulepath(sierra_modules)
try:
    envSierra = waves.scons_extensions.shell_environment(f"module use {sierra_modulefile_parent} && module load sierra")
except subprocess.CalledProcessError:
    print("Failed to initialize the Sierra environment", file=sys.stderr)
    envSierra = Environment()
envSierra["sierra"] = waves.scons_extensions.add_program(envSierra, ["sierra"])

# Comments used in tutorial code snippets: marker-4

# Set project internal variables and variable substitution dictionaries
project_name = "WAVES-TUTORIAL"
version = "0.1.0"
project_dir = pathlib.Path(Dir(".").abspath)
project_variables = {
    "project_name": project_name,
    "project_dir": project_dir,
    "version": version,
}
for key, value in project_variables.items():
    env[key] = value

# Comments used in tutorial code snippets: marker-5

# Add builders and pseudo-builders
env.Append(BUILDERS={})

envSierra.Append(
    BUILDERS={
        "Sierra": waves.scons_extensions.sierra_builder_factory(program=envSierra["sierra"]),
    }
)

# Comments used in tutorial code snippets: marker-6

# Add simulation targets
workflow_configurations = [
    "abaqus",
    "sierra",
    "fierro",
]
for workflow in workflow_configurations:
    build_dir = env["variant_dir_base"] / workflow
    SConscript(
        workflow,
        variant_dir=build_dir,
        exports={"env": env, "envSierra": envSierra},
        duplicate=False,
    )

# Comments used in tutorial code snippets: marker-7

# Add default target list to help message
env.Default()  # Empty defaults list to avoid building all simulation targets by default
# Add aliases to help message so users know what build target options are available
# This must come *after* all expected Alias definitions and SConscript files.
env.ProjectHelp()

# Comments used in tutorial code snippets: marker-8
