#!/bin/bash

# SPDX-FileCopyrightText: 2026 German Aerospace Center (DLR)
# SPDX-License-Identifier: Apache-2.0

###############################################################################
# Helper commands #
###################
# This script contains a few little helper commands to make development easier.
###############################################################################
set -e
set -o pipefail

# imports
source "$(dirname "${BASH_SOURCE[0]}")/scripts/utils.sh"

# global variables
PACKAGE_NAME=dlr.ki.logging
PACKAGE_PATH=${PACKAGE_NAME//./\/}

PROJECT_ROOT="$(pwd)"
BUILD_ROOT="${PROJECT_ROOT}/build"
PACKAGE_ROOT="${PROJECT_ROOT}/${PACKAGE_PATH}"
DOC_ROOT="${PROJECT_ROOT}/docs"
SCRIPTS_ROOT="${PROJECT_ROOT}/scripts"

# default values of arguments
HTTP_SERVE=true

# parse arguments
action=${1,,}; shift
[ "$action" == "--help" ] || [ "$action" == "-h" ] && action=help
while [[ $# -gt 0 ]]; do
  case $1 in
    --no-http-serve) HTTP_SERVE=false; shift ;;
    --help|-h) action=help; shift ;;
    --version) action=version; shift ;;
    --) shift; break ;;
    *)
      # warn "Unknown argument: '$1'; Skip further parsing.";
      break ;;
  esac
done


no_actions="$(compgen -A function)"
###############################################################################
# action functions

function help() {
  actions="$(actions="$(printf '%s,' "${action_map[@]}")"; echo "{${actions%,}}")"
  [ ${#actions} -lt 22 ] && actions=$(printf '%-22s' "$actions") || actions="$actions\n$(printf %24s "")"
  info2 "usage: $0 <action> [options]"
  info2 ""
  info2 "positional arguments:"
  info2 -e "  ${actions}Available sub commands"
  info2 "    help                Show this help message and exit"
  info2 "    start               Run the application"
  info2 "    test                Run all tests"
  info2 "    lint                Run all linter"
  info2 "    lint-code           Run code linter"
  info2 "    lint-doc            Run documentation linter"
  info2 "    lint-scripts        Run bash script linter"
  info2 "    mypy                Run type checker"
  info2 "    coverage            Run unit tests"
  info2 "    coverage-report     Generate test coverage report"
  info2 "    doc                 Start documentation server"
  info2 "    doc-build           Build documentation"
  info2 "    licenses            Check licenses"
  info2 "    safety-check        Check dependencies for known security vulnerabilities"
  info2 "    install             Install package"
  info2 "    clean               Clean up local files"
  info2 "    version             Show package version"
  info2 "    versions            Show versions"
  info2 ""
  info2 "options:"
  info2 "  --no-http-serve       Do not serve the action result via HTTP"
}

function version() {
  awk -F "=" '/version/ {print $2}' "${PROJECT_ROOT}/pyproject.toml" | awk -F'"' '{print $2}' | awk NF | head -n 1
}

function versions() {
  info "versions"
  if ! command -v docker > /dev/null 2>&1; then
    warn "uv not found, skipping uv version"
  else
    info "uv version: $(uv --version)"
  fi
  info -n "package version: "
  version
}

function install() {
  versions
  if ! command -v uv &> /dev/null; then
    if ! command -v curl &> /dev/null; then
      error "uv and curl are not installed. Please install one of them."
      exit 1
    fi
    info "install uv"
    curl -LsSf https://astral.sh/uv/install.sh | sh
  fi
  info "install package"
  uv sync --all-extras
}

function clean() {
  info "remove __pycache__|.pyc|.pyo"
  find "${PROJECT_ROOT}" | grep -E "(__pycache__|\.pyc$$|\.pyo$$)" | xargs rm -rf
  info "remove builds"
  rm -rf "${BUILD_ROOT}"
  rm -rf "${PROJECT_ROOT}/site"
  info "remove egg-info"
  rm -rf "${PROJECT_ROOT}/*.egg-info"
  info "remove tox"
  rm -rf "${PROJECT_ROOT}/.tox"
  info "remove pytest cache"
  rm -rf "${PROJECT_ROOT}/.pytest_cache"
  info "remove mypy cache"
  rm -rf "${PROJECT_ROOT}/.mypy_cache"
}

function start() {
  error "not implemented yet"
  exit 1
}

function test() {
  versions
  info "run all tests"
  lint
  mypy
  coverage
  coverage-report
  if [ "${HTTP_SERVE}" = "true" ]; then
    if [ -d "${BUILD_ROOT}/htmlcov" ]; then
      uv run -m http.server --directory "${BUILD_ROOT}/htmlcov" 8080
    else
      error "no coverage report found"
      exit 1
    fi
  fi
}

function lint() {
  versions
  info "linting"
  lint-code
  lint-doc
  lint-scripts
}

function lint-code() {
  info "lint code"
  info "flake8 version: $(uv run flake8 --version | xargs)"
  uv run flake8 "${PACKAGE_ROOT}"
  uv run flake8 "${SCRIPTS_ROOT}"
}

function lint-doc() {
  info "lint documentation"
  # use markdownlint from David Anson (based on nodejs)
  # https://github.com/DavidAnson/markdownlint
  npm exec "markdownlint-cli2@0.22.0" -- "${DOC_ROOT}/**/*.md" "${PROJECT_ROOT}/README.md"
}

function lint-scripts() {
  info "lint bash scripts"
  info "shellcheck $(shellcheck --version | head -n 2 | tail -n 1)"
  shellcheck --external-sources --shell bash --source-path "${PROJECT_ROOT}" "${PROJECT_ROOT}/dev"
  shellcheck --external-sources --shell bash --source-path "${SCRIPTS_ROOT}" "${SCRIPTS_ROOT}/"*.sh
}

function mypy() {
  info "type checking"
  uv run mypy --explicit-package-bases "${PACKAGE_ROOT}"
  if find "${SCRIPTS_ROOT}" -type f -name "*.py" | grep -q .; then
    uv run mypy "${SCRIPTS_ROOT}"
  fi
}

function coverage() {
  info "run python tests with coverage"
  warn "no tests implemented yet"
  #uv run coverage run -m pytest
  #uv run coverage html --directory "${BUILD_ROOT}/htmlcov"
}

function coverage-report() {
  info "print test coverage report"
  warn "no tests implemented yet"
  #uv run coverage report
}

function doc() {
  versions
  mkdocs_version="$(uv run mkdocs --version)"
  info "${mkdocs_version#"uv run "}"
  info "start documentation server"
  # check if the user has passed the --dirtyreload flag
  dirty_flag=false
  for value in "$@"; do
    [[ "--dirty" = "$value" ]] && dirty_flag=true
  done
  if [[ "$dirty_flag" == "false" ]]; then
    warn "consider using --dirty to reload only file changes instead of the"
    warn "whole project. This can lead to a significant speed up during the"
    warn "documentation development."
  fi
  # create and serve documentation
  uv run mkdocs serve "$@"
}

function doc-build() {
  versions
  mkdocs_version="$(uv run mkdocs --version)"
  info "${mkdocs_version#"uv run "}"
  info "build documentation"
  uv run mkdocs build "$@"
}

function licenses() {
  info "search for license conflicts"
  uv run licensecheck
  info "search for non-compliant files with REUSE"
  uv run reuse lint
}

function safety-check() {
  info "check dependencies for known security vulnerabilities"
  # main only no dev dependencies etc.
  uv run tox --recreate -e safety
}


# create array with all action functions (above)
readarray -t action_map <<< "$(comm -3 <(compgen -A function) <(echo "$no_actions"))"
###############################################################################
# run action

if ! printf '%s\n' "${action_map[@]}" | grep -x -q "$action"; then
  echo "Invalid action : $action"
  echo "Allowed actions: ${action_map[*]}"
  echo "Use --help for more information"
  exit 1
fi

$action "$@"
