#!/usr/bin/env bash

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"

ENV_FILE="$PROJECT_ROOT/.env"
COMPOSE_FILE="$PROJECT_ROOT/docker-compose.yml"

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

print_info() {
  echo -e "${BLUE}info${NC} $1"
}

print_success() {
  echo -e "${GREEN}ok${NC} $1"
}

print_warning() {
  echo -e "${YELLOW}warn${NC} $1"
}

print_error() {
  echo -e "${RED}error${NC} $1"
}

command_exists() {
  command -v "$1" >/dev/null 2>&1
}

decode_base64() {
  local value="$1"
  if command_exists openssl; then
    printf '%s' "$value" | openssl base64 -d -A 2>/dev/null
    return $?
  fi
  if command_exists base64; then
    printf '%s' "$value" | base64 --decode 2>/dev/null && return 0
    printf '%s' "$value" | base64 -d 2>/dev/null && return 0
    printf '%s' "$value" | base64 -D 2>/dev/null && return 0
    return 1
  fi
  return 1
}

validate_sa_json_b64() {
  local value="$1"
  if [ -z "$value" ]; then
    print_error "EMAIL_MONITOR_SA_JSON_B64 is empty"
    return 1
  fi
  if [[ "$value" == \{* ]]; then
    print_error "EMAIL_MONITOR_SA_JSON_B64 looks like raw JSON, not base64"
    return 1
  fi
  local decoded=""
  decoded="$(decode_base64 "$value")" || true
  if [ -z "$decoded" ]; then
    print_error "EMAIL_MONITOR_SA_JSON_B64 is not valid base64"
    return 1
  fi
  if [[ "$decoded" != \{* ]]; then
    print_error "Decoded service account does not look like JSON"
    return 1
  fi
  if [[ "$decoded" != *\"client_email\"* ]]; then
    print_warning "Decoded JSON missing client_email; verify service account key"
  fi
  return 0
}

load_env_file() {
  if [ ! -f "$ENV_FILE" ]; then
    return 1
  fi
  set -a
  # shellcheck disable=SC1090
  source "$ENV_FILE"
  set +a
  return 0
}

validate_env() {
  if ! load_env_file; then
    print_error ".env not found at $ENV_FILE"
    return 1
  fi
  validate_sa_json_b64 "${EMAIL_MONITOR_SA_JSON_B64:-}"
}

detect_docker_compose() {
  if command_exists docker && docker compose version >/dev/null 2>&1; then
    echo "docker compose"
    return 0
  fi
  if command_exists docker-compose; then
    echo "docker-compose"
    return 0
  fi
  return 1
}

read_input() {
  local prompt="$1"
  local default="$2"
  local var_name="$3"

  if [ -n "$default" ]; then
    read -r -p "$(echo -e ${BLUE}?${NC}) $prompt [default: $default]: " input
    eval "$var_name=\"${input:-$default}\""
  else
    read -r -p "$(echo -e ${BLUE}?${NC}) $prompt: " input
    eval "$var_name=\"$input\""
  fi
}

ensure_env_file() {
  if [ -f "$ENV_FILE" ]; then
    return 0
  fi

  print_info "Creating .env for email monitor"
  read_input "Service account JSON base64 (EMAIL_MONITOR_SA_JSON_B64) or @/path/to/key.json" "" SA_JSON_B64
  if [[ "$SA_JSON_B64" == @* ]]; then
    local sa_path="${SA_JSON_B64#@}"
    if [ ! -f "$sa_path" ]; then
      print_error "Service account JSON file not found: $sa_path"
      exit 1
    fi
    if command_exists openssl; then
      SA_JSON_B64="$(openssl base64 -A -in "$sa_path")"
    elif command_exists base64; then
      if base64 --version >/dev/null 2>&1; then
        SA_JSON_B64="$(base64 -w 0 "$sa_path")"
      else
        SA_JSON_B64="$(base64 < "$sa_path" | tr -d '\n')"
      fi
    else
      print_error "base64 or openssl is required to encode the JSON file"
      exit 1
    fi
  fi
  read_input "Impersonated mailbox (EMAIL_MONITOR_IMPERSONATE_USER)" "" MAILBOX
  read_input "Sender list, comma-separated (EMAIL_MONITOR_SENDERS)" "" SENDERS
  read_input "Monitor mode (poll or watch)" "poll" MODE
  read_input "Poll interval (only for poll mode)" "2m" POLL_INTERVAL
  read_input "History window" "24h" HISTORY_WINDOW
  read_input "Watch renewal interval" "24h" WATCH_RENEWAL
  read_input "GCP project (watch mode only)" "" GCP_PROJECT
  read_input "Pub/Sub topic (watch mode only)" "" PUBSUB_TOPIC
  read_input "Pub/Sub subscription (watch mode only)" "" PUBSUB_SUBSCRIPTION
  read_input "Lark/Feishu webhook URL (FEISHU_WEBHOOK)" "" WEBHOOK

  cat > "$ENV_FILE" <<EOF
EMAIL_MONITOR_SA_JSON_B64="$SA_JSON_B64"
EMAIL_MONITOR_IMPERSONATE_USER="$MAILBOX"
EMAIL_MONITOR_SENDERS="$SENDERS"
EMAIL_MONITOR_MODE="$MODE"
EMAIL_MONITOR_POLL_INTERVAL="$POLL_INTERVAL"
EMAIL_MONITOR_HISTORY_WINDOW="$HISTORY_WINDOW"
EMAIL_MONITOR_WATCH_RENEWAL="$WATCH_RENEWAL"
EMAIL_MONITOR_GCP_PROJECT="$GCP_PROJECT"
EMAIL_MONITOR_PUBSUB_TOPIC="$PUBSUB_TOPIC"
EMAIL_MONITOR_PUBSUB_SUBSCRIPTION="$PUBSUB_SUBSCRIPTION"
FEISHU_WEBHOOK="$WEBHOOK"
EOF

  chmod 600 "$ENV_FILE"
  print_success ".env created at $ENV_FILE"
  validate_env
}

compose_up() {
  local compose_cmd="$1"
  ensure_env_file
  validate_env
  $compose_cmd -f "$COMPOSE_FILE" up -d --build
  print_success "Email monitor started"
}

compose_down() {
  local compose_cmd="$1"
  $compose_cmd -f "$COMPOSE_FILE" down
  print_success "Email monitor stopped"
}

compose_status() {
  local compose_cmd="$1"
  $compose_cmd -f "$COMPOSE_FILE" ps
}

compose_logs() {
  local compose_cmd="$1"
  $compose_cmd -f "$COMPOSE_FILE" logs -f --tail=200
}

run_local() {
  ensure_env_file
  validate_env
  (cd "$PROJECT_ROOT" && go mod tidy)
  load_env_file
  (cd "$PROJECT_ROOT" && go run ./cmd)
}

usage() {
  cat <<EOF
Usage: $0 <command> [--logs]

Commands:
  start     Start with Docker Compose (default)
  stop      Stop containers
  restart   Restart containers
  status    Show container status
  logs      Tail logs
  run       Run locally with go run
  init      Create .env only

Options:
  --logs    Tail Docker logs after start or restart
EOF
}

main() {
  local cmd="${1:-start}"
  local compose_cmd=""
  local has_compose="true"
  local tail_logs="false"

  if [[ "$*" == *"--logs"* ]]; then
    tail_logs="true"
  fi

  case "$cmd" in
    init)
      ensure_env_file
      exit 0
      ;;
    run)
      if ! command_exists go; then
        print_error "go not found; install Go or use Docker"
        exit 1
      fi
      run_local
      exit 0
      ;;
    start|stop|restart|status|logs)
      compose_cmd="$(detect_docker_compose || true)"
      if [ -z "$compose_cmd" ]; then
        has_compose="false"
      fi
      ;;
    *)
      usage
      exit 1
      ;;
  esac

  case "$cmd" in
    start)
      if [ "$has_compose" = "false" ]; then
        print_warning "Docker Compose not found; falling back to local mode"
        if ! command_exists go; then
          print_error "go not found; install Go or Docker"
          exit 1
        fi
        run_local
      else
        compose_up "$compose_cmd"
        if [ "$tail_logs" = "true" ]; then
          compose_logs "$compose_cmd"
        fi
      fi
      ;;
    stop)
      if [ "$has_compose" = "false" ]; then
        print_error "Docker Compose not found; stop is only available in Docker mode"
        exit 1
      fi
      compose_down "$compose_cmd"
      ;;
    restart)
      if [ "$has_compose" = "false" ]; then
        print_warning "Docker Compose not found; running local mode instead"
        if ! command_exists go; then
          print_error "go not found; install Go or Docker"
          exit 1
        fi
        run_local
      else
        compose_down "$compose_cmd"
        compose_up "$compose_cmd"
        if [ "$tail_logs" = "true" ]; then
          compose_logs "$compose_cmd"
        fi
      fi
      ;;
    status)
      if [ "$has_compose" = "false" ]; then
        print_error "Docker Compose not found; status is only available in Docker mode"
        exit 1
      fi
      compose_status "$compose_cmd"
      ;;
    logs)
      if [ "$has_compose" = "false" ]; then
        print_error "Docker Compose not found; logs are only available in Docker mode"
        exit 1
      fi
      compose_logs "$compose_cmd"
      ;;
  esac
}

main "$@"
