#!/bin/bash
# ============================================================
# Office Translator - Deployment Script
# ============================================================
# Usage: ./deploy.sh <command> [options]
#
# Commands:
#   start     Build and start all services
#   stop      Stop all services
#   restart   Restart all services
#   status    Show services status
#   logs      Show logs (follow mode)
#   build     Build/rebuild images
#   health    Run health checks
#   backup    Backup PostgreSQL database
#   clean     Remove all containers, volumes, and images
#   shell     Open a shell in the backend container
#   migrate   Run database migrations
#   help      Show this help message
#
# Options:
#   --env <file>      Use a specific env file (default: .env.docker)
#   --prod            Use production compose file (docker-compose.yml)
#   --no-build        Skip build step on start
#   --rebuild         Force rebuild without cache
#
# Examples:
#   ./deploy.sh start                          # Start with defaults (local)
#   ./deploy.sh start --rebuild                # Force rebuild
#   ./deploy.sh start --prod                   # Start production stack
#   ./deploy.sh logs backend                   # Show backend logs
#   ./deploy.sh logs                           # Show all logs
#   ./deploy.sh backup                         # Backup database
#   ./deploy.sh clean                          # Full cleanup
# ============================================================

set -euo pipefail

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

# ---- Configuration ----
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"

COMPOSE_LOCAL="docker-compose.local.yml"
COMPOSE_PROD="docker-compose.yml"
ENV_FILE=".env.docker"
# Default to production compose if local compose doesn't exist (server context)
if [ -f "$COMPOSE_LOCAL" ] && [ -f ".env.docker" ]; then
    COMPOSE_FILE="$COMPOSE_LOCAL"
else
    COMPOSE_FILE="$COMPOSE_PROD"
fi
COMMAND=""
SERVICE=""
NO_BUILD=false
REBUILD=false

# ---- Helper Functions ----

info()    { echo -e "${BLUE}[INFO]${NC}  $*"; }
success() { echo -e "${GREEN}[OK]${NC}    $*"; }
warn()    { echo -e "${YELLOW}[WARN]${NC}  $*"; }
error()   { echo -e "${RED}[ERROR]${NC} $*" >&2; }
header()  { echo ""; echo -e "${BOLD}${CYAN}========================================${NC}"; echo -e "${BOLD}${CYAN}  $*${NC}"; echo -e "${BOLD}${CYAN}========================================${NC}"; }

# ---- Auto-detect env file if not overridden by --env ----
# Prefer .env.docker (local dev), fall back to .env (production)
if [ ! -f "$ENV_FILE" ]; then
    if [ -f ".env" ]; then
        ENV_FILE=".env"
    fi
fi

# Run docker compose with the right file and env
dc() {
    if [ -f "$ENV_FILE" ]; then
        docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" "$@"
    else
        docker compose -f "$COMPOSE_FILE" "$@"
    fi
}

# ---- Parse Arguments ----

COMMAND="${1:-help}"
shift 2>/dev/null || true

while [[ $# -gt 0 ]]; do
    case $1 in
        --env)
            ENV_FILE="$2"
            shift 2
            ;;
        --prod)
            COMPOSE_FILE="$COMPOSE_PROD"
            shift
            ;;
        --no-build)
            NO_BUILD=true
            shift
            ;;
        --rebuild)
            REBUILD=true
            shift
            ;;
        backend|frontend|postgres|redis|nginx|ollama)
            SERVICE="$1"
            shift
            ;;
        *)
            shift
            ;;
    esac
done

# ---- Prerequisite Checks ----

check_prerequisites() {
    if ! command -v docker &> /dev/null; then
        error "Docker is not installed. Install it from https://docs.docker.com/get-docker/"
        exit 1
    fi

    if ! docker info &> /dev/null 2>&1; then
        error "Docker daemon is not running. Start Docker Desktop or the Docker service."
        exit 1
    fi

    if ! docker compose version &> /dev/null 2>&1; then
        error "Docker Compose V2 is not available. Update Docker or install docker-compose."
        exit 1
    fi

    if [ ! -f "$ENV_FILE" ]; then
        error "Environment file '$ENV_FILE' not found."
        if [ "$ENV_FILE" == ".env.docker" ]; then
            info "Creating .env.docker from default settings..."
            cat > .env.docker << 'ENVEOF'
ENV=production
LOG_LEVEL=INFO
LOG_FORMAT=console
ENABLE_REQUEST_LOGGING=true
TRANSLATION_SERVICE=google
GOOGLE_TRANSLATE_ENABLED=true
DEEPL_ENABLED=false
OPENAI_ENABLED=false
OLLAMA_ENABLED=false
OPENROUTER_ENABLED=false
PROVIDER_FALLBACK_CHAIN=google,deepl,openai,ollama,openrouter
FALLBACK_CHAIN_CLASSIC=google,deepl
FALLBACK_CHAIN_LLM=ollama,openai
MAX_FILE_SIZE_MB=50
MAX_REQUEST_SIZE_MB=100
REQUEST_TIMEOUT_SECONDS=300
RATE_LIMIT_ENABLED=true
RATE_LIMIT_PER_MINUTE=30
RATE_LIMIT_PER_HOUR=200
TRANSLATIONS_PER_MINUTE=10
TRANSLATIONS_PER_HOUR=50
MAX_CONCURRENT_TRANSLATIONS=5
CLEANUP_ENABLED=true
CLEANUP_INTERVAL_MINUTES=5
FILE_TTL_MINUTES=60
INPUT_FILE_TTL_MINUTES=30
OUTPUT_FILE_TTL_MINUTES=120
DISK_WARNING_THRESHOLD_GB=5.0
DISK_CRITICAL_THRESHOLD_GB=1.0
ENABLE_HSTS=false
CORS_ORIGINS=http://localhost,http://localhost:3000,http://localhost:8000
MAX_MEMORY_PERCENT=80
POSTGRES_USER=translate
POSTGRES_PASSWORD=translate_local_2026
POSTGRES_DB=translate_db
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
DATABASE_ECHO=false
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin123
ADMIN_TOKEN_SECRET=docker_local_admin_token_secret_2026_abc123xyz
JWT_SECRET_KEY=docker_local_jwt_secret_key_2026_x7k9m3p5q8r2s4t6
FRONTEND_URL=http://localhost
NEXT_PUBLIC_API_URL=
BACKEND_URL=http://backend:8000
HTTP_PORT=80
ENVEOF
            success "Created .env.docker with default local settings"
        else
            exit 1
        fi
    fi

    # Check for port conflicts
    if command -v lsof &> /dev/null; then
        for PORT in 80 3000 5432 6379; do
            if lsof -i ":$PORT" -sTCP:LISTEN &> /dev/null 2>&1; then
                warn "Port $PORT is already in use. This may cause conflicts."
            fi
        done
    fi

    success "Prerequisites OK (Docker + Compose + $ENV_FILE)"
}

# ---- Command Functions ----

cmd_start() {
    header "Office Translator - Starting"

    check_prerequisites

    if [ "$REBUILD" = true ]; then
        info "Building images (no cache)..."
        dc build --no-cache ${SERVICE:-}
    elif [ "$NO_BUILD" = false ]; then
        info "Building images..."
        dc build ${SERVICE:-}
    else
        info "Skipping build (--no-build)"
    fi

    info "Starting services..."
    dc up -d ${SERVICE:-}

    info "Waiting for services to be ready..."
    local max_wait=120
    local elapsed=0
    while [ $elapsed -lt $max_wait ]; do
        local backend_ok=false
        local frontend_ok=false

        if curl -sf http://localhost:8000/health > /dev/null 2>&1; then
            backend_ok=true
        fi

        if curl -sf http://localhost:3000 > /dev/null 2>&1; then
            frontend_ok=true
        fi

        if [ "$backend_ok" = true ] && [ "$frontend_ok" = true ]; then
            break
        fi

        sleep 3
        elapsed=$((elapsed + 3))
        printf "\r  Waiting... (%ds/%ds) backend=%s frontend=%s" \
            "$elapsed" "$max_wait" "$backend_ok" "$frontend_ok"
    done
    echo ""

    # Health check
    echo ""
    cmd_health

    # Show status
    echo ""
    dc ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"

    echo ""
    success "Application is running!"
    echo ""
    info "Access points:"
    echo "  Frontend:  http://localhost"
    echo "  Backend:   http://localhost:8000"
    echo "  API docs:  http://localhost:8000/docs"
    echo "  Admin:     http://localhost/admin (admin / admin123)"
    echo "  Health:    http://localhost/health"
    echo ""
    info "Useful commands:"
    echo "  ./deploy.sh logs          Follow logs"
    echo "  ./deploy.sh status        Check status"
    echo "  ./deploy.sh stop          Stop all"
}

cmd_stop() {
    header "Stopping Services"
    dc down --remove-orphans ${SERVICE:-}
    success "Services stopped"
}

cmd_restart() {
    header "Restarting Services"
    info "Stopping..."
    dc restart ${SERVICE:-}
    success "Services restarted"
    sleep 5
    cmd_health
}

cmd_status() {
    header "Service Status"
    dc ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
    echo ""

    # Quick health
    info "Health checks:"
    local backend_code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/health 2>/dev/null || echo "000")
    local frontend_code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000 2>/dev/null || echo "000")
    local nginx_code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/health 2>/dev/null || echo "000")

    [ "$backend_code" = "200" ] && success "Backend  (HTTP $backend_code)" || error "Backend  (HTTP $backend_code)"
    [ "$frontend_code" = "200" ] && success "Frontend (HTTP $frontend_code)" || error "Frontend (HTTP $frontend_code)"
    [ "$nginx_code" = "200" ] && success "Nginx    (HTTP $nginx_code)" || error "Nginx    (HTTP $nginx_code)"
}

cmd_logs() {
    local target="${SERVICE:-}"
    if [ -n "$target" ]; then
        dc logs -f --tail 100 "$target"
    else
        dc logs -f --tail 50
    fi
}

cmd_build() {
    header "Building Images"
    check_prerequisites

    if [ "$REBUILD" = true ]; then
        info "Building without cache..."
        dc build --no-cache ${SERVICE:-}
    else
        info "Building..."
        dc build ${SERVICE:-}
    fi
    success "Build complete"
}

cmd_health() {
    info "Running health checks..."

    # Backend
    local backend_response=$(curl -sf http://localhost:8000/health 2>/dev/null || echo '{"status":"unreachable"}')
    if echo "$backend_response" | python3 -c "import sys,json; d=json.load(sys.stdin); exit(0 if d.get('status')=='healthy' else 1)" 2>/dev/null; then
        success "Backend: healthy"
        echo "$backend_response" | python3 -m json.tool 2>/dev/null | sed 's/^/  /'
    else
        local backend_code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/health 2>/dev/null || echo "000")
        error "Backend: unhealthy (HTTP $backend_code)"
    fi

    # Frontend
    if curl -sf http://localhost:3000 > /dev/null 2>&1; then
        success "Frontend: responding"
    else
        error "Frontend: not responding"
    fi

    # Nginx
    if curl -sf http://localhost/health > /dev/null 2>&1; then
        success "Nginx: proxying correctly"
    else
        warn "Nginx: not reachable on port 80"
    fi

    # PostgreSQL
    if dc exec -T postgres pg_isready -U translate -d translate_db &> /dev/null; then
        success "PostgreSQL: ready"
    else
        error "PostgreSQL: not ready"
    fi

    # Redis
    if dc exec -T redis redis-cli ping &> /dev/null; then
        success "Redis: ready (PONG)"
    else
        error "Redis: not ready"
    fi
}

cmd_backup() {
    header "Database Backup"
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local backup_dir="backups"
    mkdir -p "$backup_dir"

    local backup_file="$backup_dir/translate_db_${timestamp}.sql.gz"

    info "Backing up PostgreSQL to $backup_file..."
    dc exec -T postgres pg_dump -U translate translate_db | gzip > "$backup_file"

    local size=$(du -h "$backup_file" | cut -f1)
    success "Backup complete: $backup_file ($size)"
}

cmd_clean() {
    header "Full Cleanup"
    warn "This will remove all containers, volumes, and images for this project."
    read -p "Are you sure? [y/N] " -n 1 -r
    echo ""

    if [[ $REPLY =~ ^[Yy]$ ]]; then
        info "Stopping and removing containers..."
        dc down -v --rmi local --remove-orphans

        info "Pruning dangling resources..."
        docker system prune -f

        success "Cleanup complete"
    else
        info "Cancelled"
    fi
}

cmd_shell() {
    local target="${SERVICE:-backend}"
    info "Opening shell in $target container..."
    dc exec "$target" /bin/bash || dc exec "$target" /bin/sh
}

cmd_migrate() {
    header "Running Database Migrations"
    info "Running alembic upgrade head..."
    # Run directly inside the backend container — no env file needed
    docker compose -f "$COMPOSE_FILE" exec backend alembic upgrade head
    success "Migrations complete"
}

cmd_help() {
    echo ""
    echo -e "${BOLD}Office Translator - Deployment Script${NC}"
    echo ""
    echo "Usage: ./deploy.sh <command> [options]"
    echo ""
    echo -e "${BOLD}Commands:${NC}"
    echo "  start       Build and start all services"
    echo "  stop        Stop all services"
    echo "  restart     Restart all services"
    echo "  status      Show services status"
    echo "  logs [svc]  Show logs (optional: backend, frontend, postgres, redis, nginx)"
    echo "  build       Build/rebuild Docker images"
    echo "  health      Run health checks on all services"
    echo "  backup      Backup PostgreSQL database"
    echo "  clean       Remove all containers, volumes, and images"
    echo "  shell [svc] Open shell in a container (default: backend)"
    echo "  migrate     Run database migrations"
    echo "  help        Show this help message"
    echo ""
    echo -e "${BOLD}Options:${NC}"
    echo "  --env <file>    Use a specific env file (default: .env.docker)"
    echo "  --prod          Use production compose file"
    echo "  --no-build      Skip build step"
    echo "  --rebuild       Force rebuild without Docker cache"
    echo ""
    echo -e "${BOLD}Examples:${NC}"
    echo "  ./deploy.sh start"
    echo "  ./deploy.sh start --rebuild"
    echo "  ./deploy.sh start --prod --env .env.production"
    echo "  ./deploy.sh logs backend"
    echo "  ./deploy.sh shell postgres"
    echo "  ./deploy.sh backup"
    echo ""
}

# ---- Main ----

case "$COMMAND" in
    start)    cmd_start    ;;
    stop)     cmd_stop     ;;
    restart)  cmd_restart  ;;
    status)   cmd_status   ;;
    logs)     cmd_logs     ;;
    build)    cmd_build    ;;
    health)   cmd_health   ;;
    backup)   cmd_backup   ;;
    clean)    cmd_clean    ;;
    shell)    cmd_shell    ;;
    migrate)  cmd_migrate  ;;
    help|--help|-h)
        cmd_help
        ;;
    *)
        error "Unknown command: $COMMAND"
        cmd_help
        exit 1
        ;;
esac
