#!/usr/bin/env bash

set -e

# --- Defaults ---
userFlag=0
testsFlag=0
runTestsFlag=0
buildDir="build"
installDir="$HOME/.local/4DSSE"


# --- Help Menu ---
show_help() {
  cat <<EOF
Usage: $(basename "$0") [OPTIONS]

Options:
  --user         Build and Install as a release for. Intended for end users.
  --noBuildTest  Do not build tests.
  --runTest      Run tests.
  --buildDir     Specify the build directory. Default is "${buildDir}".
  --installDir   Specify the install directory. Default is "${installDir}".
  -h, --help     Show this help message and exit

You can use these flags in any order. Flags not passed will get default values.

Examples:
  For an end user who wants a seemless experience 4DSSE:
    ./mk --user
  For developers who want to modify the source:
    ./mk
  For developers who want to run tests:
    ./mk --tests
EOF
}

# --- Parse Arguments ---
while [[ $# -gt 0 ]]; do
  case "$1" in
    --user)
      userFlag=1
      shift
      ;;
    --noTest)
      testsFlag=1
      shift
      ;;
    --runTest)
      runTestsFlag=1
      shift
      ;;
    --buildDir)
      buildDir=1
      shift
      ;;
    --installDir)
      installDir=1
      shift
      ;;
    -h|--help)
      show_help
      exit 0
      ;;
    *)
      echo "Unknown option: $1"
      echo "Use --help for usage information."
      exit 1
      ;;
  esac
done

RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
BLUE="\033[0;34m"
MAGENTA="\033[0;35m"
NC="\033[0m"  # No Color

# Log file.
LOGDIR="4DSSE_logs"
if [[ ! -d "$LOGDIR" ]]; then
  echo -e "${BLUE}[Info] Creating log directory...${NC}"
  mkdir "$LOGDIR"
else
  echo -e "${MAGENTA}[Succsess] Log directory already exists. Skipping...${NC}"
fi
LOGFILE="${LOGDIR}/4DSSE-install-log.txt"


# Log function: prints to stdout and appends to logfile.
log() {
  local message="$1"
  # Print the colored message to stdout.
  echo -e "$message"
  # Strip ANSI escape sequences and append the cleaned message to the log file.
  echo -e "$message" | sed -r 's/\x1B\[[0-9;]*[mK]//g' >> "$LOGFILE"
}

if [[ -f "$LOGFILE" ]]; then
  # Get the calendar datetime of the log file creation.
  # convert UNIX timestamp to human-readable date
  rm "$LOGFILE"
  log "${BLUE}[Info] Old log file removed.${NC}"
fi
touch "$LOGFILE"

# --- Check if Clang or GCC is installed ---
log "${BLUE}[Info] Checking if Clang or GCC is installed...${NC}"
if ! command -v clang &> /dev/null && ! command -v gcc &> /dev/null; then
  log "${RED}[Error] Clang or GCC is not installed. Exiting...${NC}"
  log "${YELLOW}[Info] Please install Clang or GCC and try again.${NC}"
  exit 1
else
  log "${MAGENTA}[Succsess] Clang or GCC is installed. Continuing...${NC}"
fi

# --- Check if MESON is installed ---
log "${BLUE}[Info] Checking if Meson is installed...${NC}"
if ! command -v meson &> /dev/null; then
  log "${RED}[Error] Meson is not installed. Exiting...${NC}"
  # Check if the user would like to try to install meson by getting input
  installMeson=0
  while true; do
    echo -ne "${YELLOW}[Query] Would you like to try to install Meson? [y/n]: ${NC}"
    read -p "" yn
    case $yn in
      [Yy]* ) installMeson=1; break;;
      [Nn]* ) break;;
      * ) echo "Please answer yes or no.";;
    esac
  done
  if [[ $installMeson -eq 1 ]]; then
    # check if pip is installed
    if ! command -v pip &> /dev/null; then
      log "${RED}[Error] pip is not installed. Exiting...${NC}"
      log "${YELLOW}[Info] Please install pip and try again.${NC}"
      exit 1
    else
      log "${MAGENTA}[Succsess] pip is installed. Continuing...${NC}"
    fi

    # check if python3 is installed
    if ! command -v python3 &> /dev/null; then
      log "${RED}[Error] python3 is not installed. Exiting...${NC}"
      log "${YELLOW}[Info] Please install python3 and try again.${NC}"
      log "${YELLOW}[INFO] If you have python3 installed, please add it to your PATH.${NC}"
      exit 1
    else
      log "${MAGENTA}[Succsess] python3 is installed. Continuing...${NC}"
    fi

    # Check if the venv ~/.4DSSE_env exists
    if [[ ! -d "$HOME/.4DSSE_env" ]]; then
      log "${BLUE}[Info] Creating virtual environment...${NC}"
      python3 -m venv "$HOME/.4DSSE_env"
      source "$HOME/.4DSSE_env/bin/activate"
      log "${GREEN}[Succsess] Virtual environment created.${NC}"
    else
      log "${MAGENTA}[Succsess] Virtual environment already exists. Skipping...${NC}"
    fi

    # install meson
    log "${BLUE}[Info] Installing Meson...${NC}"
    pip install meson

    # confirm meson is installed
    if ! command -v meson &> /dev/null; then
      log "${RED}[Error] Meson did not install properly. Exiting...${NC}"
      log "${YELLOW}[Info] Please manually install Meson and try again.${NC}"
      exit 1
    else
      log "${GREEN}[Succsess] Meson installed.${NC}"
    fi
  else
    log "${YELLOW}[Info] Please install Meson and try again.${NC}"
    exit 1
  fi
else
  log "${MAGENTA}[Succsess] Meson is installed. Continuing...${NC}"
fi

# --- Check if NINJA is installed ---
log "${BLUE}[Info] Checking if Ninja is installed...${NC}"
if ! command -v ninja &> /dev/null; then
  log "${RED}[Error] Ninja is not installed. Exiting...${NC}"

  # Check if the user would like to try to install ninja by getting input
  installNinja=0
  while true; do
    echo -ne "${YELLOW}[Query] Would you like to try to install Ninja? [y/n]: ${NC}"
    read -p "" yn
    case $yn in
      [Yy]* ) installNinja=1; break;;
      [Nn]* ) break;;
      * ) echo "Please answer yes or no.";;
    esac
  done
  if [[ $installNinja -eq 1 ]]; then
    # check if pip is installed
    if ! command -v pip &> /dev/null; then
      log "${RED}[Error] pip is not installed. Exiting...${NC}"
      log "${YELLOW}[Info] Please install pip and try again.${NC}"
      exit 1
    else
      log "${MAGENTA}[Succsess] pip is installed. Continuing...${NC}"
    fi

    # check if python3 is installed
    if ! command -v python3 &> /dev/null; then
      log "${RED}[Error] python3 is not installed. Exiting...${NC}"
      log "${YELLOW}[Info] Please install python3 and try again.${NC}"
      log "${YELLOW}[INFO] If you have python3 installed, please add it to your PATH.${NC}"
      exit 1
    else
      log "${MAGENTA}[Succsess] python3 is installed. Continuing...${NC}"
    fi

    # Check if the venv ~/.4DSSE_env exists
    if [[ ! -d "$HOME/.4DSSE_env" ]]; then
      log "${BLUE}[Info] Creating virtual environment...${NC}"
      python3 -m venv "$HOME/.4DSSE_env"
      source "$HOME/.4DSSE_env/bin/activate"
      log "${GREEN}[Succsess] Virtual environment created.${NC}"
    else
      log "${MAGENTA}[Succsess] Virtual environment already exists. Skipping...${NC}"
    fi

    # install ninja
    log "${BLUE}[Info] Installing Ninja...${NC}"
    pip install ninja

    # confirm ninja is installed
    if ! command -v ninja &> /dev/null; then
      log "${RED}[Error] Ninja did not install properly. Exiting...${NC}"
      log "${YELLOW}[Info] Please manually install Ninja and try again.${NC}"
      exit 1
    else
      log "${GREEN}[Succsess] Ninja installed.${NC}"
    fi
  else
    log "${YELLOW}[Info] Please install Ninja and try again.${NC}"
    exit 1
  fi
else
  log "${MAGENTA}[Succsess] Ninja is installed. Continuing...${NC}"
fi

# --- Check if CMake is installed ---
log "${BLUE}[Info] Checking if CMake is installed...${NC}"
if ! command -v cmake &> /dev/null; then
  log "${RED}[Error] CMake is not installed....${NC}"

  # Check if the user would like to try to install cmake by getting input
  installCMake=0
  while true; do
    echo -ne "${YELLOW}[Query] Would you like to try to install CMake? [y/n]: ${NC}"
    read -p "" yn
    case $yn in
      [Yy]* ) installCMake=1; break;;
      [Nn]* ) break;;
      * ) echo "Please answer yes or no.";;
    esac
  done
  if [[ $installCMake -eq 1 ]]; then
    # check if pip is installed
    if ! command -v pip &> /dev/null; then
      log "${RED}[Error] pip is not installed. Exiting...${NC}"
      log "${YELLOW}[Info] Please install pip and try again.${NC}"
      exit 1
    else
      log "${MAGENTA}[Succsess] pip is installed. Continuing...${NC}"
    fi

    # check if python3 is installed
    if ! command -v python3 &> /dev/null; then
      log "${RED}[Error] python3 is not installed. Exiting...${NC}"
      log "${YELLOW}[Info] Please install python3 and try again.${NC}"
      log "${YELLOW}[INFO] If you have python3 installed, please add it to your PATH.${NC}"
      exit 1
    else
      log "${MAGENTA}[Succsess] python3 is installed. Continuing...${NC}"
    fi

    # Check if the venv ~/.4DSSE_env exists
    if [[ ! -d "$HOME/.4DSSE_env" ]]; then
      log "${BLUE}[Info] Creating virtual environment...${NC}"
      python3 -m venv "$HOME/.4DSSE_env"
      source "$HOME/.4DSSE_env/bin/activate"
      log "${GREEN}[Succsess] Virtual environment created.${NC}"
    else
      log "${MAGENTA}[Succsess] Virtual environment already exists. Skipping...${NC}"
    fi

    # install cmake
    log "${BLUE}[Info] Installing CMake...${NC}"
    pip install cmake

    # confirm cmake is installed
    if ! command -v cmake &> /dev/null; then
      log "${RED}[Error] CMake did not install properly. Exiting...${NC}"
      log "${YELLOW}[Info] Please manually install CMake and try again.${NC}"
      exit 1
    else
      log "${GREEN}[Succsess] CMake installed.${NC}"
    fi
  fi
else
    log "${MAGENTA}[Succsess] CMake is installed. Continuing...${NC}"
fi

# --- Build 4DSSE ---
log "${BLUE}[Info] Building 4DSSE...${NC}"
if [[ $userFlag -eq 1 ]]; then
  log "${BLUE}[Info] Installing 4DSSE in user mode...${NC}"
else
  log "${BLUE}[Info] Installing 4DSSE for developers...${NC}"
fi

if [[ $testsFlag -eq 0 ]]; then
  log "${BLUE}[Info] Building with tests...${NC}"
else
  log "${BLUE}[Info] Building without tests...${NC}"
fi

# --- First check Boost status ---
log "${BLUE}[Info] Checking Boost status...${NC}"
# if the following script exists with anything other than a 0 status the script will exit
if [[ -f ./build-config/boost/.boost_installed ]]; then
  log "${MAGENTA}[Succsess] Boost already installed. Skipping...${NC}"
else
  log "${BLUE}[Info] Installing Boost...${NC}"
  if ! ./build-config/boost/install.sh; then
    log "${RED}[Error] Boost check failed. Exiting...${NC}"
    exit 1
  else
    touch ./build-config/boost/.boost_installed
    log "${GREEN}[Succsess] Boost check passed.${NC}"
  fi
fi

#check if the last build flags are the same as the current build flags
# if the flags are the same skip the configuration step
# if they are different then reconfigure the build directory

# do not use grep -oP as it is not POSIX compliant

doReconfigure=1

log "${BLUE}[Info] Checking last build flags...${NC}"
if [[ -f $buildDir/.last_build_flags ]]; then
  lastUserFlag=$(grep -Eo 'userFlag=[0-9]+' $buildDir/.last_build_flags | cut -d'=' -f2)
  lastTestsFlag=$(grep -Eo 'testsFlag=[0-9]+' $buildDir/.last_build_flags | cut -d'=' -f2)
  if [[ $lastUserFlag -eq $userFlag && $lastTestsFlag -eq $testsFlag ]]; then
    log "${MAGENTA}[Succsess] Last build flags match current build flags. Skipping configuration...${NC}"
    doReconfigure=0
  else
    log "${YELLOW}[Info] Last build flags do not match current build flags. Reconfiguring...${NC}"
    rm -rf $buildDir
  fi
else
  log "${BLUE}[Info] Last build flags not found. Reconfiguring...${NC}"
fi


# --- Check if the build dir has been configured with the correct flags ---
if [[ $doReconfigure -eq 1 ]]; then
  log "${BLUE}[Info] Configuring build directory...${NC}"
  if [ -f "$buildDir/build.ninja" ]; then
    log "${MAGENTA}[Succsess] Build directory already configured. Skipping...${NC}"
  else
    if [[ $userFlag -eq 1 ]]; then
      meson setup "$buildDir" -Duser_mode=true --buildtype=release 
    else
      if [[ $testsFlag -eq 0 ]]; then
        meson setup "$buildDir" --buildtype=debug 
      else
        meson setup "$buildDir" --buildtype=debug -Dbuild_tests=false
      fi
    fi
    log "${GREEN}[Succsess] Build directory configured successfully.${NC}"
  fi
  log "${BLUE}[Info] Caching last build flags...${NC}"

  # --- Cache the last build flags ---
  if [[ $userFlag -eq 1 ]]; then
    echo "userFlag=1" > $buildDir/.last_build_flags
  else
    echo "userFlag=0" > $buildDir/.last_build_flags
  fi
  if [[ $testsFlag -eq 1 ]]; then
    echo "testsFlag=1" >> $buildDir/.last_build_flags
  else
    echo "testsFlag=0" >> $buildDir/.last_build_flags
  fi

  log "${GREEN}[Succsess] Last build flags cached.${NC}"
fi

log "${BLUE}[Info] Building 4DSSE...${NC}"
meson compile -C "$buildDir"

# --- Install 4DSSE ---
if [[ $userFlag -eq 1 ]]; then
  log "${BLUE}[Info] Installing 4DSSE in user mode...${NC}"
  meson install -C "$buildDir"
fi

if [[ $runTestsFlag -eq 1 ]]; then
  log "${BLUE}[Info] Running tests...${NC}"
  meson test -C "$buildDir"
fi

if [[ $userFlag -eq 1 ]]; then
  log "${GREEN}[Succsess] 4DSSE built and installed successfully.${NC}"
else
  log "${GREEN}[Succsess] 4DSSE built successfully.${NC}"
fi


log "${GREEN}[Succsess] 4DSSE mk script complete.${NC}"
