#!/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
)

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

Commands:
  restart   Build SERVICE bootJar, rebuild its Docker image and recreate only this compose service.
  build     Build SERVICE bootJar and Docker image, without restarting container.
  stop      Stop SERVICE container.
  logs      Follow SERVICE logs.

Examples:
  ./deploy/local-bundle/run-service.sh pcp-request-service
  ./deploy/local-bundle/run-service.sh pcp-request-service build
EOF
}

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
}

is_known_service() {
  local service_name="$1"
  local known_service_name

  for known_service_name in "${service_names[@]}"; do
    if [[ "$known_service_name" == "$service_name" ]]; then
      return 0
    fi
  done

  return 1
}

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_service_image() {
  local service_name="$1"
  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 image_name="pcp/$service_name:$image_tag"
  local context_dir="$docker_contexts_dir/$service_name"
  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 bootJar for $service_name..."
  "$repo_root/gradlew" --project-dir "$repo_root" "${gradle_common_args[@]}" ":services:$service_name:bootJar"

  rm -rf "$context_dir"
  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"
}

http_get() {
  local url="$1"
  if command -v curl >/dev/null 2>&1; then
    curl -fsS "$url" >/dev/null
  elif command -v wget >/dev/null 2>&1; then
    wget -q -O /dev/null "$url"
  else
    return 2
  fi
}

wait_for_config_server() {
  local attempt
  local url="http://localhost:${CONFIG_SERVER_PORT:-38888}/actuator/health"

  for attempt in {1..90}; do
    if http_get "$url"; then
      echo "spring-cloud-config-server is ready: $url"
      return 0
    fi
    sleep 2
  done

  echo "spring-cloud-config-server is not ready after 180 seconds: $url" >&2
  exit 1
}

restart_service() {
  local service_name="$1"

  build_service_image "$service_name"

  if [[ "$service_name" == "spring-cloud-config-server" ]]; then
    compose up -d --no-deps --force-recreate "$service_name"
    wait_for_config_server
    return 0
  fi

  compose up -d spring-cloud-config-server
  wait_for_config_server
  compose up -d --no-deps --force-recreate "$service_name"
}

service_name="${1:-}"
command="${2:-restart}"

if [[ -z "$service_name" || "$service_name" == "help" || "$service_name" == "-h" || "$service_name" == "--help" ]]; then
  usage
  exit 0
fi

if ! is_known_service "$service_name"; then
  echo "Unknown service: $service_name" >&2
  echo "Known services:" >&2
  printf '  %s\n' "${service_names[@]}" >&2
  exit 1
fi

ensure_env_file
ensure_source_config_repo_dir
load_env
require_command docker

case "$command" in
  restart)
    restart_service "$service_name"
    ;;
  build)
    build_service_image "$service_name"
    ;;
  stop)
    compose stop "$service_name"
    ;;
  logs)
    compose logs -f "$service_name"
    ;;
  help|-h|--help)
    usage
    ;;
  *)
    usage >&2
    exit 1
    ;;
esac
