#!/bin/bash
#
# Contract Lucidity — EasyPanel Deployment Script
# Deploys a fresh CL instance to an EasyPanel server.
#
# Usage: ./deploy-easypanel.sh
#
# Requirements:
#   - curl, jq installed
#   - EasyPanel server with API access + GitHub token configured
#   - Source code in a GitHub repo accessible by EasyPanel
#

set -u  # Fail on undefined vars only — NOT on command errors (deploys timeout)

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

log()  { echo -e "${BLUE}[CL]${NC} $1"; }
ok()   { echo -e "${GREEN}[OK]${NC} $1"; }
warn() { echo -e "${YELLOW}[!!]${NC} $1"; }
fail() { echo -e "${RED}[FAIL]${NC} $1"; exit 1; }

# ─── Check dependencies ───
for cmd in curl jq; do
  if ! command -v "$cmd" &>/dev/null; then
    fail "'$cmd' is required but not installed. Install it and try again."
  fi
done

# ─── Helper: tRPC API calls ───
ep_get() {
  local procedure="$1"
  local url="$EP_URL/api/trpc/$procedure?input=%7B%22json%22%3A%7B%7D%7D"
  local response
  response=$(curl -s --max-time 30 "$url" \
    -H "Authorization: Bearer $EP_API_KEY" \
    -H "Content-Type: application/json" 2>/dev/null) || true
  if [ -z "$response" ]; then
    fail "API GET failed: $procedure — no response"
  fi
  echo "$response"
}

ep_post() {
  local procedure="$1"
  local json_input="$2"
  local url="$EP_URL/api/trpc/$procedure"
  local response http_code body

  response=$(curl -s -w "\n%{http_code}" --max-time 120 -X POST "$url" \
    -H "Authorization: Bearer $EP_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"json\": $json_input}") || true

  http_code=$(echo "$response" | tail -1)
  body=$(echo "$response" | sed '$d')

  if [ "$http_code" = "524" ] || [ "$http_code" = "000" ]; then
    warn "Timeout on $procedure — likely succeeded. Continuing..."
    return 0
  fi

  local error_msg
  error_msg=$(echo "$body" | jq -r '.error.json.message // empty' 2>/dev/null)
  if [ -n "$error_msg" ]; then
    fail "API error on $procedure: $error_msg"
  fi

  echo "$body"
}

# ═══════════════════════════════════════════════════
#  STEP 1: GATHER CONFIGURATION
# ═══════════════════════════════════════════════════
echo ""
echo -e "${BLUE}═══════════════════════════════════════════════════${NC}"
echo -e "${BLUE}  Contract Lucidity — EasyPanel Deployment${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════${NC}"
echo ""

read -p "EasyPanel URL (e.g., https://easypanel.example.com): " EP_URL
EP_URL="${EP_URL%/}"
read -p "EasyPanel API Key: " EP_API_KEY

if [ -z "$EP_URL" ] || [ -z "$EP_API_KEY" ]; then
  fail "EasyPanel URL and API Key are required."
fi

# Validate connection
log "Connecting to EasyPanel..."
SD_RESPONSE=$(ep_get "settings.getServiceDomain")
SERVICE_DOMAIN=$(echo "$SD_RESPONSE" | jq -r '.result.data.json.defaultServiceDomain' 2>/dev/null)
if [ -z "$SERVICE_DOMAIN" ] || [ "$SERVICE_DOMAIN" = "null" ]; then
  fail "Could not connect to EasyPanel. Check URL and API key."
fi
ok "Connected to EasyPanel (domain: $SERVICE_DOMAIN)"

# Get server IP
SERVER_IP=$(ep_get "settings.getServerIp" | jq -r '.result.data.json // empty' 2>/dev/null || echo "")
if [ -z "$SERVER_IP" ] || [ "$SERVER_IP" = "null" ]; then
  SERVER_IP="unknown"
fi
ok "Server IP: $SERVER_IP"

echo ""
read -p "Deployment type — client or product? [client/product] (default: client): " DEPLOY_TYPE
DEPLOY_TYPE="${DEPLOY_TYPE:-client}"
read -p "Project name [contract-lucidity]: " PROJECT
PROJECT="${PROJECT:-contract-lucidity}"

echo ""
echo -e "  ${BLUE}GitHub Repository:${NC}"
echo -e "  The source code must be in a GitHub repo that EasyPanel can access."
echo -e "  Make sure your GitHub token is configured in EasyPanel Settings → GitHub."
echo ""
read -p "GitHub owner (org or username): " GH_OWNER
if [ -z "$GH_OWNER" ]; then
  fail "GitHub owner is required."
fi
read -p "GitHub repo name [contract-lucidity]: " GH_REPO
GH_REPO="${GH_REPO:-contract-lucidity}"
read -p "GitHub branch [master]: " GH_BRANCH
GH_BRANCH="${GH_BRANCH:-master}"
read -p "Postgres password [cl_prod_2026!]: " PG_PASS
PG_PASS="${PG_PASS:-cl_prod_2026!}"
read -p "Admin email [admin@contractlucidity.local]: " ADMIN_EMAIL
ADMIN_EMAIL="${ADMIN_EMAIL:-admin@contractlucidity.local}"
read -p "Admin password [ChangeMeNow!2026]: " ADMIN_PASS
ADMIN_PASS="${ADMIN_PASS:-ChangeMeNow!2026}"

echo ""
echo -e "  ${BLUE}Pipeline concurrency — how many documents process simultaneously:${NC}"
echo ""
echo -e "  ┌──────────┬──────────┬─────────────┬───────────────────────────┐"
echo -e "  │ ${GREEN}Workers${NC}  │ ${GREEN}RAM${NC}      │ ${GREEN}CPUs${NC}        │ ${GREEN}Use Case${NC}                  │"
echo -e "  ├──────────┼──────────┼─────────────┼───────────────────────────┤"
echo -e "  │ 2        │ 4 GB     │ 2 vCPU      │ Demo / small team         │"
echo -e "  │ 4        │ 8 GB     │ 2-4 vCPU    │ Small firm (< 50 users)   │"
echo -e "  │ 8        │ 16 GB    │ 4-8 vCPU    │ Mid-size firm             │"
echo -e "  │ 16       │ 32 GB    │ 8+ vCPU     │ Am Law 200 / Enterprise   │"
echo -e "  │ 32+      │ 64 GB+   │ 16+ vCPU    │ Am Law 100 / High volume  │"
echo -e "  └──────────┴──────────┴─────────────┴───────────────────────────┘"
echo ""
read -p "Pipeline concurrency [2]: " CELERY_CONCURRENCY
CELERY_CONCURRENCY="${CELERY_CONCURRENCY:-2}"

echo ""
echo -e "  ${BLUE}External storage mount (e.g., Azure Files, S3, NFS):${NC}"
echo -e "  If you have mounted external storage on the server (recommended),"
echo -e "  enter the path here. Example: /mnt/cl-storage"
echo ""
read -p "External storage path [Enter to skip]: " EXTERNAL_STORAGE
EXTERNAL_STORAGE="${EXTERNAL_STORAGE:-}"

if [ -z "$EXTERNAL_STORAGE" ]; then
  echo ""
  warn "═══════════════════════════════════════════════════════════════"
  warn "  No external storage configured."
  warn "  Documents will be stored on the server's local disk."
  warn "  This WILL fill the disk in a production deployment."
  warn "  NOT RECOMMENDED PAST 15-30 DAYS MAX."
  warn "  For production: mount Azure Files / S3 / NFS at /mnt/cl-storage"
  warn "═══════════════════════════════════════════════════════════════"
  echo ""
  read -p "Continue without external storage? [y/N]: " STORAGE_CONFIRM
  STORAGE_CONFIRM="${STORAGE_CONFIRM:-N}"
  if [[ ! "$STORAGE_CONFIRM" =~ ^[Yy] ]]; then
    fail "Deployment cancelled. Mount external storage and try again."
  fi
fi

JWT_SECRET="cl-$(head -c 24 /dev/urandom | xxd -p 2>/dev/null || date +%s)"
FRONTEND_HOST="cl-frontend-${PROJECT}.${SERVICE_DOMAIN}"

echo ""
log "Configuration:"
log "  Server:    $EP_URL ($SERVER_IP)"
log "  Project:   $PROJECT"
log "  Type:      $DEPLOY_TYPE"
log "  Branch:    $GH_BRANCH"
log "  Admin:     $ADMIN_EMAIL"
log "  URL:       https://$FRONTEND_HOST"
log "  Workers:   $CELERY_CONCURRENCY concurrent"
if [ -n "$EXTERNAL_STORAGE" ]; then
  log "  Storage:   $EXTERNAL_STORAGE (external)"
else
  log "  Storage:   ${YELLOW}local disk (temporary — not for production)${NC}"
fi
echo ""
read -p "Proceed with deployment? [Y/n]: " CONFIRM
CONFIRM="${CONFIRM:-Y}"
if [[ ! "$CONFIRM" =~ ^[Yy] ]]; then
  fail "Deployment cancelled."
fi

# ═══════════════════════════════════════════════════
#  STEP 2: CREATE INFRASTRUCTURE
# ═══════════════════════════════════════════════════
echo ""
log "═══ Creating Infrastructure ═══"

# Project
log "Checking project '$PROJECT'..."
PROJECT_EXISTS=$(ep_get "projects.listProjects" | jq -r '.result.data.json[].name // empty' 2>/dev/null | grep -x "$PROJECT" || true)
if [ -z "$PROJECT_EXISTS" ]; then
  ep_post "projects.createProject" "{\"name\": \"$PROJECT\"}" > /dev/null
  ok "Project '$PROJECT' created"
else
  ok "Project '$PROJECT' exists"
fi

# Databases
log "Creating PostgreSQL (pgvector)..."
PG_RESULT=$(ep_post "services.postgres.createService" "{\"projectName\": \"$PROJECT\", \"serviceName\": \"cl-db\", \"image\": \"pgvector/pgvector:pg16\", \"password\": \"$PG_PASS\"}")
PG_DB=$(echo "$PG_RESULT" | jq -r '.result.data.json.databaseName // empty' 2>/dev/null)
PG_DB="${PG_DB:-$PROJECT}"
ok "PostgreSQL (db: $PG_DB)"

log "Creating Redis..."
REDIS_RESULT=$(ep_post "services.redis.createService" "{\"projectName\": \"$PROJECT\", \"serviceName\": \"cl-redis\"}")
REDIS_PASS=$(echo "$REDIS_RESULT" | jq -r '.result.data.json.password // empty' 2>/dev/null)
if [ -z "$REDIS_PASS" ]; then
  warn "Could not read Redis password"
  read -p "Enter Redis password from EasyPanel: " REDIS_PASS
fi
ok "Redis created"

log "Waiting 10s for databases..."
sleep 10

# ═══════════════════════════════════════════════════
#  STEP 3: CREATE APP SERVICES
# ═══════════════════════════════════════════════════
log "═══ Creating App Services ═══"

# Determine storage mount strategy
if [ -n "$EXTERNAL_STORAGE" ]; then
  # External storage: both services bind mount to the same external path
  BACKEND_MOUNT="{\"type\": \"bind\", \"hostPath\": \"$EXTERNAL_STORAGE\", \"mountPath\": \"/data/storage\"}"
  WORKER_MOUNT="{\"type\": \"bind\", \"hostPath\": \"$EXTERNAL_STORAGE\", \"mountPath\": \"/data/storage\"}"
  STORAGE_DESC="external ($EXTERNAL_STORAGE)"
else
  # Local storage: backend gets a named volume, worker bind-mounts to backend's volume dir
  BACKEND_MOUNT="{\"type\": \"volume\", \"name\": \"cl-storage\", \"mountPath\": \"/data/storage\"}"
  WORKER_BIND_PATH="/etc/easypanel/projects/${PROJECT}/cl-backend/volumes/cl-storage"
  WORKER_MOUNT="{\"type\": \"bind\", \"hostPath\": \"$WORKER_BIND_PATH\", \"mountPath\": \"/data/storage\"}"
  STORAGE_DESC="local volume (bind to backend)"
fi

log "Creating cl-backend..."
ep_post "services.app.createService" "{
  \"projectName\": \"$PROJECT\",
  \"serviceName\": \"cl-backend\",
  \"source\": {
    \"type\": \"github\",
    \"owner\": \"$GH_OWNER\",
    \"repo\": \"$GH_REPO\",
    \"ref\": \"$GH_BRANCH\",
    \"path\": \"/backend\",
    \"autoDeploy\": false
  },
  \"build\": {\"type\": \"dockerfile\", \"file\": \"Dockerfile\"},
  \"mounts\": [$BACKEND_MOUNT]
}" > /dev/null
ok "cl-backend created"

log "Creating cl-worker..."
ep_post "services.app.createService" "{
  \"projectName\": \"$PROJECT\",
  \"serviceName\": \"cl-worker\",
  \"source\": {
    \"type\": \"github\",
    \"owner\": \"$GH_OWNER\",
    \"repo\": \"$GH_REPO\",
    \"ref\": \"$GH_BRANCH\",
    \"path\": \"/backend\",
    \"autoDeploy\": false
  },
  \"build\": {\"type\": \"dockerfile\", \"file\": \"Dockerfile.worker\"},
  \"mounts\": [$WORKER_MOUNT]
}" > /dev/null
ok "cl-worker created (storage: $STORAGE_DESC)"

# Frontend — no shared volume needed
log "Creating cl-frontend..."
ep_post "services.app.createService" "{
  \"projectName\": \"$PROJECT\",
  \"serviceName\": \"cl-frontend\",
  \"source\": {
    \"type\": \"github\",
    \"owner\": \"$GH_OWNER\",
    \"repo\": \"$GH_REPO\",
    \"ref\": \"$GH_BRANCH\",
    \"path\": \"/frontend\",
    \"autoDeploy\": false
  },
  \"build\": {\"type\": \"dockerfile\", \"file\": \"Dockerfile\"}
}" > /dev/null
ok "cl-frontend created"

# ═══════════════════════════════════════════════════
#  STEP 4: CONFIGURE (env vars, commands, domains)
# ═══════════════════════════════════════════════════
log "═══ Configuring Services ═══"

log "cl-backend env..."
ep_post "services.app.updateEnv" "{
  \"projectName\": \"$PROJECT\",
  \"serviceName\": \"cl-backend\",
  \"env\": \"APP_NAME=Contract Lucidity\nAPP_ENV=production\nLOG_LEVEL=info\nPOSTGRES_USER=postgres\nPOSTGRES_PASSWORD=$PG_PASS\nPOSTGRES_DB=$PG_DB\nPOSTGRES_HOST=${PROJECT}_cl-db\nPOSTGRES_PORT=5432\nREDIS_HOST=${PROJECT}_cl-redis\nREDIS_PORT=6379\nREDIS_URL=redis://:${REDIS_PASS}@${PROJECT}_cl-redis:6379/0\nCELERY_BROKER_URL=redis://:${REDIS_PASS}@${PROJECT}_cl-redis:6379/0\nCELERY_RESULT_BACKEND=redis://:${REDIS_PASS}@${PROJECT}_cl-redis:6379/1\nJWT_SECRET_KEY=$JWT_SECRET\nJWT_ALGORITHM=HS256\nJWT_ACCESS_TOKEN_EXPIRE_MINUTES=1440\nJWT_REFRESH_TOKEN_EXPIRE_DAYS=30\nSTORAGE_PATH=/data/storage\nCONFIG_PATH=/data/config\nCORS_ORIGINS=*\nDEFAULT_ADMIN_EMAIL=$ADMIN_EMAIL\nDEFAULT_ADMIN_PASSWORD=$ADMIN_PASS\nMAX_UPLOAD_SIZE_MB=100\"
}" > /dev/null
ok "cl-backend env"

log "cl-worker env..."
ep_post "services.app.updateEnv" "{
  \"projectName\": \"$PROJECT\",
  \"serviceName\": \"cl-worker\",
  \"env\": \"APP_NAME=Contract Lucidity\nAPP_ENV=production\nLOG_LEVEL=info\nPOSTGRES_USER=postgres\nPOSTGRES_PASSWORD=$PG_PASS\nPOSTGRES_DB=$PG_DB\nPOSTGRES_HOST=${PROJECT}_cl-db\nPOSTGRES_PORT=5432\nREDIS_HOST=${PROJECT}_cl-redis\nREDIS_PORT=6379\nREDIS_URL=redis://:${REDIS_PASS}@${PROJECT}_cl-redis:6379/0\nCELERY_BROKER_URL=redis://:${REDIS_PASS}@${PROJECT}_cl-redis:6379/0\nCELERY_RESULT_BACKEND=redis://:${REDIS_PASS}@${PROJECT}_cl-redis:6379/1\nSTORAGE_PATH=/data/storage\nCONFIG_PATH=/data/config\nCELERY_CONCURRENCY=${CELERY_CONCURRENCY}\"
}" > /dev/null
ok "cl-worker env (concurrency: $CELERY_CONCURRENCY)"

FRONTEND_ENV="BACKEND_INTERNAL_URL=http://${PROJECT}_cl-backend:8000"
[ "$DEPLOY_TYPE" = "client" ] && FRONTEND_ENV="$FRONTEND_ENV\nNEXT_PUBLIC_DEPLOYMENT_MODE=client"
log "cl-frontend env ($DEPLOY_TYPE mode)..."
ep_post "services.app.updateEnv" "{
  \"projectName\": \"$PROJECT\",
  \"serviceName\": \"cl-frontend\",
  \"env\": \"$FRONTEND_ENV\"
}" > /dev/null
ok "cl-frontend env"

# Default domain
log "Creating default domain..."
ep_post "domains.createDomain" "{
  \"id\": \"cl-frontend-${PROJECT}\",
  \"host\": \"$FRONTEND_HOST\",
  \"https\": true,
  \"path\": \"/\",
  \"middlewares\": [],
  \"certificateResolver\": \"letsencrypt\",
  \"wildcard\": false,
  \"destinationType\": \"service\",
  \"serviceDestination\": {
    \"projectName\": \"$PROJECT\",
    \"serviceName\": \"cl-frontend\",
    \"protocol\": \"http\",
    \"port\": 3000
  }
}" > /dev/null
ok "https://$FRONTEND_HOST"

# ═══════════════════════════════════════════════════
#  STEP 5: DEPLOY
# ═══════════════════════════════════════════════════
echo ""
log "═══ Deploying (Docker builds — 3-5 min) ═══"

ep_post "services.app.deployService" "{\"projectName\": \"$PROJECT\", \"serviceName\": \"cl-backend\"}" > /dev/null
ok "cl-backend deploy triggered"

ep_post "services.app.deployService" "{\"projectName\": \"$PROJECT\", \"serviceName\": \"cl-worker\"}" > /dev/null
ok "cl-worker deploy triggered"

ep_post "services.app.deployService" "{\"projectName\": \"$PROJECT\", \"serviceName\": \"cl-frontend\"}" > /dev/null
ok "cl-frontend deploy triggered"

# ═══════════════════════════════════════════════════
#  STEP 6: HEALTH CHECK — wait for backend
# ═══════════════════════════════════════════════════
echo ""
log "Waiting for services to build and start..."
log "Polling https://$FRONTEND_HOST (up to 8 minutes)..."
echo ""

MAX_WAIT=480  # 8 minutes
ELAPSED=0
INTERVAL=15
APP_READY=false

while [ $ELAPSED -lt $MAX_WAIT ]; do
  # Check if frontend responds
  HTTP_CODE=$(curl -so /dev/null -w "%{http_code}" --max-time 5 "https://$FRONTEND_HOST" 2>/dev/null || echo "000")
  if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "307" ] || [ "$HTTP_CODE" = "302" ]; then
    # Frontend is up — now check if backend API responds through it
    API_CHECK=$(curl -sf --max-time 5 "https://$FRONTEND_HOST/api/health" 2>/dev/null || echo "")
    if echo "$API_CHECK" | grep -q "healthy" 2>/dev/null; then
      APP_READY=true
      break
    fi
  fi
  printf "\r  Building... %dm %02ds elapsed" $((ELAPSED / 60)) $((ELAPSED % 60))
  sleep $INTERVAL
  ELAPSED=$((ELAPSED + INTERVAL))
done
echo ""

if [ "$APP_READY" = true ]; then
  ok "Application is live and healthy!"
else
  warn "Application didn't respond within 8 minutes."
  warn "Check EasyPanel for build progress. It may still be building."
  warn "The URL will work once all services show green."
fi

# ═══════════════════════════════════════════════════
#  STEP 7: CUSTOM DOMAIN (after app is deployed)
# ═══════════════════════════════════════════════════
PRIMARY_URL="https://$FRONTEND_HOST"

# ═══════════════════════════════════════════════════
#  DONE
# ═══════════════════════════════════════════════════
echo ""
echo -e "${GREEN}═══════════════════════════════════════════════════${NC}"
echo -e "${GREEN}  Deployment Complete!${NC}"
echo -e "${GREEN}═══════════════════════════════════════════════════${NC}"
echo ""
echo -e "  ${BLUE}Application:${NC}  $PRIMARY_URL"
echo -e "  ${BLUE}Admin Email:${NC}  $ADMIN_EMAIL"
echo -e "  ${BLUE}Admin Pass:${NC}   $ADMIN_PASS"
echo -e "  ${BLUE}Type:${NC}         $DEPLOY_TYPE"
echo -e "  ${BLUE}EasyPanel:${NC}    $EP_URL"
echo ""
echo -e "  ${YELLOW}Next steps:${NC}"
echo -e "  1. Visit $PRIMARY_URL"
echo -e "  2. Login with admin credentials above"
echo -e "  3. Complete the setup wizard (configure AI provider)"
echo -e "  4. Upload a document to verify the pipeline works"
echo ""
