set -e

SCRIPT_NAME="vk"
PROJECT_ROOT=$(pwd)
BUILD_DIR="$PROJECT_ROOT/build"

function help() {
  echo "Vulkan Cookbook Project Management Tool"
  echo ""
  echo "Usage: $SCRIPT_NAME [command]"
  echo ""
  echo "Commands:"
  echo "  new CHAPTER SAMPLE NAME    Create a new sample (e.g. vk new 2 1 'GLFW Window')"
  echo "  build [sample]             Build project using Ninja (all or specific sample)"
  echo "  run CHAPTER SAMPLE         Run a specific sample"
  echo "  cmake                      Regenerate CMake files"
  echo "  list                       List all samples"
  echo "  compile-commands           Copy compile_commands.json to project root"
  echo "  deps                       Run deps bootstrapping"
  echo "  help                       Show this help message"
}

function new_sample() {
  if [ $# -lt 3 ]; then
    echo "Error: Missing arguments for 'new'"
    echo "Usage: $SCRIPT_NAME new CHAPTER SAMPLE NAME"
    return 1
  fi

  CHAPTER=$1
  SAMPLE=$2
  NAME=$3

  PADDED_CHAPTER=$(printf "%02d" "$CHAPTER")
  PADDED_SAMPLE=$(printf "%02d" "$SAMPLE")

  SAMPLE_DIR="$PROJECT_ROOT/Chapter$PADDED_CHAPTER/$PADDED_SAMPLE"_"$NAME"

  if [ -d "$SAMPLE_DIR" ]; then
    echo "Error: Sample directory already exists: $SAMPLE_DIR"
    return 1
  fi

  echo "Creating new sample Ch${PADDED_CHAPTER}_${PADDED_SAMPLE}_${NAME}..."
  mkdir -p "$SAMPLE_DIR/src"

  # Create CMakeLists.txt
  cat >"$SAMPLE_DIR/CMakeLists.txt" <<EOL
cmake_minimum_required(VERSION 3.19)
project(Chapter${PADDED_CHAPTER})
include(../../CMake/CommonMacros.txt)
SETUP_APP(Ch${PADDED_CHAPTER}_${PADDED_SAMPLE}_${NAME} "Chapter ${PADDED_CHAPTER}")

target_include_directories(Ch${PADDED_CHAPTER}_${PADDED_SAMPLE}_${NAME} PUBLIC \${CMAKE_SOURCE_DIR})
target_link_libraries(Ch${PADDED_CHAPTER}_${PADDED_SAMPLE}_${NAME} SharedUtils)
EOL

  # Create minimal main.cpp with GLFW boilerplate
  cat >"$SAMPLE_DIR/src/main.cpp" <<EOL
#include <cstdint>
#include <iostream>
#include <shared/HelpersGLFW.h>

int main(int argc, char* argv[]) {
  std::cout << "Chapter ${CHAPTER}, Sample ${SAMPLE}: ${NAME}" << std::endl;
  
  uint32_t width = 1280;
  uint32_t height = 720;

  GLFWwindow *window = initWindow("Ch${PADDED_CHAPTER}_${PADDED_SAMPLE}: ${NAME}", width, height);

  while (!glfwWindowShouldClose(window)) {
    glfwPollEvents();
  }

  glfwDestroyWindow(window);
  glfwTerminate();
  return 0;
}
EOL

  echo "Successfully created new sample: $SAMPLE_DIR"
  echo "Run '$SCRIPT_NAME cmake' to update CMake configuration"
}

function build_project() {
  if [ ! -d "$BUILD_DIR" ]; then
    echo "Creating build directory..."
    mkdir -p "$BUILD_DIR"
  fi

  cd "$BUILD_DIR"

  if [ $# -eq 0 ]; then
    echo "Building all targets..."
    ninja
  else
    TARGET="Ch$1"
    echo "Building target: $TARGET"
    ninja "$TARGET"
  fi

  cd "$PROJECT_ROOT"
}

function run_sample() {
  if [ $# -lt 2 ]; then
    echo "Error: Missing arguments for 'run'"
    echo "Usage: $SCRIPT_NAME run CHAPTER SAMPLE"
    return 1
  fi

  CHAPTER=$(printf "%02d" "$1")
  SAMPLE=$(printf "%02d" "$2")

  # Find the exact sample name
  SAMPLE_PATTERN="Ch${CHAPTER}_${SAMPLE}_*"
  SAMPLE_BINARY=$(find "$PROJECT_ROOT/bin" -name "$SAMPLE_PATTERN" -type f -executable 2>/dev/null | head -1)

  if [ -z "$SAMPLE_BINARY" ]; then
    echo "Error: Sample not found or not built: Chapter $CHAPTER, Sample $SAMPLE"
    echo "Try building it first: $SCRIPT_NAME build"
    return 1
  fi

  echo "Running $SAMPLE_BINARY..."
  "$SAMPLE_BINARY"
}

function regenerate_cmake() {
  if [ ! -d "$BUILD_DIR" ]; then
    mkdir -p "$BUILD_DIR"
  fi

  # Update root CMakeLists.txt to include all chapters/samples
  echo "Updating root CMakeLists.txt with new samples..."

  # Find all chapter/sample directories, excluding the build directory
  SAMPLES=$(find "$PROJECT_ROOT" -type d -path "*/Chapter*/[0-9][0-9]_*" -not -path "*/**/build/*" -not -path "*/**/src" | sort)

  # Create a temporary file with updated subdirectories
  TEMP_CMAKE=$(mktemp)

  # Extract the content up to line 100 (before add_subdirectory calls)
  head -n "$(grep -n "BINARIES" CMakeLists.txt | head -n 1 | cut -d: -f1)" "$PROJECT_ROOT/CMakeLists.txt" >"$TEMP_CMAKE"

  # Add subdirectories for all samples
  for SAMPLE_DIR in $SAMPLES; do
    # Skip src directories
    if [[ "$SAMPLE_DIR" == */src ]]; then
      continue
    fi

    # Get relative path from project root
    REL_PATH=$(realpath --relative-to="$PROJECT_ROOT" "$SAMPLE_DIR")
    echo "add_subdirectory($REL_PATH)" >>"$TEMP_CMAKE"
  done

  # Update the CMakeLists.txt file
  mv "$TEMP_CMAKE" "$PROJECT_ROOT/CMakeLists.txt"

  cd "$BUILD_DIR"
  echo "Regenerating CMake files..."
  cmake -G Ninja ..
  cd "$PROJECT_ROOT"

  # Copy compile_commands.json to project root
  if [ -f "$BUILD_DIR/compile_commands.json" ]; then
    cp "$BUILD_DIR/compile_commands.json" "$PROJECT_ROOT/"
    echo "Copied compile_commands.json to project root"
  fi
}

function update_deps() {
  echo "Updating Dependencies"
  pushd "$PROJECT_ROOT/deps"
  ./bootstrap.py
  popd
  echo "Dependencies updated"
}

function list_samples() {
  echo "Available samples:"
  find "$PROJECT_ROOT" -type d -path "*/Chapter*/[0-9][0-9]_*" -not -path "build/*" -not -path "*/**/src" | sort | while read -r dir; do
    # Skip src directories
    if [[ "$dir" == */src ]]; then
      continue
    fi
    echo "  $(basename "$(dirname "$dir")")/$(basename "$dir")"
  done
}

# Update main CMakeLists.txt if sample is added or removed
function update_root_cmake() {
  # Check if we need to update the root CMakeLists.txt
  if [ "$1" == "new" ] || [ "$1" == "delete" ]; then
    regenerate_cmake
  fi
}

# Main command dispatcher
if [ $# -eq 0 ]; then
  help
  exit 0
fi

COMMAND=$1
shift

case "$COMMAND" in
"new")
  new_sample "$@"
  update_root_cmake "new"
  ;;
"build")
  build_project "$@"
  ;;
"run")
  run_sample "$@"
  ;;
"cmake")
  regenerate_cmake
  ;;
"list")
  list_samples
  ;;
"deps")
  update_deps
  ;;
"compile-commands")
  cp "$BUILD_DIR/compile_commands.json" "$PROJECT_ROOT/" 2>/dev/null || echo "No compile_commands.json found in build directory"
  ;;
"help")
  help
  ;;
*)
  echo "Unknown command: $COMMAND"
  help
  exit 1
  ;;
esac
