#!/usr/bin/env bash
# =============================================================================
# Maree-CareFlow - Docker Installer (zero-friction)
# =============================================================================
# Usage: bash stack-docker/install.sh
# Requires: Docker 24+ and Docker Compose v2 (plugin)
# =============================================================================
set -euo pipefail

LOG=/tmp/careflow-docker-install.log
exec > >(tee -a "$LOG") 2>&1

# ── Colour helpers ────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'

ok()   { echo -e "${GREEN}  ✔  $*${NC}"; }
info() { echo -e "${CYAN}  ℹ  $*${NC}"; }
warn() { echo -e "${YELLOW}  ⚠  $*${NC}"; }
err()  { echo -e "${RED}  ✘  $*${NC}" >&2; exit 1; }
step() { echo -e "\n${BOLD}${CYAN}━━━  $*  ━━━${NC}"; }

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

# ── Banner ────────────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}${CYAN}"
echo "  ╔══════════════════════════════════════════════════════════════╗"
echo "  ║          Maree-CareFlow - Docker Installer                  ║"
echo "  ║          Zero-friction • recommended for most users         ║"
echo "  ╚══════════════════════════════════════════════════════════════╝"
echo -e "${NC}"

# ── Check Docker ──────────────────────────────────────────────────────────────
check_docker() {
  step "Checking Docker prerequisites"

  if ! command -v docker &>/dev/null; then
    err "Docker is not installed.

  Install Docker Engine (Ubuntu/Debian):
    curl -fsSL https://get.docker.com | bash
    sudo usermod -aG docker \$USER   # then log out and back in

  Install Docker Desktop (Mac/Windows):
    https://www.docker.com/products/docker-desktop/

  Then re-run this script."
  fi

  DOCKER_VER=$(docker version --format '{{.Server.Version}}' 2>/dev/null || echo "unknown")
  ok "Docker Engine: ${DOCKER_VER}"

  # Check Docker is running
  docker info &>/dev/null || err "Docker daemon is not running. Start it with: sudo systemctl start docker"

  # Check Docker Compose v2 (plugin)
  if docker compose version &>/dev/null; then
    COMPOSE_VER=$(docker compose version --short 2>/dev/null || echo "v2")
    ok "Docker Compose: ${COMPOSE_VER}"
  elif command -v docker-compose &>/dev/null; then
    COMPOSE_VER=$(docker-compose version --short 2>/dev/null || echo "v1")
    warn "Found legacy docker-compose v1 (${COMPOSE_VER}). Docker Compose v2 plugin is recommended."
    warn "Install: sudo apt install docker-compose-plugin  OR  pip install docker-compose"
    # Override compose command to use legacy binary
    DOCKER_COMPOSE="docker-compose"
  else
    err "Docker Compose not found.

  Install Docker Compose v2 plugin:
    sudo apt install docker-compose-plugin       # Ubuntu/Debian
    sudo dnf install docker-compose-plugin       # RHEL/Fedora

  Then re-run this script."
  fi

  DOCKER_COMPOSE="${DOCKER_COMPOSE:-docker compose}"
}

# ── Gather config ─────────────────────────────────────────────────────────────
gather_config() {
  step "Configuration - 4 questions"

  echo ""
  echo -e "  ${CYAN}Press Enter to accept the default shown in [brackets]${NC}"
  echo ""

  # Question 1: Domain
  read -r -p "  Domain name [careflow.local]: " DOMAIN_INPUT
  DOMAIN="${DOMAIN_INPUT:-careflow.local}"
  ok "Domain: ${DOMAIN}"

  # Question 2: Admin email
  while true; do
    read -r -p "  Admin email address: " ADMIN_EMAIL
    [[ -n "$ADMIN_EMAIL" ]] && break
    warn "Admin email cannot be empty."
  done
  ok "Admin email: ${ADMIN_EMAIL}"

  # Question 3: SMTP host (optional)
  echo ""
  echo -e "  ${CYAN}SMTP is used to send password reset and notification emails.${NC}"
  echo -e "  ${CYAN}Leave blank to skip (you can configure this later in .env).${NC}"
  read -r -p "  SMTP host [skip]: " SMTP_HOST
  SMTP_HOST="${SMTP_HOST:-}"

  if [[ -n "$SMTP_HOST" ]]; then
    read -r -p "  SMTP port [587]: " SMTP_PORT_INPUT
    SMTP_PORT="${SMTP_PORT_INPUT:-587}"
    read -r -p "  SMTP username [${ADMIN_EMAIL}]: " SMTP_USER_INPUT
    SMTP_USER="${SMTP_USER_INPUT:-${ADMIN_EMAIL}}"
    ok "SMTP: ${SMTP_HOST}:${SMTP_PORT}"
  else
    SMTP_PORT="587"
    SMTP_USER="${ADMIN_EMAIL}"
    warn "SMTP skipped - email sending disabled until configured in .env"
  fi

  # Question 4: Pull Ollama models
  echo ""
  echo -e "  ${CYAN}Ollama AI models enable clinical note summarisation and AI reports.${NC}"
  echo -e "  ${YELLOW}  Models are 4-8 GB each and take time to download.${NC}"
  read -r -p "  Pull Ollama AI models now? [n]: " PULL_MODELS_INPUT
  PULL_MODELS="${PULL_MODELS_INPUT:-n}"

  echo ""
  echo -e "${BOLD}  Configuration summary:${NC}"
  echo "  ┌─────────────────────────────────────────────┐"
  echo "  │  Domain     : ${DOMAIN}"
  echo "  │  Admin email: ${ADMIN_EMAIL}"
  echo "  │  SMTP host  : ${SMTP_HOST:-<disabled>}"
  echo "  │  Pull models: ${PULL_MODELS}"
  echo "  └─────────────────────────────────────────────┘"
  echo ""
  read -r -p "  Press Enter to continue (Ctrl+C to cancel): "
}

# ── Auto-generate all secrets ─────────────────────────────────────────────────
generate_secrets() {
  step "Generating secrets (auto)"

  SECRETS_DIR="${REPO_ROOT}/secrets"
  mkdir -p "$SECRETS_DIR"

  # JWT RS256 keypair
  if [[ ! -f "${SECRETS_DIR}/jwt_private_key.pem" ]]; then
    openssl genrsa -out "${SECRETS_DIR}/jwt_private_key.pem" 2048 2>/dev/null
    openssl rsa \
      -in "${SECRETS_DIR}/jwt_private_key.pem" \
      -pubout \
      -out "${SECRETS_DIR}/jwt_public_key.pem" 2>/dev/null
    chmod 600 "${SECRETS_DIR}/jwt_private_key.pem"
    chmod 644 "${SECRETS_DIR}/jwt_public_key.pem"
    ok "JWT RS256 key pair generated"
  else
    ok "JWT keys already exist - reusing"
  fi

  # PostgreSQL password
  if [[ ! -f "${SECRETS_DIR}/postgres_password.txt" ]]; then
    openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c32 \
      > "${SECRETS_DIR}/postgres_password.txt"
    ok "PostgreSQL password generated"
  else
    ok "DB password already exists - reusing"
  fi
  DB_PASSWORD=$(cat "${SECRETS_DIR}/postgres_password.txt")

  # MinIO credentials
  if [[ ! -f "${SECRETS_DIR}/minio_access_key.txt" ]]; then
    openssl rand -base64 16 | tr -dc 'a-zA-Z0-9' | head -c20 \
      > "${SECRETS_DIR}/minio_access_key.txt"
    openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c40 \
      > "${SECRETS_DIR}/minio_secret_key.txt"
    ok "MinIO credentials generated"
  else
    ok "MinIO credentials already exist - reusing"
  fi
  MINIO_ACCESS=$(cat "${SECRETS_DIR}/minio_access_key.txt")
  MINIO_SECRET=$(cat "${SECRETS_DIR}/minio_secret_key.txt")

  # TOTP encryption key
  if [[ ! -f "${SECRETS_DIR}/totp_encryption_key.txt" ]]; then
    openssl rand -base64 32 > "${SECRETS_DIR}/totp_encryption_key.txt"
    ok "TOTP encryption key generated"
  else
    ok "TOTP key already exists - reusing"
  fi
  TOTP_KEY=$(cat "${SECRETS_DIR}/totp_encryption_key.txt")

  # OAuth encryption key
  if [[ ! -f "${SECRETS_DIR}/oauth_encryption_key.txt" ]]; then
    openssl rand -base64 32 > "${SECRETS_DIR}/oauth_encryption_key.txt"
    ok "OAuth encryption key generated"
  else
    ok "OAuth key already exists - reusing"
  fi
  OAUTH_KEY=$(cat "${SECRETS_DIR}/oauth_encryption_key.txt")

  # PHI field-encryption key (Fernet; compose passes it via .env)
  if [[ ! -f "${SECRETS_DIR}/phi_encryption_key.txt" ]]; then
    openssl rand -base64 32 > "${SECRETS_DIR}/phi_encryption_key.txt"
    ok "PHI encryption key generated"
  else
    ok "PHI key already exists - reusing"
  fi
  PHI_KEY=$(cat "${SECRETS_DIR}/phi_encryption_key.txt")

  # SMTP password secret file - docker-compose declares this secret, so the
  # file must exist even when SMTP is skipped (fill it in later to enable email)
  if [[ ! -f "${SECRETS_DIR}/smtp_password.txt" ]]; then
    touch "${SECRETS_DIR}/smtp_password.txt"
    chmod 600 "${SECRETS_DIR}/smtp_password.txt"
    ok "SMTP password placeholder created (set it later to enable email)"
  fi

  # Secure the secrets directory
  chmod 700 "${SECRETS_DIR}"
  info "Secrets written to: ${SECRETS_DIR}/"
  warn "Keep the secrets/ directory private - never commit it to version control."
}

# ── Write .env ────────────────────────────────────────────────────────────────
write_env() {
  step "Writing .env"

  ENV_FILE="${REPO_ROOT}/.env"
  ENV_EXAMPLE="${REPO_ROOT}/.env.example"

  if [[ -f "$ENV_EXAMPLE" ]]; then
    cp "$ENV_EXAMPLE" "$ENV_FILE"
    info "Copied .env.example to .env"
  else
    info ".env.example not found - writing .env from scratch"
    touch "$ENV_FILE"
  fi

  # Helper: set or replace a variable in .env
  set_env() {
    local key="$1" val="$2"
    if grep -q "^${key}=" "$ENV_FILE" 2>/dev/null; then
      # Replace existing line (use | as delimiter to avoid issues with slashes)
      sed -i "s|^${key}=.*|${key}=${val}|" "$ENV_FILE"
    else
      echo "${key}=${val}" >> "$ENV_FILE"
    fi
  }

  set_env "CAREFLOW_DOMAIN"   "${DOMAIN}"
  set_env "ALLOWED_ORIGINS"   "https://${DOMAIN},http://${DOMAIN}"
  set_env "ADMIN_EMAIL"       "${ADMIN_EMAIL}"
  set_env "SMTP_HOST"         "${SMTP_HOST}"
  set_env "SMTP_PORT"         "${SMTP_PORT}"
  set_env "SMTP_USER"         "${SMTP_USER}"
  set_env "ENVIRONMENT"       "production"

  set_env "POSTGRES_PASSWORD" "${DB_PASSWORD}"
  set_env "MINIO_ROOT_USER"   "${MINIO_ACCESS}"
  set_env "MINIO_ROOT_PASSWORD" "${MINIO_SECRET}"
  set_env "TOTP_ENCRYPTION_KEY" "${TOTP_KEY}"
  set_env "OAUTH_ENCRYPTION_KEY" "${OAUTH_KEY}"
  set_env "PHI_ENCRYPTION_KEY"   "${PHI_KEY}"

  chmod 600 "$ENV_FILE"
  ok ".env written: ${ENV_FILE}"
}

# ── docker compose up ─────────────────────────────────────────────────────────
start_services() {
  step "Starting Maree-CareFlow services"

  cd "$REPO_ROOT"

  info "Pulling latest images..."
  $DOCKER_COMPOSE pull --quiet 2>/dev/null || info "Some images will be built locally"

  info "Starting containers..."
  $DOCKER_COMPOSE up -d --build

  ok "Containers started"
}

# ── Health check ──────────────────────────────────────────────────────────────
health_check() {
  step "Waiting for application to be ready"

  HEALTH_URL="http://localhost/health"
  MAX_ATTEMPTS=30
  WAIT_SECS=5
  ATTEMPT=0

  info "Polling ${HEALTH_URL} (up to $((MAX_ATTEMPTS * WAIT_SECS))s)..."

  until curl -sf "$HEALTH_URL" &>/dev/null; do
    ATTEMPT=$((ATTEMPT + 1))
    if [[ $ATTEMPT -ge $MAX_ATTEMPTS ]]; then
      echo ""
      warn "Health check did not pass after $((MAX_ATTEMPTS * WAIT_SECS)) seconds."
      warn "Showing last 20 lines of container logs:"
      echo ""
      cd "$REPO_ROOT"
      $DOCKER_COMPOSE logs --tail=20 2>/dev/null || true
      echo ""
      warn "The containers may still be starting up."
      warn "Check status:  docker compose ps"
      warn "Full logs:     docker compose logs -f"
      return 1
    fi
    printf "  ${CYAN}  [%2d/%d] waiting...${NC}\r" "$ATTEMPT" "$MAX_ATTEMPTS"
    sleep "$WAIT_SECS"
  done

  echo ""
  ok "Application is healthy at ${HEALTH_URL}"
}

# ── Pull Ollama models ────────────────────────────────────────────────────────
pull_models() {
  if [[ "${PULL_MODELS,,}" == "y" || "${PULL_MODELS,,}" == "yes" ]]; then
    step "Pulling Ollama AI models (this may take several minutes)"
    cd "$REPO_ROOT"

    info "Pulling qwen2.5:7b (language model, ~4.7 GB)..."
    $DOCKER_COMPOSE exec -T ollama ollama pull qwen2.5:7b || \
      warn "Could not pull qwen2.5:7b - retry with: docker compose exec ollama ollama pull qwen2.5:7b"

    info "Pulling nomic-embed-text (embeddings, ~274 MB)..."
    $DOCKER_COMPOSE exec -T ollama ollama pull nomic-embed-text || \
      warn "Could not pull nomic-embed-text - retry manually"

    ok "AI models ready"
  else
    info "Skipping AI model download."
    info "Pull later with: docker compose exec ollama ollama pull qwen2.5:7b"
  fi
}

# ── Final summary ─────────────────────────────────────────────────────────────
print_summary() {
  PROTO="http"
  if [[ "$DOMAIN" != "careflow.local" && "$DOMAIN" != "localhost" ]]; then
    PROTO="https"
  fi

  echo ""
  echo -e "${BOLD}${GREEN}"
  echo "  ╔══════════════════════════════════════════════════════════════╗"
  echo "  ║       Maree-CareFlow is running!                            ║"
  echo "  ╚══════════════════════════════════════════════════════════════╝"
  echo -e "${NC}"
  echo -e "  ${BOLD}Application URL:${NC}  ${PROTO}://${DOMAIN}/"
  echo -e "  ${BOLD}API Docs:${NC}         ${PROTO}://${DOMAIN}/api/v1/docs"
  echo -e "  ${BOLD}Admin setup:${NC}      ${PROTO}://${DOMAIN}/admin"
  echo ""
  echo -e "  ${BOLD}Admin email:${NC}      ${ADMIN_EMAIL}"
  echo -e "  ${BOLD}Config file:${NC}      ${REPO_ROOT}/.env"
  echo -e "  ${BOLD}Secrets dir:${NC}      ${REPO_ROOT}/secrets/"
  echo -e "  ${BOLD}Install log:${NC}      ${LOG}"
  echo ""
  echo -e "  ${CYAN}Useful commands:${NC}"
  echo "    docker compose ps                 # container status"
  echo "    docker compose logs -f            # follow all logs"
  echo "    docker compose logs -f careflow-api  # API logs only"
  echo "    docker compose restart careflow-api  # restart API"
  echo "    docker compose down               # stop everything"
  echo "    docker compose up -d              # start again"
  echo ""
  echo -e "  ${CYAN}Support:${NC}"
  echo "    https://github.com/supportcall/Maree-CareFlow-2026/issues"
  echo ""
}

# ── Parse arguments ────────────────────────────────────────────────────────────
UPGRADE_MODE=0
for arg in "$@"; do
  case "$arg" in
    --upgrade) UPGRADE_MODE=1 ;;
    -h|--help)
      echo "Usage: bash $0 [--upgrade]"
      echo ""
      echo "  (no flag)   Fresh install, or a safe re-run. Every secret in secrets/"
      echo "              (including the PHI encryption key) is reused if already"
      echo "              present, never rotated, so stored data stays readable."
      echo "  --upgrade   Update an existing install in place: pull the new images,"
      echo "              rebuild, run database migrations and restart the containers,"
      echo "              reusing the existing .env and secrets unchanged."
      exit 0 ;;
    *) err "Unknown argument: $arg (try --help)" ;;
  esac
done

# ── Main ──────────────────────────────────────────────────────────────────────
main() {
  check_docker
  if [[ "$UPGRADE_MODE" -eq 1 ]]; then
    [[ -f "${REPO_ROOT}/.env" ]] || err "--upgrade needs an existing install, but ${REPO_ROOT}/.env was not found. Run a fresh install first."
    step "Upgrade mode - reusing existing .env and secrets (nothing regenerated)"
    DOMAIN="$(sed -n 's/^CAREFLOW_DOMAIN=//p' "${REPO_ROOT}/.env" | head -n1)"; DOMAIN="${DOMAIN:-careflow.local}"
    ADMIN_EMAIL="$(sed -n 's/^ADMIN_EMAIL=//p' "${REPO_ROOT}/.env" | head -n1)"
    PULL_MODELS=n
    # generate_secrets is idempotent: it fills in any secret file that is missing
    # but NEVER rewrites one that already exists (incl. the PHI encryption key).
    generate_secrets
    ok "Existing configuration preserved (Domain: ${DOMAIN})"
  else
    gather_config
    generate_secrets
    write_env
  fi
  start_services
  if health_check; then
    ok "Health check passed"
  else
    warn "Health check failed - but continuing. Check logs above."
  fi
  pull_models
  print_summary
}

main "$@"
