#!/bin/bash
# =============================================================================
# MPC System - Deployment Script
# =============================================================================
# This script manages the MPC System Docker services
#
# Deployment Modes:
#   1. Development (default): All services on one machine (docker-compose.yml)
#   2. Production Central:    Central services only (docker-compose.prod.yml)
#   3. Production Party:      Standalone party (docker-compose.party.yml)
#
# External Ports (Development):
#   4000  - Account Service HTTP API
#   8081  - Session Coordinator API
#   8082  - Message Router HTTP
#   8083  - Server Party API
#
# External Ports (Production Central):
#   50051 - Message Router gRPC (for party connections)
#   50052 - Session Coordinator gRPC (for party connections)
#   4000  - Account Service HTTP API
#   8081  - Session Coordinator HTTP API
#   8082  - Message Router HTTP API
# =============================================================================

set -e

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

log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_header() { echo -e "${CYAN}=== $1 ===${NC}"; }

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

# Determine which environment file to load
load_env() {
    local env_file="$1"
    if [ -f "$env_file" ]; then
        log_info "Loading environment from $env_file"
        set -a
        source "$env_file"
        set +a
        return 0
    fi
    return 1
}

# Load environment based on mode
load_environment() {
    local mode="$1"
    case "$mode" in
        prod)
            load_env ".env.prod" || load_env ".env" || {
                log_error "No .env.prod or .env file found"
                exit 1
            }
            ;;
        party)
            load_env ".env.party" || {
                log_error "No .env.party file found. Create from .env.party.example"
                exit 1
            }
            ;;
        *)
            load_env ".env" || {
                if [ -f ".env.example" ]; then
                    log_warn ".env file not found. Creating from .env.example"
                    cp .env.example .env
                    log_error "Please configure .env file and run again"
                fi
                exit 1
            }
            ;;
    esac
}

# Service lists
CORE_SERVICES="postgres"
DEV_MPC_SERVICES="session-coordinator message-router server-party-1 server-party-2 server-party-3 server-party-api server-party-co-managed-1 server-party-co-managed-2 server-party-co-managed-3 account-service"
PROD_CENTRAL_SERVICES="postgres message-router session-coordinator account-service server-party-api server-party-co-managed-1 server-party-co-managed-2 server-party-co-managed-3"

# ============================================
# Development Mode Commands (docker-compose.yml)
# ============================================
dev_commands() {
    load_environment "dev"

    case "$1" in
        build)
            log_info "Building MPC System services..."
            docker compose build
            log_success "MPC System built successfully"
            ;;

        build-no-cache)
            log_info "Building MPC System (no cache)..."
            docker compose build --no-cache
            log_success "MPC System built successfully"
            ;;

        up|start)
            log_info "Starting MPC System (Development)..."
            docker compose up -d
            log_success "MPC System started"
            echo ""
            log_info "Services status:"
            docker compose ps
            ;;

        down|stop)
            log_info "Stopping MPC System..."
            docker compose down
            log_success "MPC System stopped"
            ;;

        restart)
            log_info "Restarting MPC System..."
            docker compose down
            docker compose up -d
            log_success "MPC System restarted"
            ;;

        logs)
            if [ -n "$2" ]; then
                docker compose logs -f "$2"
            else
                docker compose logs -f
            fi
            ;;

        logs-tail)
            if [ -n "$2" ]; then
                docker compose logs --tail 100 "$2"
            else
                docker compose logs --tail 100
            fi
            ;;

        status|ps)
            log_info "MPC System status:"
            docker compose ps
            ;;

        health)
            log_info "Checking MPC System health..."
            echo ""
            log_header "Infrastructure"
            for svc in $CORE_SERVICES; do
                if docker compose ps "$svc" --format json 2>/dev/null | grep -q '"Health":"healthy"'; then
                    log_success "$svc is healthy"
                else
                    log_warn "$svc is not healthy"
                fi
            done

            echo ""
            log_header "MPC Services"
            for svc in $DEV_MPC_SERVICES; do
                if docker compose ps "$svc" --format json 2>/dev/null | grep -q '"Health":"healthy"'; then
                    log_success "$svc is healthy"
                else
                    log_warn "$svc is not healthy"
                fi
            done

            echo ""
            log_header "External API"
            if curl -sf "http://localhost:4000/health" > /dev/null 2>&1; then
                log_success "Account Service API (port 4000) is accessible"
            else
                log_error "Account Service API (port 4000) is not accessible"
            fi
            ;;

        clean)
            log_warn "This will remove all containers and volumes!"
            read -p "Are you sure? (y/N) " -n 1 -r
            echo
            if [[ $REPLY =~ ^[Yy]$ ]]; then
                docker compose down -v
                log_success "MPC System cleaned"
            else
                log_info "Cancelled"
            fi
            ;;

        shell)
            if [ -n "$2" ]; then
                log_info "Opening shell in $2..."
                docker compose exec "$2" sh
            else
                log_info "Opening shell in account-service..."
                docker compose exec account-service sh
            fi
            ;;

        test-api)
            log_info "Testing Account Service API..."
            echo ""
            echo "Health check:"
            curl -s "http://localhost:4000/health" | jq . 2>/dev/null || curl -s "http://localhost:4000/health"
            echo ""
            ;;

        start-svc)
            if [ -z "$2" ]; then
                log_error "Please specify a service name"
                return 1
            fi
            log_info "Starting $2..."
            docker compose up -d "$2"
            log_success "$2 started"
            ;;

        stop-svc)
            if [ -z "$2" ]; then
                log_error "Please specify a service name"
                return 1
            fi
            log_info "Stopping $2..."
            docker compose stop "$2"
            log_success "$2 stopped"
            ;;

        restart-svc)
            if [ -z "$2" ]; then
                log_error "Please specify a service name"
                return 1
            fi
            log_info "Restarting $2..."
            docker compose stop "$2"
            docker compose up -d "$2"
            log_success "$2 restarted"
            ;;

        rebuild-svc)
            if [ -z "$2" ]; then
                log_error "Please specify a service name"
                return 1
            fi
            local svc="$2"
            local no_cache="$3"
            log_info "Rebuilding $svc..."
            if [ "$no_cache" = "--no-cache" ]; then
                log_info "Building without cache..."
                docker compose build --no-cache "$svc"
            else
                docker compose build "$svc"
            fi
            docker compose up -d "$svc"
            log_success "$svc rebuilt and restarted"
            ;;

        *)
            return 1
            ;;
    esac
}

# ============================================
# Production Central Commands (docker-compose.prod.yml)
# ============================================
prod_commands() {
    load_environment "prod"

    case "$1" in
        build)
            log_info "Building Production Central services..."
            docker compose -f docker-compose.prod.yml build
            log_success "Production services built"
            ;;

        up|start)
            log_info "Starting Production Central services..."
            docker compose -f docker-compose.prod.yml up -d
            log_success "Production Central services started"
            echo ""
            log_header "Services Status"
            docker compose -f docker-compose.prod.yml ps
            echo ""
            log_header "Public Endpoints"
            echo "  Message Router gRPC:     ${MESSAGE_ROUTER_GRPC_PORT:-50051}"
            echo "  Session Coordinator gRPC: ${SESSION_COORDINATOR_GRPC_PORT:-50052}"
            echo "  Account Service HTTP:     ${ACCOUNT_SERVICE_PORT:-4000}"
            ;;

        down|stop)
            log_info "Stopping Production Central services..."
            docker compose -f docker-compose.prod.yml down
            log_success "Production Central services stopped"
            ;;

        restart)
            log_info "Restarting Production Central services..."
            docker compose -f docker-compose.prod.yml down
            docker compose -f docker-compose.prod.yml up -d
            log_success "Production Central services restarted"
            ;;

        logs)
            if [ -n "$2" ]; then
                docker compose -f docker-compose.prod.yml logs -f "$2"
            else
                docker compose -f docker-compose.prod.yml logs -f
            fi
            ;;

        status|ps)
            log_info "Production Central status:"
            docker compose -f docker-compose.prod.yml ps
            ;;

        health)
            log_info "Checking Production Central health..."
            echo ""
            log_header "Central Services"
            for svc in $PROD_CENTRAL_SERVICES; do
                if docker compose -f docker-compose.prod.yml ps "$svc" --format json 2>/dev/null | grep -q '"Health":"healthy"'; then
                    log_success "$svc is healthy"
                else
                    log_warn "$svc is not healthy"
                fi
            done

            echo ""
            log_header "Public Endpoints"
            if curl -sf "http://localhost:${MESSAGE_ROUTER_HTTP_PORT:-8082}/health" > /dev/null 2>&1; then
                log_success "Message Router (port ${MESSAGE_ROUTER_HTTP_PORT:-8082}) is accessible"
            else
                log_error "Message Router is not accessible"
            fi
            if curl -sf "http://localhost:${SESSION_COORDINATOR_HTTP_PORT:-8081}/health" > /dev/null 2>&1; then
                log_success "Session Coordinator (port ${SESSION_COORDINATOR_HTTP_PORT:-8081}) is accessible"
            else
                log_error "Session Coordinator is not accessible"
            fi
            if curl -sf "http://localhost:${ACCOUNT_SERVICE_PORT:-4000}/health" > /dev/null 2>&1; then
                log_success "Account Service (port ${ACCOUNT_SERVICE_PORT:-4000}) is accessible"
            else
                log_error "Account Service is not accessible"
            fi
            ;;

        clean)
            log_warn "This will remove all Production Central containers and volumes!"
            read -p "Are you sure? (y/N) " -n 1 -r
            echo
            if [[ $REPLY =~ ^[Yy]$ ]]; then
                docker compose -f docker-compose.prod.yml down -v
                log_success "Production Central cleaned"
            else
                log_info "Cancelled"
            fi
            ;;

        start-svc)
            if [ -z "$2" ]; then
                log_error "Please specify a service name"
                return 1
            fi
            log_info "Starting $2..."
            docker compose -f docker-compose.prod.yml up -d "$2"
            log_success "$2 started"
            ;;

        stop-svc)
            if [ -z "$2" ]; then
                log_error "Please specify a service name"
                return 1
            fi
            log_info "Stopping $2..."
            docker compose -f docker-compose.prod.yml stop "$2"
            log_success "$2 stopped"
            ;;

        restart-svc)
            if [ -z "$2" ]; then
                log_error "Please specify a service name"
                return 1
            fi
            log_info "Restarting $2..."
            docker compose -f docker-compose.prod.yml stop "$2"
            docker compose -f docker-compose.prod.yml up -d "$2"
            log_success "$2 restarted"
            ;;

        rebuild-svc)
            if [ -z "$2" ]; then
                log_error "Please specify a service name"
                return 1
            fi
            local svc="$2"
            local no_cache="$3"
            log_info "Rebuilding $svc..."
            if [ "$no_cache" = "--no-cache" ]; then
                log_info "Building without cache..."
                docker compose -f docker-compose.prod.yml build --no-cache "$svc"
            else
                docker compose -f docker-compose.prod.yml build "$svc"
            fi
            docker compose -f docker-compose.prod.yml up -d "$svc"
            log_success "$svc rebuilt and restarted"
            ;;

        *)
            return 1
            ;;
    esac
}

# ============================================
# Production Party Commands (docker-compose.party.yml)
# ============================================
party_commands() {
    load_environment "party"

    # Validate required environment variables
    if [ -z "$PARTY_ID" ]; then
        log_error "PARTY_ID must be set (e.g., server-party-1)"
        exit 1
    fi
    if [ -z "$MESSAGE_ROUTER_ADDR" ]; then
        log_error "MESSAGE_ROUTER_ADDR must be set (e.g., grpc.mpc.example.com:50051)"
        exit 1
    fi

    case "$1" in
        build)
            log_info "Building Party ($PARTY_ID)..."
            docker compose -f docker-compose.party.yml build
            log_success "Party built"
            ;;

        up|start)
            log_info "Starting Party: $PARTY_ID"
            log_info "Connecting to Message Router: $MESSAGE_ROUTER_ADDR"
            docker compose -f docker-compose.party.yml up -d
            log_success "Party $PARTY_ID started"
            echo ""
            docker compose -f docker-compose.party.yml ps
            ;;

        down|stop)
            log_info "Stopping Party: $PARTY_ID..."
            docker compose -f docker-compose.party.yml down
            log_success "Party stopped"
            ;;

        restart)
            log_info "Restarting Party: $PARTY_ID..."
            docker compose -f docker-compose.party.yml down
            docker compose -f docker-compose.party.yml up -d
            log_success "Party restarted"
            ;;

        logs)
            docker compose -f docker-compose.party.yml logs -f server-party
            ;;

        status|ps)
            log_info "Party $PARTY_ID status:"
            docker compose -f docker-compose.party.yml ps
            ;;

        health)
            log_info "Checking Party $PARTY_ID health..."
            echo ""
            log_header "Local Services"
            if docker compose -f docker-compose.party.yml ps postgres --format json 2>/dev/null | grep -q '"Health":"healthy"'; then
                log_success "Local PostgreSQL is healthy"
            else
                log_warn "Local PostgreSQL is not healthy"
            fi
            if docker compose -f docker-compose.party.yml ps server-party --format json 2>/dev/null | grep -q '"Health":"healthy"'; then
                log_success "Server Party is healthy"
            else
                log_warn "Server Party is not healthy"
            fi

            echo ""
            log_header "Central Service Connectivity"
            # Extract host and port from MESSAGE_ROUTER_ADDR
            MR_HOST=$(echo "$MESSAGE_ROUTER_ADDR" | cut -d: -f1)
            MR_PORT=$(echo "$MESSAGE_ROUTER_ADDR" | cut -d: -f2)
            if timeout 5 bash -c "echo >/dev/tcp/$MR_HOST/$MR_PORT" 2>/dev/null; then
                log_success "Message Router ($MESSAGE_ROUTER_ADDR) is reachable"
            else
                log_error "Message Router ($MESSAGE_ROUTER_ADDR) is NOT reachable"
            fi
            ;;

        clean)
            log_warn "This will remove Party $PARTY_ID containers and LOCAL KEY STORAGE!"
            log_warn "Your encrypted key shares will be DELETED!"
            read -p "Are you absolutely sure? (yes/N) " confirm
            echo
            if [ "$confirm" = "yes" ]; then
                docker compose -f docker-compose.party.yml down -v
                log_success "Party $PARTY_ID cleaned"
            else
                log_info "Cancelled"
            fi
            ;;

        *)
            return 1
            ;;
    esac
}

# ============================================
# Main Command Router
# ============================================
show_help() {
    echo "MPC System Deployment Script"
    echo ""
    echo "Usage: $0 <mode> <command> [options]"
    echo ""
    echo "Deployment Modes:"
    echo "  (default)     Development mode - all services on one machine"
    echo "  prod          Production Central - Message Router, Session Coordinator, Account"
    echo "  party         Production Party - standalone server-party (distributed)"
    echo ""
    echo "Development Commands (default mode):"
    echo "  $0 build              Build all Docker images"
    echo "  $0 build-no-cache     Build all images without cache"
    echo "  $0 up|start           Start all services"
    echo "  $0 down|stop          Stop all services"
    echo "  $0 restart            Restart all services"
    echo "  $0 logs [service]     Follow logs"
    echo "  $0 logs-tail [svc]    Show last 100 lines of logs"
    echo "  $0 status|ps          Show services status"
    echo "  $0 health             Check all services health"
    echo "  $0 clean              Remove containers and volumes"
    echo "  $0 shell [service]    Open shell in container"
    echo "  $0 test-api           Test Account Service API"
    echo ""
    echo "Single Service Commands (Development):"
    echo "  $0 start-svc <name>   Start a specific service"
    echo "  $0 stop-svc <name>    Stop a specific service"
    echo "  $0 restart-svc <name> Restart a specific service"
    echo "  $0 rebuild-svc <name> [--no-cache]  Rebuild and restart a service"
    echo ""
    echo "Production Central Commands:"
    echo "  $0 prod build         Build central services"
    echo "  $0 prod up            Start central services"
    echo "  $0 prod down          Stop central services"
    echo "  $0 prod restart       Restart central services"
    echo "  $0 prod logs [svc]    Follow central logs"
    echo "  $0 prod status        Show central status"
    echo "  $0 prod health        Check central health"
    echo "  $0 prod clean         Remove central containers and volumes"
    echo "  $0 prod start-svc <name>   Start a specific service"
    echo "  $0 prod stop-svc <name>    Stop a specific service"
    echo "  $0 prod restart-svc <name> Restart a specific service"
    echo "  $0 prod rebuild-svc <name> [--no-cache]  Rebuild and restart"
    echo ""
    echo "Production Party Commands (run on each party machine):"
    echo "  $0 party build        Build party service"
    echo "  $0 party up           Start party (connects to central)"
    echo "  $0 party down         Stop party"
    echo "  $0 party restart      Restart party"
    echo "  $0 party logs         Follow party logs"
    echo "  $0 party status       Show party status"
    echo "  $0 party health       Check party health and connectivity"
    echo "  $0 party clean        Remove party containers and volumes"
    echo ""
    echo "Environment Files:"
    echo "  .env              Development configuration"
    echo "  .env.prod         Production Central configuration"
    echo "  .env.party        Production Party configuration"
    echo ""
    echo "Services (Development):"
    echo "  postgres, session-coordinator, message-router, account-service,"
    echo "  server-party-api, server-party-1, server-party-2, server-party-3,"
    echo "  server-party-co-managed-1, server-party-co-managed-2, server-party-co-managed-3"
    echo ""
    echo "Examples:"
    echo "  # Development (all on one machine)"
    echo "  $0 up"
    echo "  $0 rebuild-svc account-service --no-cache"
    echo "  $0 restart-svc session-coordinator"
    echo ""
    echo "  # Production Central (on central server)"
    echo "  $0 prod up"
    echo "  $0 prod rebuild-svc account-service"
    echo ""
    echo "  # Production Party (on each party machine)"
    echo "  PARTY_ID=server-party-1 $0 party up"
    echo "  PARTY_ID=server-party-2 $0 party up"
    echo "  PARTY_ID=server-party-3 $0 party up"
}

# Route commands based on first argument
case "$1" in
    prod)
        shift
        prod_commands "$@" || {
            echo "Usage: $0 prod {build|up|down|restart|logs|status|health|clean}"
            exit 1
        }
        ;;

    party)
        shift
        party_commands "$@" || {
            echo "Usage: $0 party {build|up|down|restart|logs|status|health|clean}"
            echo ""
            echo "Required environment variables:"
            echo "  PARTY_ID                  Unique party identifier"
            echo "  MESSAGE_ROUTER_ADDR       Central Message Router address (only connection needed)"
            echo "  CRYPTO_MASTER_KEY         Encryption key for key shares"
            exit 1
        }
        ;;

    help|--help|-h)
        show_help
        ;;

    "")
        show_help
        exit 1
        ;;

    *)
        # Default to development mode
        dev_commands "$@" || {
            show_help
            exit 1
        }
        ;;
esac
