#!/usr/bin/env bash

set -euo pipefail

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_root="$(cd "$script_dir/../.." && pwd)"
env_file="$script_dir/.env"
env_example_file="$script_dir/.env.example"
docker_contexts_dir="$script_dir/build/local-docker-contexts"

service_names=(
  spring-cloud-config-server
  pcp-srpring-boot-admin-server
  pcp-satellite-catalog-service
  pcp-ballistics-service
  pcp-request-service
  pcp-route-processing-service
  slots-service
  pcp-complex-mission-service
  pcp-mission-planing-service
  pcp-coverage-scheme-service
  pcp-dynamic-plan-service
  pcp-stations-service
  pcp-ui-service
  pcp-tgu-service
)

ensure_env_file() {
  if [[ ! -f "$env_file" && -f "$env_example_file" ]]; then
    cp "$env_example_file" "$env_file"
    echo "Created $env_file from .env.example"
  fi
}

ensure_source_config_repo_dir() {
  if grep -q '^CONFIG_REPO_DIR=' "$env_file"; then
    sed -i "s#^CONFIG_REPO_DIR=.*#CONFIG_REPO_DIR=$repo_root/config-repo#" "$env_file"
  else
    printf '\nCONFIG_REPO_DIR=%s/config-repo\n' "$repo_root" >> "$env_file"
  fi
}

load_env() {
  set -a
  # shellcheck disable=SC1090
  source "$env_file"
  set +a
}

require_command() {
  local command_name="$1"
  if ! command -v "$command_name" >/dev/null 2>&1; then
    echo "$command_name is required." >&2
    exit 1
  fi
}

compose() {
  if docker compose version >/dev/null 2>&1; then
    docker compose --project-directory "$script_dir" -f "$script_dir/docker-compose.yml" "$@"
  elif command -v docker-compose >/dev/null 2>&1; then
    docker-compose --project-directory "$script_dir" -f "$script_dir/docker-compose.yml" "$@"
  else
    echo "docker compose or docker-compose is required." >&2
    exit 1
  fi
}

copy_single_boot_jar() {
  local service_name="$1"
  local context_dir="$2"
  local jar_count
  local jar_file

  jar_count="$(
    find "$repo_root/services/$service_name/build/libs" -maxdepth 1 -type f -name '*.jar' ! -name '*-plain.jar' | wc -l
  )"

  if [[ "$jar_count" != "1" ]]; then
    echo "Expected exactly one bootJar for $service_name, found $jar_count:" >&2
    find "$repo_root/services/$service_name/build/libs" -maxdepth 1 -type f -name '*.jar' -print >&2 || true
    exit 1
  fi

  jar_file="$(
    find "$repo_root/services/$service_name/build/libs" -maxdepth 1 -type f -name '*.jar' ! -name '*-plain.jar' | head -n 1
  )"

  mkdir -p "$context_dir/build/libs"
  cp "$repo_root/services/$service_name/Dockerfile" "$context_dir/Dockerfile"
  cp "$jar_file" "$context_dir/build/libs/app.jar"
}

build_images() {
  local gradle_max_workers="${GRADLE_MAX_WORKERS:-1}"
  local gradle_jvmargs="${GRADLE_JVMARGS:--Xmx2g -Dfile.encoding=UTF-8}"
  local kotlin_daemon_jvmargs="${KOTLIN_DAEMON_JVMARGS:--Xmx3g -XX:MaxMetaspaceSize=768m}"
  local gradle_offline="${GRADLE_OFFLINE:-true}"
  local runtime_image="${LOCAL_BUNDLE_RUNTIME_IMAGE:-bellsoft/liberica-openjre-alpine:21.0.5}"
  local image_tag="${PCP_IMAGE_TAG:-local}"
  local service_name
  local image_name
  local context_dir
  local gradle_common_args=(
    "--no-parallel"
    "--max-workers=$gradle_max_workers"
    "-Dorg.gradle.jvmargs=$gradle_jvmargs"
    "-Pkotlin.daemon.jvmargs=$kotlin_daemon_jvmargs"
  )

  if [[ "$gradle_offline" == "true" ]]; then
    gradle_common_args+=("--offline")
  fi

  echo "Building local Docker images..."
  echo "Gradle offline mode: $gradle_offline"
  echo "Local image tag: $image_tag"
  echo "Runtime image: $runtime_image"

  for service_name in "${service_names[@]}"; do
    echo "Building bootJar for $service_name..."
    "$repo_root/gradlew" --project-dir "$repo_root" "${gradle_common_args[@]}" ":services:$service_name:bootJar"
  done

  rm -rf "$docker_contexts_dir"
  mkdir -p "$docker_contexts_dir"

  for service_name in "${service_names[@]}"; do
    image_name="pcp/$service_name:$image_tag"
    context_dir="$docker_contexts_dir/$service_name"

    copy_single_boot_jar "$service_name" "$context_dir"
    echo "Building Docker image $image_name..."
    docker build \
      --build-arg "RUNTIME_IMAGE=$runtime_image" \
      --file "$context_dir/Dockerfile" \
      --tag "$image_name" \
      "$context_dir"
  done
}

usage() {
  cat <<'EOF'
Usage:
  ./deploy/local-bundle/run-local.sh [command]

Commands:
  start     Build service images locally and start docker compose.
  restart   Stop compose stack, then build and start.
  build     Build service images locally, without starting compose.
  stop      Stop compose stack.
  status    Show compose status.
  logs      Follow compose logs.
EOF
}

start_local() {
  build_images
  "$script_dir/scripts/start.sh"
}

command="${1:-start}"
case "$command" in
  help|-h|--help)
    usage
    exit 0
    ;;
esac

ensure_env_file
ensure_source_config_repo_dir
load_env
require_command docker

case "$command" in
  start)
    start_local
    ;;
  restart)
    "$script_dir/scripts/stop.sh"
    start_local
    ;;
  build)
    build_images
    ;;
  stop)
    "$script_dir/scripts/stop.sh"
    ;;
  status)
    "$script_dir/scripts/status.sh"
    ;;
  logs)
    compose logs -f
    ;;
  *)
    usage >&2
    exit 1
    ;;
esac
