#!/bin/bash

# AirwavePBX v2.0.2 Installer - Fixed Wazo URL
# Supports Ubuntu 24.04 LTS with comprehensive dependency checking

set -e

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

# Print colored output
print_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }

# Configuration variables
AIRWAVE_VERSION="2.0.2"
WAZO_VERSION="latest"
INSTALL_DIR="/opt/airwavepbx"
CONFIG_DIR="/etc/airwavepbx"
LOG_DIR="/var/log/airwavepbx"
SSL_DIR="/etc/letsencrypt"

# Header
echo "============================================="
echo "AirwavePBX v${AIRWAVE_VERSION} Installer"
echo "Powered by Wazo Platform"
echo "============================================="
echo

# Check if running as root
if [[ $EUID -ne 0 ]]; then
   print_error "This script must be run as root"
   exit 1
fi

# Check Ubuntu version
if ! grep -q "Ubuntu 24.04" /etc/os-release; then
    print_warning "This installer is designed for Ubuntu 24.04 LTS"
    read -p "Continue anyway? (y/N) " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        exit 1
    fi
fi

# Function to check if a command exists
command_exists() {
    command -v "$1" >/dev/null 2>&1
}

# Function to check if a port is in use
port_in_use() {
    netstat -tuln | grep -q ":$1 "
}

# Function to generate secure password
generate_password() {
    openssl rand -base64 32 | tr -d "=+/" | cut -c1-25
}

# Detect existing Let's Encrypt certificates
detect_letsencrypt() {
    print_info "Checking for existing Let's Encrypt certificates..."
    
    if [ -d "$SSL_DIR/live" ]; then
        EXISTING_DOMAINS=$(ls -1 "$SSL_DIR/live" 2>/dev/null | grep -v README || true)
        if [ -n "$EXISTING_DOMAINS" ]; then
            print_success "Found existing Let's Encrypt certificates:"
            echo "$EXISTING_DOMAINS" | while read domain; do
                echo "  - $domain"
            done
            
            echo
            read -p "Would you like to use an existing certificate? (y/N) " -n 1 -r
            echo
            if [[ $REPLY =~ ^[Yy]$ ]]; then
                echo "Available domains:"
                select DOMAIN in $EXISTING_DOMAINS "Enter new domain"; do
                    if [ "$DOMAIN" = "Enter new domain" ]; then
                        read -p "Enter your domain name: " DOMAIN
                        USE_EXISTING_CERT=false
                    else
                        USE_EXISTING_CERT=true
                    fi
                    break
                done
            else
                read -p "Enter your domain name: " DOMAIN
                USE_EXISTING_CERT=false
            fi
        else
            read -p "Enter your domain name: " DOMAIN
            USE_EXISTING_CERT=false
        fi
    else
        read -p "Enter your domain name: " DOMAIN
        USE_EXISTING_CERT=false
    fi
}

# Check and install dependencies
install_dependencies() {
    print_info "Checking and installing dependencies..."
    
    # Update package list
    apt-get update
    
    # Essential packages
    PACKAGES=(
        curl
        wget
        gnupg
        lsb-release
        ca-certificates
        software-properties-common
        apt-transport-https
        build-essential
        git
        python3
        python3-pip
        nginx
        certbot
        python3-certbot-nginx
        ufw
        net-tools
        jq
    )
    
    # Docker dependencies
    DOCKER_PACKAGES=(
        docker.io
        docker-compose
        docker-buildx
    )
    
    # Install packages
    for pkg in "${PACKAGES[@]}"; do
        if ! dpkg -l | grep -q "^ii  $pkg "; then
            print_info "Installing $pkg..."
            apt-get install -y "$pkg"
        else
            print_success "$pkg already installed"
        fi
    done
    
    # Install Docker if not present
    if ! command_exists docker; then
        print_info "Installing Docker..."
        apt-get install -y "${DOCKER_PACKAGES[@]}"
        systemctl enable docker
        systemctl start docker
    else
        print_success "Docker already installed"
    fi
    
    # Install Node.js 20.x if not present
    if ! command_exists node || ! node --version | grep -q "v20"; then
        print_info "Installing Node.js 20.x..."
        curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
        apt-get install -y nodejs
    else
        print_success "Node.js already installed: $(node --version)"
    fi
    
    # Install PM2 for Node.js process management
    if ! command_exists pm2; then
        print_info "Installing PM2..."
        npm install -g pm2
    else
        print_success "PM2 already installed"
    fi
}

# Check Asterisk dependencies
check_asterisk_deps() {
    print_info "Checking Asterisk dependencies..."
    
    # Asterisk modules required by Wazo
    ASTERISK_MODULES=(
        "res_pjsip"
        "res_pjsip_session"
        "res_pjsip_pubsub"
        "res_pjsip_outbound_publish"
        "res_http_websocket"
        "res_ari"
        "res_ari_applications"
        "res_ari_asterisk"
        "res_ari_bridges"
        "res_ari_channels"
        "res_ari_device_states"
        "res_ari_endpoints"
        "res_ari_events"
        "res_ari_playbacks"
        "res_ari_recordings"
        "res_ari_sounds"
    )
    
    # These will be handled by Wazo's containerized Asterisk
    print_success "Asterisk modules will be provided by Wazo Platform"
}

# Configure firewall
configure_firewall() {
    print_info "Configuring firewall..."
    
    # Enable UFW if not already enabled
    if ! ufw status | grep -q "Status: active"; then
        ufw --force enable
    fi
    
    # Allow SSH (preserve existing SSH rules)
    ufw allow ssh
    
    # Web ports
    ufw allow 80/tcp comment "HTTP"
    ufw allow 443/tcp comment "HTTPS"
    
    # SIP ports
    ufw allow 5060/tcp comment "SIP TCP"
    ufw allow 5060/udp comment "SIP UDP"
    ufw allow 5061/tcp comment "SIP TLS"
    
    # RTP ports
    ufw allow 10000:20000/udp comment "RTP Media"
    
    # Wazo specific ports
    ufw allow 9486/tcp comment "Wazo confd API"
    ufw allow 9497/tcp comment "Wazo REST API"
    ufw allow 9500/tcp comment "Wazo websocketd"
    
    print_success "Firewall configured"
}

# Install Wazo Platform
install_wazo() {
    print_info "Installing Wazo Platform..."
    
    # Check if Wazo is already installed
    if docker ps --format '{{.Names}}' | grep -q "wazo"; then
        print_warning "Wazo appears to be already installed"
        read -p "Reinstall Wazo? (y/N) " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            return
        fi
        
        # Stop existing Wazo containers
        print_info "Stopping existing Wazo containers..."
        docker-compose -f /etc/wazo-platform/docker-compose.yml down 2>/dev/null || true
    fi
    
    # Create directories first
    mkdir -p "$CONFIG_DIR"
    
    print_info "Checking Wazo installation method..."
    
    # Check if we can download from GitHub releases
    WAZO_INSTALLER_URL="https://github.com/wazo-platform/wazo-install/raw/master/wazo-install.sh"
    
    print_info "Downloading Wazo installer from GitHub..."
    
    # Try to download the installer
    if curl -L "$WAZO_INSTALLER_URL" -o /tmp/wazo-install.sh; then
        print_success "Wazo installer downloaded successfully"
    else
        print_warning "Failed to download from GitHub, trying alternative method..."
        
        # Alternative: Use Docker Compose directly
        print_info "Setting up Wazo using Docker Compose..."
        
        # Create Wazo directory
        mkdir -p /etc/wazo-platform
        
        # Download docker-compose.yml from Wazo repository
        curl -L https://raw.githubusercontent.com/wazo-platform/wazo-platform.org/master/content/uc-doc/installation/docker-compose.yml \
             -o /etc/wazo-platform/docker-compose.yml
        
        if [ ! -f "/etc/wazo-platform/docker-compose.yml" ]; then
            print_error "Failed to download Wazo configuration"
            print_info "Please check https://wazo-platform.org for installation instructions"
            exit 1
        fi
    fi
    
    # Generate and save Wazo credentials
    WAZO_PASSWORD=$(generate_password)
    
    # Save credentials for later use
    cat > "$CONFIG_DIR/wazo-credentials.txt" << EOF
WAZO_ENGINE_FQDN=$DOMAIN
WAZO_ENGINE_INTERNAL_ADDRESS=127.0.0.1
WAZO_ENGINE_SETUPD_USERNAME=airwavepbx
WAZO_ENGINE_SETUPD_PASSWORD=$WAZO_PASSWORD
EOF
    chmod 600 "$CONFIG_DIR/wazo-credentials.txt"
    
    # If installer exists, run it
    if [ -f "/tmp/wazo-install.sh" ]; then
        chmod +x /tmp/wazo-install.sh
        
        print_info "Running Wazo installer (this may take 10-15 minutes)..."
        
        # Export variables for Wazo installer
        export WAZO_ENGINE_FQDN="$DOMAIN"
        export WAZO_ENGINE_INTERNAL_ADDRESS="127.0.0.1"
        export WAZO_ENGINE_SETUPD_USERNAME="airwavepbx"
        export WAZO_ENGINE_SETUPD_PASSWORD="$WAZO_PASSWORD"
        
        # Run installer
        if ! bash /tmp/wazo-install.sh; then
            print_error "Wazo installation failed"
            print_info "Check the error messages above"
            print_info "Credentials saved to: $CONFIG_DIR/wazo-credentials.txt"
            exit 1
        fi
    else
        # Use docker-compose directly
        print_info "Starting Wazo with Docker Compose..."
        cd /etc/wazo-platform
        
        # Create .env file
        cat > .env << EOF
WAZO_ENGINE_FQDN=$DOMAIN
WAZO_ENGINE_INTERNAL_ADDRESS=127.0.0.1
WAZO_ENGINE_SETUPD_USERNAME=airwavepbx
WAZO_ENGINE_SETUPD_PASSWORD=$WAZO_PASSWORD
EOF
        
        docker-compose up -d
    fi
    
    # Wait for Wazo to be ready
    print_info "Waiting for Wazo services to start..."
    sleep 30
    
    # Check Wazo status with retries
    RETRY_COUNT=0
    MAX_RETRIES=6
    while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
        if curl -s http://localhost:9486/api/confd/1.1/infos >/dev/null 2>&1; then
            print_success "Wazo Platform installed successfully"
            break
        else
            RETRY_COUNT=$((RETRY_COUNT + 1))
            if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
                print_warning "Wazo might still be starting"
                print_info "You can check with: curl http://localhost:9486/api/confd/1.1/infos"
                print_info "Continuing with installation..."
            else
                print_info "Waiting for Wazo to start... (attempt $RETRY_COUNT/$MAX_RETRIES)"
                sleep 10
            fi
        fi
    done
}

# Install AirwavePBX
install_airwavepbx() {
    print_info "Installing AirwavePBX..."
    
    # Create directories
    mkdir -p "$INSTALL_DIR"
    mkdir -p "$CONFIG_DIR"
    mkdir -p "$LOG_DIR"
    
    # Extract AirwavePBX files
    print_info "Extracting AirwavePBX files..."
    cp -r * "$INSTALL_DIR/" 2>/dev/null || true
    
    # Install Node.js dependencies
    cd "$INSTALL_DIR"
    print_info "Installing Node.js dependencies..."
    npm install --production
    
    # Build Next.js application
    print_info "Building AirwavePBX frontend..."
    npm run build
    
    # Generate configuration
    print_info "Generating configuration..."
    
    # Load Wazo credentials if they exist
    if [ -f "$CONFIG_DIR/wazo-credentials.txt" ]; then
        source "$CONFIG_DIR/wazo-credentials.txt"
        WAZO_AUTH_USERNAME="airwavepbx"
        WAZO_AUTH_PASSWORD="$WAZO_ENGINE_SETUPD_PASSWORD"
    else
        WAZO_AUTH_USERNAME="airwavepbx"
        WAZO_AUTH_PASSWORD="$(generate_password)"
    fi
    
    cat > "$CONFIG_DIR/airwavepbx.env" << EOF
# AirwavePBX Configuration
NODE_ENV=production
PORT=3000

# Domain
DOMAIN=$DOMAIN
ADMIN_EMAIL=$ADMIN_EMAIL

# Wazo Platform
WAZO_API_URL=http://localhost:9486
WAZO_WEBSOCKET_URL=ws://localhost:9502
WAZO_AUTH_USERNAME=$WAZO_AUTH_USERNAME
WAZO_AUTH_PASSWORD=$WAZO_AUTH_PASSWORD

# Session
SESSION_SECRET=$(generate_password)

# SSL
USE_LETSENCRYPT=$USE_LETSENCRYPT
LETSENCRYPT_EMAIL=$ADMIN_EMAIL
EOF

    # Create PM2 ecosystem file
    cat > "$INSTALL_DIR/ecosystem.config.js" << 'EOF'
module.exports = {
  apps: [{
    name: 'airwavepbx',
    script: 'npm',
    args: 'start',
    cwd: '/opt/airwavepbx',
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    env_file: '/etc/airwavepbx/airwavepbx.env',
    error_file: '/var/log/airwavepbx/error.log',
    out_file: '/var/log/airwavepbx/out.log',
    log_file: '/var/log/airwavepbx/combined.log',
    time: true
  }]
};
EOF

    # Start AirwavePBX with PM2
    print_info "Starting AirwavePBX..."
    pm2 start ecosystem.config.js
    pm2 save
    pm2 startup systemd -u root --hp /root
    
    print_success "AirwavePBX installed"
}

# Configure Nginx
configure_nginx() {
    print_info "Configuring Nginx..."
    
    # Create Nginx configuration
    cat > /etc/nginx/sites-available/airwavepbx << EOF
server {
    listen 80;
    server_name $DOMAIN;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host \$host;
        proxy_cache_bypass \$http_upgrade;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
    }

    # Wazo API proxy
    location /api/wazo/ {
        proxy_pass http://localhost:9486/api/;
        proxy_http_version 1.1;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
    }

    # WebSocket proxy for Wazo
    location /ws {
        proxy_pass http://localhost:9502;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
    }
}
EOF

    # Enable site
    ln -sf /etc/nginx/sites-available/airwavepbx /etc/nginx/sites-enabled/
    
    # Remove default site if it exists
    rm -f /etc/nginx/sites-enabled/default
    
    # Test Nginx configuration
    nginx -t
    
    # Reload Nginx
    systemctl reload nginx
    
    print_success "Nginx configured"
}

# Configure SSL with Let's Encrypt
configure_ssl() {
    if [ "$USE_EXISTING_CERT" = true ]; then
        print_info "Using existing Let's Encrypt certificate for $DOMAIN"
        
        # Update Nginx configuration to use existing certificate
        certbot --nginx -d "$DOMAIN" --redirect --quiet --non-interactive
    else
        print_info "Obtaining new Let's Encrypt certificate..."
        
        # Get new certificate
        certbot --nginx -d "$DOMAIN" --redirect --agree-tos --email "$ADMIN_EMAIL" --non-interactive
    fi
    
    # Set up auto-renewal
    systemctl enable certbot.timer
    systemctl start certbot.timer
    
    print_success "SSL configured with Let's Encrypt"
}

# Create management script
create_management_script() {
    print_info "Creating management script..."
    
    cat > /usr/local/bin/airwavepbx << 'EOF'
#!/bin/bash

case "$1" in
    start)
        pm2 start airwavepbx
        ;;
    stop)
        pm2 stop airwavepbx
        ;;
    restart)
        pm2 restart airwavepbx
        ;;
    status)
        pm2 status airwavepbx
        echo
        echo "Wazo Status:"
        docker ps --filter "name=wazo"
        ;;
    logs)
        pm2 logs airwavepbx --lines 50
        ;;
    wazo-logs)
        docker-compose -f /etc/wazo-platform/docker-compose.yml logs -f --tail=50
        ;;
    update)
        cd /opt/airwavepbx
        git pull
        npm install --production
        npm run build
        pm2 restart airwavepbx
        ;;
    *)
        echo "Usage: airwavepbx {start|stop|restart|status|logs|wazo-logs|update}"
        exit 1
        ;;
esac
EOF

    chmod +x /usr/local/bin/airwavepbx
    print_success "Management script created"
}

# Main installation flow
main() {
    # Get configuration
    detect_letsencrypt
    read -p "Enter admin email address: " ADMIN_EMAIL
    
    # Set SSL configuration
    if [ -z "$USE_EXISTING_CERT" ]; then
        USE_EXISTING_CERT=false
    fi
    USE_LETSENCRYPT=true
    
    # Confirm installation
    echo
    echo "Installation Summary:"
    echo "  Domain: $DOMAIN"
    echo "  Admin Email: $ADMIN_EMAIL"
    echo "  Use existing certificate: $USE_EXISTING_CERT"
    echo
    read -p "Continue with installation? (y/N) " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        exit 1
    fi
    
    # Run installation steps
    install_dependencies
    check_asterisk_deps
    configure_firewall
    install_wazo
    install_airwavepbx
    configure_nginx
    configure_ssl
    create_management_script
    
    # Display completion message
    echo
    echo "============================================="
    echo "Installation Complete!"
    echo "============================================="
    echo
    print_success "AirwavePBX has been installed successfully!"
    echo
    echo "Access your system at: https://$DOMAIN"
    echo
    echo "Wazo Platform credentials saved in:"
    echo "  $CONFIG_DIR/wazo-credentials.txt"
    echo
    echo "AirwavePBX configuration:"
    echo "  $CONFIG_DIR/airwavepbx.env"
    echo
    echo "Management commands:"
    echo "  airwavepbx status    - Check service status"
    echo "  airwavepbx logs      - View application logs"
    echo "  airwavepbx restart   - Restart services"
    echo
    echo "Documentation: https://docs.airwavepbx.com"
    echo
}

# Run main installation
main "$@"