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

ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
LOCAL_FILE="${SPOON_INFISICAL_LOCAL_FILE:-$ROOT_DIR/.local/infisical.env}"
INFISICAL_DIR="${HOME}/.infisical"
CONFIG_FILE="$INFISICAL_DIR/infisical-config.json"
LOCK_FILE="$INFISICAL_DIR/.switch.lock"

usage() {
  printf 'usage: infisical-account <ensure|status>\n' >&2
  exit 2
}

require_command() {
  local command_name="$1"
  if ! command -v "$command_name" >/dev/null 2>&1; then
    printf 'infisical-account: required command not found: %s\n' "$command_name" >&2
    exit 1
  fi
}

require_dependencies() {
  require_command infisical
  require_command jq
  require_command flock
}

require_config() {
  if [[ ! -f "$CONFIG_FILE" ]]; then
    printf 'infisical-account: Infisical config not found at ~/.infisical/infisical-config.json.\n' >&2
    printf 'Run: infisical login\n' >&2
    exit 1
  fi
}

logged_in_user_count() {
  jq -er '
    if (.loggedInUsers | type) == "array" then
      .loggedInUsers | length
    else
      error("loggedInUsers missing")
    end
  ' "$CONFIG_FILE" 2>/dev/null || {
    printf 'infisical-account: Infisical config is invalid or missing loggedInUsers.\n' >&2
    printf 'Run: infisical login\n' >&2
    exit 1
  }
}

print_logged_in_accounts() {
  jq -r '(.loggedInUsers // [])[] | "  - \(.email)"' "$CONFIG_FILE"
}

trim() {
  local value="$1"
  value="${value#"${value%%[![:space:]]*}"}"
  value="${value%"${value##*[![:space:]]}"}"
  printf '%s' "$value"
}

strip_matching_quotes() {
  local value="$1"
  case "$value" in
    \"*\") value="${value#\"}"; value="${value%\"}" ;;
    \'*\') value="${value#\'}"; value="${value%\'}" ;;
  esac
  printf '%s' "$value"
}

read_project_email() {
  if [[ ! -f "$LOCAL_FILE" ]]; then
    printf 'infisical-account: multiple Infisical users are logged in, but .local/infisical.env is missing.\n\n' >&2
    printf 'Create it with:\n' >&2
    printf '  mkdir -p .local\n' >&2
    printf '  printf "INFISICAL_EMAIL=you@example.com\\n" > .local/infisical.env\n\n' >&2
    printf 'Logged-in accounts:\n' >&2
    print_logged_in_accounts >&2
    exit 1
  fi

  local email=""
  local line key value
  while IFS= read -r line || [[ -n "$line" ]]; do
    line="$(trim "$line")"
    case "$line" in
      ''|'#'*) continue ;;
    esac
    key="$(trim "${line%%=*}")"
    value="${line#*=}"
    if [[ "$key" == "$line" ]]; then
      continue
    fi
    value="$(strip_matching_quotes "$(trim "$value")")"
    if [[ "$key" == "INFISICAL_EMAIL" ]]; then
      email="$value"
      break
    fi
  done < "$LOCAL_FILE"

  if [[ -z "$email" ]]; then
    printf 'infisical-account: .local/infisical.env must contain INFISICAL_EMAIL=you@example.com.\n' >&2
    exit 1
  fi

  printf '%s' "$email"
}

domain_for_email() {
  local email="$1"
  jq -er --arg email "$email" '
    first((.loggedInUsers // [])[] | select(.email == $email) | .domain)
  ' "$CONFIG_FILE"
}

switch_to_email() {
  local email="$1"
  local domain
  domain="$(domain_for_email "$email")" || {
    printf 'infisical-account: configured Infisical user is not logged in locally: %s\n' "$email" >&2
    printf 'Run: infisical login\n' >&2
    exit 1
  }

  local tmp
  tmp="$(mktemp "$INFISICAL_DIR/infisical-config.XXXXXX")"
  jq --arg email "$email" --arg domain "$domain" '
    .loggedInUserEmail = $email
    | .LoggedInUserDomain = $domain
  ' "$CONFIG_FILE" > "$tmp"
  chmod 600 "$tmp"
  mv "$tmp" "$CONFIG_FILE"
}

ensure_account() {
  require_dependencies
  require_config

  (
    flock 9
    local count
    count="$(logged_in_user_count)"
    if [[ "$count" -eq 0 ]]; then
      printf 'infisical-account: no local Infisical users are logged in.\n' >&2
      printf 'Run: infisical login\n' >&2
      exit 1
    fi
    if [[ "$count" -eq 1 ]]; then
      exit 0
    fi

    local email
    email="$(read_project_email)"
    switch_to_email "$email"
  ) 9>"$LOCK_FILE"
}

status() {
  ensure_account
  local count configured active
  count="$(logged_in_user_count)"
  configured="not required"
  if [[ -f "$LOCAL_FILE" ]]; then
    configured="$(read_project_email 2>/dev/null || printf 'invalid')"
  fi
  active="$(jq -r '.loggedInUserEmail // "unknown"' "$CONFIG_FILE")"

  printf 'Infisical accounts logged in: %s\n' "$count"
  printf 'Configured project email: %s\n' "$configured"
  printf 'Active account after ensure: %s\n' "$active"
}

case "${1:-}" in
  ensure) ensure_account ;;
  status) status ;;
  *) usage ;;
esac
