#!/bin/bash

# Startup script for ui-apt-mirror
# This script handles the deployment and configuration of the apt-mirror container

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

# Configuration
IMAGE_NAME="ui-apt-mirror"
CONTAINER_NAME="ui-apt-mirror"
DIST_DIR="dist"

# Function to print colored output
print_status() {
    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"
}

# Function to detect system architecture
detect_architecture() {
    print_status "Detecting system architecture..." >&2
    
    local arch=$(uname -m)
    case $arch in
        x86_64)
            echo "amd64"
            ;;
        aarch64|arm64)
            echo "arm64"
            ;;
        *)
            print_error "Unsupported architecture: $arch"
            exit 1
            ;;
    esac
}

# Function to calculate optimal threads and connections based on RAM
calculate_resource_limits() {
    print_status "Calculating optimal resource limits based on available RAM..."
    
    # Get total RAM in KB and convert to MB (fix for ARM64/OpenWrt)
    local total_ram_kb=$(free | awk 'NR==2{print $2}')
    local total_ram_mb=$((total_ram_kb / 1024))
    
    print_status "Total RAM detected: ${total_ram_mb}MB"
    
    # Calculate threads: 1 thread per 700MB RAM
    local calculated_threads=$((total_ram_mb / 700))
    
    # Ensure minimum of 1 thread and maximum of 8 threads
    if [ $calculated_threads -lt 1 ]; then
        calculated_threads=1
    elif [ $calculated_threads -gt 8 ]; then
        calculated_threads=8
    fi
    
    # Calculate connections: 6 connections per 700MB RAM
    local calculated_connections=$((6 * (total_ram_mb / 700)))
    
    # Ensure minimum of 6 connections and maximum of 48 connections
    if [ $calculated_connections -lt 6 ]; then
        calculated_connections=6
    elif [ $calculated_connections -gt 48 ]; then
        calculated_connections=48
    fi
    
    print_success "Calculated optimal settings:"
    print_success "  - Threads: $calculated_threads (1 per 700MB RAM)"
    print_success "  - Connections: $calculated_connections (6 per 700MB RAM)"
    
    # Set global variables
    OPTIMAL_THREADS=$calculated_threads
    OPTIMAL_CONNECTIONS=$calculated_connections
}

# Function to validate dist directory
validate_dist() {
    local arch=$1
    local tar_file="${DIST_DIR}/${IMAGE_NAME}-${arch}.tar.gz"
    
    print_status "Validating distribution files..."
    
    if [ ! -d "$DIST_DIR" ]; then
        print_error "Distribution directory '$DIST_DIR' not found."
        print_error "Please run ./build.sh first to build the images."
        exit 1
    fi
    
    if [ ! -f "$tar_file" ]; then
        print_error "Image file '$tar_file' not found."
        print_error "Please run ./build.sh first to build the images."
        exit 1
    fi
    
    print_success "Found image file: $tar_file"
}

# Function to get user configuration
get_user_config() {
    print_status "Getting user configuration..."
    
    # Default values
    local default_domain="mirror.intra"
    local default_sync_freq="14400"
    local default_admin_pass="admin"
    
    # Get custom domain
    echo ""
    read -p "Enter your custom domain (default: $default_domain): " custom_domain
    custom_domain=${custom_domain:-$default_domain}
    
    # Get sync frequency
    echo ""
    echo "Sync frequency options:"
    echo "  1. Every 4 hours"
    echo "  2. Every 12 hours"
    echo "  3. Every 24 hours"
    read -p "Select sync frequency (1-3, default: 1): " sync_choice
    sync_choice=${sync_choice:-1}
    
    # Convert choice to seconds
    case $sync_choice in
        1)
            sync_freq="14400"
            ;;
        2)
            sync_freq="43200"
            ;;
        3)
            sync_freq="86400"
            ;;
        *)
            print_error "Invalid choice. Using default (Every 4 hours)."
            sync_freq="14400"
            ;;
    esac
    
    # Get admin password
    echo ""
    read -s -p "Enter admin password (default: $default_admin_pass): " admin_pass
    echo ""
    admin_pass=${admin_pass:-$default_admin_pass}
    
    # Ask about npm proxy
    echo ""
    echo "NPM Proxy Configuration:"
    echo "  The npm proxy provides a local caching proxy for npm packages."
    echo "  This can speed up npm installs and reduce bandwidth usage."
    read -p "Do you need a caching npm proxy? (Y/n): " enable_npm_proxy
    enable_npm_proxy=${enable_npm_proxy:-y}
    
    # Detect host timezone
    local host_timezone=$(timedatectl show --property=Timezone --value 2>/dev/null || echo "UTC")
    echo ""
    read -p "Enter timezone (default: $host_timezone): " custom_timezone
    custom_timezone=${custom_timezone:-$host_timezone}
    
    # Set global variables for use in other functions
    MIRROR_DOMAIN="$custom_domain"
    ADMIN_DOMAIN="admin.$custom_domain"
    FILES_DOMAIN="files.$custom_domain"
    NPM_DOMAIN="npm.$custom_domain"
    CHEATSHEETS_DOMAIN="cheatsheets.$custom_domain"
    SYNC_FREQUENCY="$sync_freq"
    ADMIN_PASSWORD="$admin_pass"
    HOST_TIMEZONE="$custom_timezone"
    ENABLE_NPM_PROXY="$enable_npm_proxy"
    
    print_success "Configuration completed."
}

generate_htpasswd() {
    local admin_pass=$1
    
    print_status "Generating htpasswd file..."
    
    mkdir -p data/auth
    
    # Generate SHA-512 hash using openssl
    local pass_hash=$(openssl passwd -6 "$admin_pass")
    echo "admin:$pass_hash" > data/auth/.htpasswd
    
    print_success "htpasswd file generated successfully."
}

# Function to update admin app configuration files
update_admin_config() {
    local domain=$1
    
    print_status "Updating admin app configuration files..."
    
    # Generate a random JWT secret
    local jwt_secret=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-32)
    print_status "Generated JWT secret: ${jwt_secret:0:8}..."
    
    # Determine npm proxy enabled status
    local npm_enabled="false"
    if [ "$ENABLE_NPM_PROXY" = "y" ] || [ "$ENABLE_NPM_PROXY" = "Y" ]; then
        npm_enabled="true"
    fi
    
    # Update config.json
    if [ -f "admin/app/config/config.json" ]; then
        # Replace domain placeholders
        sed -i "s/domain/$domain/g" admin/app/config/config.json
        # Replace npm proxy enabled status
        sed -i "s/\"isNpmProxyEnabled\": true/\"isNpmProxyEnabled\": $npm_enabled/g" admin/app/config/config.json
        sed -i "s/\"isNpmProxyEnabled\": false/\"isNpmProxyEnabled\": $npm_enabled/g" admin/app/config/config.json
        # Replace JWT secret
        sed -i "s/\"jwtSecret\": \"your-secret-key-change-in-production\"/\"jwtSecret\": \"$jwt_secret\"/g" admin/app/config/config.json
    fi
    
    # Update config.build.json
    if [ -f "admin/app/config/config.build.json" ]; then
        # Replace domain placeholders
        sed -i "s/domain/$domain/g" admin/app/config/config.build.json
        # Replace npm proxy enabled status
        sed -i "s/\"isNpmProxyEnabled\": true/\"isNpmProxyEnabled\": $npm_enabled/g" admin/app/config/config.build.json
        sed -i "s/\"isNpmProxyEnabled\": false/\"isNpmProxyEnabled\": $npm_enabled/g" admin/app/config/config.build.json
        # Replace JWT secret
        sed -i "s/\"jwtSecret\": \"your-secret-key-change-in-production\"/\"jwtSecret\": \"$jwt_secret\"/g" admin/app/config/config.build.json
    fi
    
    print_success "Admin app configuration files updated successfully."
    print_success "JWT secret generated and configured in both config files."
}

# Function to generate docker-compose.yml from template
generate_docker_compose() {
    local domain=$1
    local sync_freq=$2
    local timezone=$3
    
    print_status "Generating docker-compose.yml from template..."
    
    # Remove existing docker-compose.yml if it exists
    if [ -f "docker-compose.yml" ]; then
        print_status "Removing existing docker-compose.yml..."
        rm docker-compose.yml
    fi
    
    # Copy source template
    cp docker-compose.src.yml docker-compose.yml
    
    # Replace environment variable references with actual values
    sed -i "s/\${SYNC_FREQUENCY:-3600}/$sync_freq/g" docker-compose.yml
    sed -i "s/\${MIRROR_DOMAIN:-mirror.intra}/$domain/g" docker-compose.yml
    sed -i "s/\${ADMIN_DOMAIN:-admin.mirror.intra}/admin.$domain/g" docker-compose.yml
    sed -i "s/\${FILES_DOMAIN:-files.mirror.intra}/files.$domain/g" docker-compose.yml
    sed -i "s/\${NPM_DOMAIN:-npm.mirror.intra}/npm.$domain/g" docker-compose.yml
    sed -i "s/\${CHEATSHEETS_DOMAIN:-cheatsheets.mirror.intra}/cheatsheets.$domain/g" docker-compose.yml
    
    # Escape timezone for sed (replace / with \/)
    local escaped_timezone=$(echo "$timezone" | sed 's/\//\\\//g')
    sed -i "s/\${TZ:-UTC}/$escaped_timezone/g" docker-compose.yml
    
    print_success "docker-compose.yml generated successfully."
}

# Function to clean up previous installation
cleanup_previous() {
    print_status "Cleaning up previous installation..."
    
    # Stop and remove existing container
    if docker ps -a --format "table {{.Names}}" | grep -q "^${CONTAINER_NAME}$"; then
        print_status "Stopping existing container..."
        docker stop "$CONTAINER_NAME" 2>/dev/null || true
        print_status "Removing existing container..."
        docker rm "$CONTAINER_NAME" 2>/dev/null || true
    fi
    
    # Remove existing images
    if docker images --format "table {{.Repository}}" | grep -q "^${IMAGE_NAME}$"; then
        print_status "Removing existing images..."
        docker rmi "$IMAGE_NAME:latest" 2>/dev/null || true
    fi
    
    print_success "Cleanup completed."
}

# Function to create data directories
create_data_dirs() {
    print_status "Creating data directories..."
    
    mkdir -p data/{data/apt-mirror,data/files,data/npm,data/cheatsheets,logs/apt-mirror,logs/nginx,conf/apt-mirror,conf/nginx/sites-available}
    
    # Set proper permissions
    chmod 755 data/
    chmod 755 data/*
    
    print_success "Data directories created."
}

# Function to generate apt-mirror2 configuration
generate_mirror_config() {
    local domain=$1
    
    print_status "Generating apt-mirror2 configuration..."
    
    cat > data/conf/apt-mirror/mirror.list << EOF
# apt-mirror2 configuration for $domain
# Generated on $(date)

# Set base_path to the directory where you want to store the mirror
set base_path    /var/spool/apt-mirror

# Set mirror_path to the directory where you want to store the mirror
set mirror_path  \$base_path/mirror

# Set skel_path to the directory where you want to store the skeleton
set skel_path    \$base_path/skel

# Set var_path to the directory where you want to store the variable data
set var_path     \$base_path/var

# Set cleanscript to the script that cleans the mirror
set cleanscript  \$var_path/clean.sh

# Set defaultarch to the default architecture
set defaultarch  amd64

# Set postmirror_script to the script that runs after mirroring
set postmirror_script \$var_path/postmirror.sh

# Set run_postmirror to 1 to run the postmirror script
set run_postmirror 0

# Set nthreads to the number of threads to use (calculated based on RAM)
set nthreads     $OPTIMAL_THREADS

# Set _tilde to 1 to download tilde files
set _tilde 0

# Set timeout for downloads (in seconds)
set _timeout 300

# Set retry count for failed downloads
set _retry 3

# Set download speed limit (in bytes per second, 0 = unlimited)
set _limit_rate 16777216

# Set user agent for downloads
set _user_agent "apt-mirror2/14"

# Set number of connections per host (calculated based on RAM)
set _max_connections $OPTIMAL_CONNECTIONS

set release_files_retries 15

# ---start---Ubuntu Noble---
# Ubuntu 24.04 (Noble Numbat) repositories - AMD64 architecture
deb http://archive.ubuntu.com/ubuntu noble main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu noble-updates main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu noble-security main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu noble-backports main restricted universe multiverse
# Usage start
#Types: deb
#URIs: http://mirror.intra/archive.ubuntu.com/ubuntu
#Suites: noble noble-updates noble-security noble-backports
#Components: main restricted universe multiverse
#Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
# Usage end
# ---end---Ubuntu Noble---

# ---start---Debian Bookworm---
# Debian 12 (Bookworm) repositories - AMD64 and ARM64 architectures
#deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
#deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
#deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
#deb http://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware

#deb-src http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
#deb-src http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
#deb-src http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
#deb-src http://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware
# Usage start
#deb http://mirror.intra/deb.debian.org/debian bookworm main non-free-firmware
#deb http://mirror.intra/security.debian.org/debian-security bookworm-security main non-free-firmware
#deb http://mirror.intra/deb.debian.org/debian bookworm-updates main non-free-firmware
# Usage end
# ---end---Debian Bookworm---

# ---start---Debian Trixie---
# Debian 13 (Trixie) repositories - AMD64 and ARM64 architectures
deb http://deb.debian.org/debian trixie main contrib non-free non-free-firmware
deb http://deb.debian.org/debian trixie-updates main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security trixie-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian trixie-backports main contrib non-free non-free-firmware

deb-src http://deb.debian.org/debian trixie main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian trixie-updates main contrib non-free non-free-firmware
deb-src http://security.debian.org/debian-security trixie-security main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian trixie-backports main contrib non-free non-free-firmware
# Usage start
#deb http://mirror.intra/deb.debian.org/debian trixie main non-free-firmware
#deb http://mirror.intra/security.debian.org/debian-security trixie-security main non-free-firmware
#deb http://mirror.intra/deb.debian.org/debian trixie-updates main non-free-firmware
#deb http://mirror.intra/deb.debian.org/debian trixie-backports main non-free-firmware
# Usage end
# ---end---Debian Trixie---

# ---start---Docker Ubuntu Noble---
# Docker CE for Ubuntu 24.04 (Noble Numbat) - AMD64 architecture
deb https://download.docker.com/linux/ubuntu noble stable
# Usage start
#Types: deb
#URIs: http://mirror.intra/download.docker.com/linux/ubuntu
#Suites: noble
#Components: stable
#Trusted: yes
# Usage end
# ---end---Docker Ubuntu Noble---

# ---start---Docker Debian 13---
# Docker CE for Debian 13 (Trixie) - AMD64 architecture
deb https://download.docker.com/linux/debian trixie stable
# Usage start
#deb [trusted=yes] http://mirror.intra/download.docker.com/linux/debian trixie stable
# Usage end
# ---end---Docker Debian 13---


# Clean up old packages
clean http://archive.ubuntu.com/ubuntu
clean http://deb.debian.org/debian
clean http://security.debian.org/debian-security
clean https://download.docker.com/linux/ubuntu
clean https://download.docker.com/linux/debian
EOF
    
    print_success "apt-mirror2 configuration generated with $OPTIMAL_THREADS threads and $OPTIMAL_CONNECTIONS connections."
}

# Function to show status
show_status() {
    print_status "Container status:"
    docker ps --filter "name=$CONTAINER_NAME" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
    
    echo ""
    print_status "Resource Configuration:"
    echo "  Threads: $OPTIMAL_THREADS (1 per 700MB RAM)"
    echo "  Connections: $OPTIMAL_CONNECTIONS (6 per 700MB RAM)"
    
    echo ""
    print_status "Access URLs:"
    if [ -f "docker-compose.yml" ]; then
        # Extract values from generated docker-compose.yml
        local mirror_domain=$(grep "MIRROR_DOMAIN" docker-compose.yml | sed 's/.*MIRROR_DOMAIN: //')
        local admin_domain=$(grep "ADMIN_DOMAIN" docker-compose.yml | sed 's/.*ADMIN_DOMAIN: //')
        local files_domain=$(grep "FILES_DOMAIN" docker-compose.yml | sed 's/.*FILES_DOMAIN: //')
        local cheatsheets_domain=$(grep "CHEATSHEETS_DOMAIN" docker-compose.yml | sed 's/.*CHEATSHEETS_DOMAIN: //')
        
        echo "  Main Repository: http://$mirror_domain"
        echo "  Admin Panel: http://$admin_domain (admin/[password])"
        echo "  File Repository: http://$files_domain"
        echo "  Cheatsheets: http://$cheatsheets_domain"
        
        # Show npm proxy URL if enabled
        if [ "$ENABLE_NPM_PROXY" = "y" ] || [ "$ENABLE_NPM_PROXY" = "Y" ]; then
            echo "  NPM Proxy: http://npm.$mirror_domain"
            echo "    Usage: npm config set registry http://npm.$mirror_domain"
        fi
    else
        echo "  Main Repository: http://mirror.intra"
        echo "  Admin Panel: http://admin.mirror.intra (admin/[password])"
        echo "  File Repository: http://files.mirror.intra"
        echo "  Cheatsheets: http://cheatsheets.mirror.intra"
        
        # Show npm proxy URL if enabled
        if [ "$ENABLE_NPM_PROXY" = "y" ] || [ "$ENABLE_NPM_PROXY" = "Y" ]; then
            echo "  NPM Proxy: http://npm.mirror.intra"
            echo "    Usage: npm config set registry http://npm.mirror.intra"
        fi
    fi
    
    echo ""
    print_status "Logs:"
    echo "  docker logs $CONTAINER_NAME"
    echo "  docker compose -f docker-compose.yml logs"
}

# Function to show usage
show_usage() {
    echo "Usage: $0 [OPTIONS]"
    echo ""
    echo "Options:"
    echo "  --config-only     Only generate configuration, don't start container"
    echo "  --no-cleanup      Skip cleanup of previous installation"
    echo "  --help            Show this help message"
    echo ""
    echo "This script will:"
    echo "  1. Detect your system architecture"
    echo "  2. Calculate optimal resource limits based on available RAM"
    echo "  3. Validate that required image files exist"
    echo "  4. Get your custom configuration"
    echo "  5. Clean up previous installation"
    echo "  6. Create data directories and generate configurations"
    echo "  7. Call start.sh to load image and start container"
    echo ""
    echo "Resource Calculation:"
    echo "  - Threads: 1 per 700MB RAM (min: 1, max: 8)"
    echo "  - Connections: 6 per 700MB RAM (min: 6, max: 48)"
    echo ""
    echo "Prerequisites:"
    echo "  - Docker installed and running"
    echo "  - Built images in dist/ directory (run ./build.sh first)"
    echo "  - htpasswd command (apache2-utils package) for custom passwords"
    echo "    Install with: sudo apt-get install apache2-utils"
}

# Function to update nginx configuration files with custom domain
update_nginx_configs() {
    local domain=$1
    
    print_status "Updating nginx configuration files with domain: $domain..."
    
    # Create nginx sites-available directory if it doesn't exist
    mkdir -p data/conf/nginx/sites-available
    
    # Replace domain in all nginx config files
    for config_file in data/conf/nginx/sites-available/*.conf; do
        if [ -f "$config_file" ]; then
            # Replace mirror.intra with custom domain
            sed -i "s/mirror\.intra/$domain/g" "$config_file"
            # Replace admin.mirror.intra with admin.customdomain
            sed -i "s/admin\.mirror\.intra/admin.$domain/g" "$config_file"
            # Replace files.mirror.intra with files.customdomain
            sed -i "s/files\.mirror\.intra/files.$domain/g" "$config_file"
            # Replace npm.mirror.intra with npm.customdomain
            sed -i "s/npm\.mirror\.intra/npm.$domain/g" "$config_file"
            # Replace cheatsheets.mirror.intra with cheatsheets.customdomain
            sed -i "s/cheatsheets\.mirror\.intra/cheatsheets.$domain/g" "$config_file"
        fi
    done
    
    # Handle npm proxy configuration
    if [ "$ENABLE_NPM_PROXY" = "y" ] || [ "$ENABLE_NPM_PROXY" = "Y" ]; then
        print_status "NPM proxy is enabled. Updating npm proxy configuration..."
        
        # Update domain in the npm config file
        sed -i "s/npm\.mirror\.intra/npm.$domain/g" data/conf/nginx/sites-available/npm.mirror.intra.conf
        
        print_success "NPM proxy configuration updated at: http://npm.$domain"
    else
        print_status "NPM proxy is disabled. Skipping npm proxy configuration."
    fi
    
    print_success "Nginx configuration files updated with domain: $domain"
}

# Main execution
main() {
    local config_only=false
    local no_cleanup=false
    
    # Parse command line arguments
    while [[ $# -gt 0 ]]; do
        case $1 in
            --config-only)
                config_only=true
                shift
                ;;
            --no-cleanup)
                no_cleanup=true
                shift
                ;;
            --help)
                show_usage
                exit 0
                ;;
            *)
                print_error "Unknown option: $1"
                show_usage
                exit 1
                ;;
        esac
    done
    
    print_status "Starting ui-apt-mirror deployment..."
    
    # Detect architecture
    local arch=$(detect_architecture)
    print_success "Detected architecture: $arch"
    
    # Calculate optimal resource limits
    calculate_resource_limits
    
    # Validate dist directory
    validate_dist "$arch"
    
    # Get user configuration
    get_user_config
    
    # Generate nginx htpasswd file
    generate_htpasswd "$ADMIN_PASSWORD"
    
    if [ "$config_only" = true ]; then
        print_success "Configuration completed. Run without --config-only to start the container."
        exit 0
    fi
    
    # Clean up previous installation
    if [ "$no_cleanup" = false ]; then
        cleanup_previous
    fi
    
    # Create data directories
    create_data_dirs
    
    # Generate apt-mirror configuration
    generate_mirror_config "$MIRROR_DOMAIN"
    
    # Update admin app configuration
    update_admin_config "$MIRROR_DOMAIN"
    
    # Generate docker-compose.yml
    generate_docker_compose "$MIRROR_DOMAIN" "$SYNC_FREQUENCY" "$HOST_TIMEZONE"
    
    # Update nginx configuration files with custom domain
    update_nginx_configs "$MIRROR_DOMAIN"
    
    # Start container using start.sh
    print_status "Starting container..."
    ./start.sh
    
    # Show status
    show_status
    
    print_success "Deployment completed successfully!"
}

# Run main function with all arguments
main "$@" 