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

# ═══════════════════════════════════════════════════════════════════════
# ByteLyst Investment Trading - Production Deployment Script
# ═══════════════════════════════════════════════════════════════════════
# Usage: ./deploy-invttrdg.sh [--force] [--skip-health-check] [--no-cache]
#        (No arguments = interactive menu)
#
# Deployment Target: This VM is the single production environment
#   - No separate staging/development environments
#   - All deployments go directly to production on this VM
#
# What it does:
#   1. Dirty check: uncommitted changes, unpushed commits
#   2. Pull and rebase origin/main
#   3. Check @bytelyst package publication
#   4. Build and deploy Docker containers on this VM
#   5. Verify endpoints: https://api.bytelyst.com/invttrdg, https://invttrdg.bytelyst.com
#
# Options:
#   --force              Skip dirty checks and force deployment
#   --skip-health-check  Skip endpoint health verification
#   --no-cache           Build Docker images without cache
#
# Interactive Menu (no arguments):
#   1 - Normal deployment (with cache, with health checks)
#   2 - Force deployment (skip dirty checks, with cache)
#   3 - Skip health checks (with cache)
#   4 - No-cache build (force rebuild, with health checks)
#   5 - Force + No-cache (skip checks, force rebuild)
#   6 - Force + Skip health checks (skip both)
#   7 - All options: Force + Skip health + No-cache
# ═══════════════════════════════════════════════════════════════════════

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

log()  { echo -e "${CYAN}[$(date +%H:%M:%S)]${NC} $*"; }
ok()   { echo -e "${GREEN}[$(date +%H:%M:%S)] ✓${NC} $*"; }
warn() { echo -e "${YELLOW}[$(date +%H:%M:%S)] ⚠${NC} $*"; }
fail() { echo -e "${RED}[$(date +%H:%M:%S)] ✗${NC} $*"; exit 1; }

# ── Configuration ────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_DIR="${SCRIPT_DIR}/../learning_ai_invt_trdg"
cd "$SCRIPT_DIR"

FORCE=false
SKIP_HEALTH_CHECK=false
NO_CACHE=false
INTERACTIVE=true

while [[ $# -gt 0 ]]; do
  case "$1" in
    --force) FORCE=true; INTERACTIVE=false; shift ;;
    --skip-health-check) SKIP_HEALTH_CHECK=true; INTERACTIVE=false; shift ;;
    --no-cache) NO_CACHE=true; INTERACTIVE=false; shift ;;
    *) fail "Unknown option: $1" ;;
  esac
done

# ── Interactive Menu ────────────────────────────────────────────────────
if [ "$INTERACTIVE" = true ]; then
  echo ""
  echo -e "${CYAN}╔═══════════════════════════════════════════════════════════════╗${NC}"
  echo -e "${CYAN}║${NC}  ByteLyst Investment Trading - Deployment Options         ${CYAN}║${NC}"
  echo -e "${CYAN}╚═══════════════════════════════════════════════════════════════╝${NC}"
  echo ""
  echo -e "  ${GREEN}1${NC} - Normal deployment (with cache, with health checks)"
  echo -e "  ${GREEN}2${NC} - Force deployment (skip dirty checks, with cache)"
  echo -e "  ${GREEN}3${NC} - Skip health checks (with cache)"
  echo -e "  ${GREEN}4${NC} - No-cache build (force rebuild, with health checks)"
  echo -e "  ${GREEN}5${NC} - Force + No-cache (skip checks, force rebuild)"
  echo -e "  ${GREEN}6${NC} - Force + Skip health checks (skip both)"
  echo -e "  ${GREEN}7${NC} - All options: Force + Skip health + No-cache"
  echo ""
  read -r -p "Select option [1-7]: " choice

  case "$choice" in
    1)
      # Normal deployment (defaults)
      ;;
    2)
      FORCE=true
      ;;
    3)
      SKIP_HEALTH_CHECK=true
      ;;
    4)
      NO_CACHE=true
      ;;
    5)
      FORCE=true
      NO_CACHE=true
      ;;
    6)
      FORCE=true
      SKIP_HEALTH_CHECK=true
      ;;
    7)
      FORCE=true
      SKIP_HEALTH_CHECK=true
      NO_CACHE=true
      ;;
    *)
      fail "Invalid option. Please run again and select 1-7."
      ;;
  esac

  echo ""
  log "Selected configuration:"
  [ "$FORCE" = true ] && echo "  - Force deployment (skip dirty checks)"
  [ "$SKIP_HEALTH_CHECK" = true ] && echo "  - Skip health checks"
  [ "$NO_CACHE" = true ] && echo "  - No-cache build (force rebuild)"
  [ "$FORCE" = false ] && [ "$SKIP_HEALTH_CHECK" = false ] && [ "$NO_CACHE" = false ] && echo "  - Normal deployment"
  echo ""
  read -r -p "Press Enter to continue or Ctrl+C to cancel..."
  echo ""
fi

# ── Prerequisites ────────────────────────────────────────────────────
if [ ! -d "$REPO_DIR" ]; then
  fail "Repo directory not found: $REPO_DIR"
fi

cd "$REPO_DIR"

# ── Dirty Check ───────────────────────────────────────────────────────
if [ "$FORCE" = false ]; then
  log "Running dirty checks..."

  # Check for uncommitted changes
  if ! git diff-index --quiet HEAD --; then
    fail "Uncommitted changes detected. Commit or stash first, or use --force"
  fi

  # Check for untracked files
  if [ -n "$(git ls-files --others --exclude-standard)" ]; then
    fail "Untracked files detected. Commit or remove them, or use --force"
  fi

  # Check for unpushed commits
  LOCAL_COMMIT=$(git rev-parse @)
  REMOTE_COMMIT=$(git rev-parse '@{u}' 2>/dev/null || echo "")

  if [ -n "$REMOTE_COMMIT" ] && [ "$LOCAL_COMMIT" != "$REMOTE_COMMIT" ]; then
    fail "Unpushed commits detected. Push first or use --force"
  fi

  ok "Dirty checks passed"
else
  warn "Skipping dirty checks (--force enabled)"
fi

# ── Pull and Rebase ───────────────────────────────────────────────────
log "Pulling latest changes from origin/main..."
git fetch origin

LOCAL_MAIN=$(git rev-parse main)
REMOTE_MAIN=$(git rev-parse origin/main)

if [ "$LOCAL_MAIN" != "$REMOTE_MAIN" ]; then
  log "Local main is behind origin/main, rebasing..."
  git rebase origin/main || {
    fail "Rebase failed. Resolve conflicts and run: git rebase --continue"
  }
  ok "Rebase completed successfully"
else
  ok "Already up to date with origin/main"
fi

# ── Run Smoke Tests ─────────────────────────────────────────────────────
if [ "$SKIP_HEALTH_CHECK" = false ]; then
  log "Running smoke tests before deployment..."
  if [ -f "scripts/smoke-release.sh" ]; then
    chmod +x scripts/smoke-release.sh
    ./scripts/smoke-release.sh || {
      fail "Smoke tests failed. Fix issues before deploying or use --skip-health-check"
    }
    ok "Smoke tests passed"
  else
    warn "Smoke test script not found, skipping pre-deployment tests"
  fi
fi

# ── Check Package Publication ──────────────────────────────────────────
log "Checking @bytelyst package publication..."

# Check if required packages are published to Gitea registry
GITEA_REGISTRY="http://localhost:3300/api/packages/bytelyst/npm/"
REQUIRED_PACKAGES=(
  "@bytelyst/config"
  "@bytelyst/cosmos"
  "@bytelyst/auth"
  "@bytelyst/llm"
  "@bytelyst/telemetry-client"
  "@bytelyst/devops"
  "@bytelyst/errors"
  "@bytelyst/logger"
)

MISSING_PACKAGES=()

for package in "${REQUIRED_PACKAGES[@]}"; do
  # Check if package is published (Gitea API returns 200 if package exists)
  if ! curl -sf "${GITEA_REGISTRY}${package}" > /dev/null 2>&1; then
    MISSING_PACKAGES+=("$package")
  fi
done

if [ ${#MISSING_PACKAGES[@]} -gt 0 ]; then
  fail "Required @bytelyst packages not published to Gitea registry:
${MISSING_PACKAGES[*]}

Please publish the packages first by running:
  python3 /opt/bytelyst/republish_packages.py

This will publish all @bytelyst/* packages to https://gitea.bytelyst.com/"
fi

ok "All required @bytelyst packages are published"

# ── Build and Deploy ──────────────────────────────────────────────────
log "Building and deploying Docker containers..."

# Check if docker-compose files exist
if [ ! -f "docker-compose.yml" ]; then
  fail "docker-compose.yml not found in $REPO_DIR"
fi

# Build and start services
log "Building Docker images..."
if [ "$NO_CACHE" = true ]; then
  warn "Building without cache (--no-cache enabled)"
else
  log "Building with cache (use --no-cache to force rebuild)"
fi

# Resolve Gitea npm token for BuildKit secret
# Unset any existing environment variable to ensure we use file values
unset GITEA_NPM_TOKEN

if [ -f "/opt/bytelyst/.gitea_token" ]; then
  GITEA_NPM_TOKEN=$(cat /opt/bytelyst/.gitea_token)
  export GITEA_NPM_TOKEN
elif [ -f "$HOME/.gitea_npm_token" ]; then
  GITEA_NPM_TOKEN=$(cat "$HOME/.gitea_npm_token")
  export GITEA_NPM_TOKEN
else
  fail "GITEA_NPM_TOKEN not set and no token file found"
fi

# Collect build metadata (consumed by @bytelyst/devops)
# Declare separately so set -e + $(…) don't mask non-zero exit codes (SC2155).
BYTELYST_COMMIT_SHA=
BYTELYST_COMMIT_SHA_FULL=
BYTELYST_BRANCH=
BYTELYST_BUILT_AT=
BYTELYST_COMMIT_AUTHOR=
BYTELYST_COMMIT_MESSAGE=

# Change to repo directory to collect correct git metadata
cd "$REPO_DIR"
BYTELYST_COMMIT_SHA=$(git rev-parse --short HEAD 2>/dev/null || echo unknown)
BYTELYST_COMMIT_SHA_FULL=$(git rev-parse HEAD 2>/dev/null || echo unknown)
BYTELYST_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)
BYTELYST_BUILT_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)
BYTELYST_COMMIT_AUTHOR=$(git log -1 --pretty=format:'%an' 2>/dev/null || echo unknown)
BYTELYST_COMMIT_MESSAGE=$(git log -1 --pretty=format:'%s' 2>/dev/null | head -c 200 || echo unknown)
cd "$SCRIPT_DIR"

build_image() {
  local dockerfile="$1"
  local tag="$2"
  local cache_flag=""
  if [ "$NO_CACHE" = true ]; then
    cache_flag="--no-cache"
  fi
  # Build from repo directory to ensure correct source code is used
  (cd "$REPO_DIR" && docker build --network host $cache_flag \
    --build-arg "GITEA_NPM_TOKEN=${GITEA_NPM_TOKEN}" \
    --build-arg "BYTELYST_COMMIT_SHA=${BYTELYST_COMMIT_SHA}" \
    --build-arg "BYTELYST_COMMIT_SHA_FULL=${BYTELYST_COMMIT_SHA_FULL}" \
    --build-arg "BYTELYST_BRANCH=${BYTELYST_BRANCH}" \
    --build-arg "BYTELYST_BUILT_AT=${BYTELYST_BUILT_AT}" \
    --build-arg "BYTELYST_COMMIT_AUTHOR=${BYTELYST_COMMIT_AUTHOR}" \
    --build-arg "BYTELYST_COMMIT_MESSAGE=${BYTELYST_COMMIT_MESSAGE}" \
    --build-arg "BYTELYST_DOCKER_IMAGE=${tag}" \
    -f "$dockerfile" -t "$tag" .) || fail "Docker build failed for $dockerfile"
}

build_image backend/Dockerfile invttrdg-backend:latest || fail "Backend build failed"
build_image web/Dockerfile invttrdg-web:latest || fail "Web build failed"

log "Starting services..."
# Stop and remove existing containers to ensure fresh deployment
cd "$REPO_DIR"
docker compose down || true
# Start services with force-recreate to ensure new images are used
docker compose up -d --force-recreate || fail "Docker compose up failed"
cd "$SCRIPT_DIR"

ok "Deployment completed"

# ── Health Check ──────────────────────────────────────────────────────
if [ "$SKIP_HEALTH_CHECK" = true ]; then
  warn "Skipping health checks (--skip-health-check enabled)"
  exit 0
fi

log "Waiting for services to be healthy..."
sleep 10

# Check backend health
BACKEND_HEALTH=false
for _ in {1..30}; do
  if curl -sf http://localhost:4025/health/live > /dev/null 2>&1; then
    BACKEND_HEALTH=true
    break
  fi
  echo -n "."
  sleep 2
done
echo ""

if [ "$BACKEND_HEALTH" = true ]; then
  ok "Backend health check passed (http://localhost:4025)"
else
  fail "Backend health check failed"
fi

# Check web health
WEB_HEALTH=false
for _ in {1..30}; do
  if curl -sf http://localhost:3085 > /dev/null 2>&1; then
    WEB_HEALTH=true
    break
  fi
  echo -n "."
  sleep 2
done
echo ""

if [ "$WEB_HEALTH" = true ]; then
  ok "Web health check passed (http://localhost:3085)"
else
  warn "Web health check failed (may be starting up)"
fi

# ── Endpoint Verification ─────────────────────────────────────────────
log "Verifying production endpoints..."

API_ENDPOINT="https://api.bytelyst.com/invttrdg"
WEB_ENDPOINT="https://invttrdg.bytelyst.com"

# Check API endpoint
if curl -sf "$API_ENDPOINT/health/live" > /dev/null 2>&1; then
  ok "API endpoint accessible: $API_ENDPOINT"
else
  warn "API endpoint not accessible: $API_ENDPOINT (may need DNS propagation)"
fi

# Check web endpoint
if curl -sf "$WEB_ENDPOINT" > /dev/null 2>&1; then
  ok "Web endpoint accessible: $WEB_ENDPOINT"
else
  warn "Web endpoint not accessible: $WEB_ENDPOINT (may need DNS propagation)"
fi

# ── API Smoke Tests (Post-Deployment) ───────────────────────────────────
log "Running post-deployment API smoke tests..."

# Test backend health endpoint
BACKEND_URL="http://localhost:4025"
if curl -sf "$BACKEND_URL/health/live" > /dev/null 2>&1; then
  ok "Backend health endpoint responding"
  # Try to get health details
  HEALTH_RESPONSE=$(curl -s "$BACKEND_URL/health/live" 2>/dev/null || echo "{}")
  log "Health response: $HEALTH_RESPONSE"
else
  fail "Backend health endpoint not responding"
fi

# Test web is serving content
WEB_URL="http://localhost:3085"
if curl -sf "$WEB_URL" > /dev/null 2>&1; then
  ok "Web frontend is serving content"
  # Check if it's actually HTML (nginx serving the SPA)
  CONTENT_TYPE=$(curl -sI "$WEB_URL" | grep -i content-type || echo "")
  if echo "$CONTENT_TYPE" | grep -qi "text/html"; then
    ok "Web frontend is serving HTML content"
  else
    warn "Web frontend content type unexpected: $CONTENT_TYPE"
  fi
else
  fail "Web frontend not responding"
fi

log "══════════════════════════════════════════════════════════════════════"
ok "Deployment completed successfully!"
log "Backend: http://localhost:4025 → $API_ENDPOINT"
log "Web: http://localhost:3085 → $WEB_ENDPOINT"
log "══════════════════════════════════════════════════════════════════════"

# ── Verify Deployed Commit Hash ─────────────────────────────────────────────
log "Verifying deployed commit hash..."
BACKEND_URL="http://localhost:4025"
DEVOPS_RESPONSE=$(curl -s "$BACKEND_URL/api/devops/version" 2>/dev/null || echo "{}")

if [ "$DEVOPS_RESPONSE" != "{}" ] && [ -n "$DEVOPS_RESPONSE" ]; then
  if command -v jq &> /dev/null; then
    DEPLOYED_COMMIT_SHA=$(echo "$DEVOPS_RESPONSE" | jq -r '.commitSha // empty')
    DEPLOYED_COMMIT_FULL=$(echo "$DEVOPS_RESPONSE" | jq -r '.commitShaFull // empty')
    DEPLOYED_MESSAGE=$(echo "$DEVOPS_RESPONSE" | jq -r '.commitMessage // empty')

    if [ -n "$DEPLOYED_COMMIT_SHA" ]; then
      ok "Deployed commit: $DEPLOYED_COMMIT_SHA"
      log "Full SHA: $DEPLOYED_COMMIT_FULL"
      log "Message: $DEPLOYED_MESSAGE"

      # Compare with expected latest commit
      cd "$REPO_DIR"
      LATEST_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")

      if [ "$DEPLOYED_COMMIT_SHA" = "$LATEST_COMMIT" ]; then
        ok "✓ Deployed commit matches latest commit ($LATEST_COMMIT)"
      else
        warn "✗ Deployed commit ($DEPLOYED_COMMIT_SHA) differs from latest commit ($LATEST_COMMIT)"
        warn "  This indicates the deployment may not have used the latest code"
        warn "  Consider running: ./deploy-invttrdg.sh --force --no-cache"
      fi
    else
      warn "Could not extract commit SHA from devops endpoint"
    fi
  else
    warn "jq not installed, showing raw devops response:"
    echo "$DEVOPS_RESPONSE"
  fi
else
  warn "Could not retrieve deployment info from devops endpoint"
fi

log "══════════════════════════════════════════════════════════════════════"
