#!/usr/bin/env bash
set -euo pipefail

log() {
  printf '[redeploy] %s\n' "$*"
}

read_env_value() {
  local key="$1"
  local line=""

  if [[ ! -f .env ]]; then
    return 1
  fi

  while IFS= read -r line || [[ -n "$line" ]]; do
    if [[ "$line" == "${key}="* ]]; then
      printf '%s\n' "${line#*=}"
      return 0
    fi
  done < .env

  return 1
}

upsert_env_value() {
  local key="$1"
  local value="$2"
  local temp_file=""
  local line=""
  local found=0

  temp_file="$(mktemp)"
  while IFS= read -r line || [[ -n "$line" ]]; do
    if [[ "$line" == "${key}="* ]]; then
      printf '%s=%s\n' "$key" "$value" >> "$temp_file"
      found=1
    else
      printf '%s\n' "$line" >> "$temp_file"
    fi
  done < .env

  if [[ "$found" -eq 0 ]]; then
    printf '%s=%s\n' "$key" "$value" >> "$temp_file"
  fi

  chmod --reference=.env "$temp_file" 2>/dev/null || chmod 600 "$temp_file"
  mv "$temp_file" .env
}

parse_route_source_ip() {
  local route="$1"
  local previous=""
  local token

  for token in $route; do
    if [[ "$previous" == "src" ]]; then
      printf '%s\n' "$token"
      return 0
    fi
    previous="$token"
  done

  return 1
}

detect_ad_dns_ip() {
  local lookup_name="$1"
  local target_ip=""
  local route=""

  if ! command -v ip >/dev/null 2>&1; then
    return 1
  fi

  if [[ -n "$lookup_name" ]] && command -v getent >/dev/null 2>&1; then
    while read -r target_ip _; do
      if [[ ! "$target_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
        continue
      fi
      route="$(ip -o -4 route get "$target_ip" 2>/dev/null || true)"
      parse_route_source_ip "$route" && return 0
    done < <(getent ahostsv4 "$lookup_name" 2>/dev/null)
  fi

  route="$(ip -o -4 route get 1.1.1.1 2>/dev/null || true)"
  parse_route_source_ip "$route"
}

refresh_ad_dns_env() {
  local auto=""
  local domain=""
  local detected_ip=""
  local samba_hostname=""
  local netbios_name=""
  local host_part=""

  if [[ ! -f .env ]]; then
    log '.env missing; skipping AD DNS IP refresh'
    return
  fi

  auto="$(read_env_value AD_DNS_IP_AUTO || true)"
  case "${auto,,}" in
    0|false|no)
      log 'AD_DNS_IP_AUTO disabled; keeping configured AD_DNS_IP'
      return
      ;;
  esac

  domain="$(read_env_value DOMAIN || true)"
  if [[ -z "$domain" ]]; then
    log 'DOMAIN missing in .env; skipping AD DNS IP refresh'
    return
  fi

  detected_ip="$(detect_ad_dns_ip "$domain" || true)"
  if [[ -z "$detected_ip" ]]; then
    log 'Unable to detect host LAN IP; keeping configured AD_DNS_IP'
    return
  fi

  upsert_env_value AD_DNS_IP "$detected_ip"
  if ! read_env_value AD_DNS_NAME >/dev/null; then
    samba_hostname="$(read_env_value SAMBA_HOSTNAME || true)"
    netbios_name="$(read_env_value NETBIOS_NAME || true)"
    host_part="${samba_hostname:-${netbios_name,,}}"
    host_part="${host_part:-adsambafsrv}"
    upsert_env_value AD_DNS_NAME "${host_part}.${domain}"
  fi
  upsert_env_value AD_DNS_IP_AUTO "1"
  log "Updated AD_DNS_IP=${detected_ip}"
}

if [[ ! -d .git ]]; then
  printf '[redeploy] ERROR: run this script from the repository root.\n' >&2
  exit 1
fi

refresh_ad_dns_env

OLD_COMPOSE_FILE="$(mktemp)"

cleanup() {
  if [[ -f "$OLD_COMPOSE_FILE" ]]; then
    rm -f "$OLD_COMPOSE_FILE"
  fi
}
trap cleanup EXIT

log 'Capturing current compose configuration'
docker compose config > "$OLD_COMPOSE_FILE"

log 'Pulling latest git changes'
git pull

log 'Building updated images while current stack is running'
docker compose build --no-cache

log 'Stopping previous stack using captured configuration'
docker compose --project-directory "$PWD" -f "$OLD_COMPOSE_FILE" down

log 'Starting stack'
docker compose up -d

log 'Redeploy complete'
