#!/usr/bin/env bash

# docker-setup.sh
# Cross-platform installer for Retro AIM Server Docker Setup
# Compatible with Linux and macOS

set -e
set -u  # Exit on undefined variables

# ANSI color codes (fallback for POSIX shells that support it)
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'

log()    { printf "%b\n" "${CYAN}[*] $1${NC}" >&2; }
success(){ printf "%b\n" "${GREEN}[✔] $1${NC}" >&2; }
warn()   { printf "%b\n" "${YELLOW}[!] $1${NC}" >&2; }
error()  { printf "%b\n" "${RED}[✖] $1${NC}" >&2; return 1; }

prompt() {
    local varname=$1
    local prompt_text=$2

    if [ -t 0 ] && [ -t 1 ]; then
        # Interactive shell with both stdin and stdout connected to terminal
        printf "%b" "$prompt_text"
        read -r "$varname"
    else
        # Non-interactive shell (like curl | bash) or output redirected
        printf "%b" "$prompt_text" >&2
        read -r "$varname" < /dev/tty
    fi

    # Use eval for POSIX-compatible indirect variable access
    local value
    eval "value=\$$varname"
    if [ -z "$value" ]; then
        printf "%b\n" "${RED}[✖] Input required but not provided.${NC}" >&2
        return 1
    fi
}

check_os() {
    case "$(uname -s)" in
        Linux|Darwin)
            : # supported
            ;;
        *)
            error "Unsupported OS: $(uname -s)"
            return 1
            ;;
    esac
}

check_prereqs() {
    log "Checking for required tools..."
    for cmd in git docker make; do
        if ! command -v "$cmd" >/dev/null 2>&1; then
            error "Missing required command: $cmd"
            return 1
        fi
    done
    success "All prerequisites are installed."
}

stop_existing_services() {
    log "Stopping any existing Docker Compose services..."
    if docker compose ps -q 2>/dev/null | grep -q .; then
        log "Found running services, stopping them..."
        docker compose down 2>/dev/null || true
        success "Stopped existing services."
    else
        log "No running services found."
    fi
}

resolve_repo_root() {
    SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)

    # If this script is inside a Git repo already, use that
    if git -C "$SCRIPT_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
        REPO_ROOT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel)
    else
        TMP_DIR="retro-aim-server"
        if [ -d "$TMP_DIR/.git" ]; then
            warn "Directory '$TMP_DIR' is already a git repo. Using existing directory."
        else
            log "Cloning Retro AIM Server repository..."
            if ! git clone https://github.com/mk6i/retro-aim-server.git "$TMP_DIR"; then
                error "Failed to clone repository"
                return 1
            fi
        fi
        REPO_ROOT=$(cd "$TMP_DIR" && pwd)
    fi
    if ! cd "$REPO_ROOT"; then
        error "Failed to enter repository directory"
        return 1
    fi
}

build_images() {
    log "Building Docker images..."
    if ! make docker-images; then
        error "Docker image build failed"
        return 1
    fi
    success "Docker images built successfully."
}

setup_ssl_cert() {
    if ! prompt OSCAR_HOST "Enter the OSCAR_HOST (e.g., ras.dev): "; then
        return 1
    fi
    
    # Validate OSCAR_HOST format (basic hostname validation)
    if ! echo "$OSCAR_HOST" | grep -qE '^[a-zA-Z0-9]([a-zA-Z0-9.-]*[a-zA-Z0-9])?$'; then
        error "Invalid hostname format: $OSCAR_HOST"
        return 1
    fi
    
    # Export OSCAR_HOST so docker-compose can use it
    export OSCAR_HOST

    log "SSL certificate options:"
    printf "%b\n" "${YELLOW}1) Generate self-signed certificate"
    printf "%b"   "2) Use existing PEM certificate at certs/server.pem${NC}\n"

    if ! prompt cert_choice "${CYAN}Choose an option [1/2]: ${NC}"; then
        return 1
    fi

    case "$cert_choice" in
        1)
            log "Generating self-signed SSL certificate for $OSCAR_HOST..."
            make clean-certs
            log "OSCAR_HOST set to ${OSCAR_HOST}"
            if ! make docker-cert OSCAR_HOST="$OSCAR_HOST"; then
                error "Failed to generate self-signed cert"
                return 1
            fi
            success "Self-signed certificate generated."
            ;;
        2)
            if [ ! -f "certs/server.pem" ]; then
                error "certs/server.pem not found. Please place your PEM file there and rerun."
                return 1
            else
                success "Using existing certificate at certs/server.pem."
            fi
            ;;
        *)
            error "Invalid option for certificate setup."
            return 1
            ;;
    esac
}

generate_nss() {
    log "Generating NSS certificate database..."
    if ! make docker-nss; then
        error "Failed to generate NSS cert DB"
        return 1
    fi
    success "NSS certificate database created at certs/nss/"
}

start_server() {
    log "Starting Retro AIM Server with hostname $OSCAR_HOST..."
    if ! make docker-run-bg OSCAR_HOST="$OSCAR_HOST"; then
        error "Failed to start server"
        return 1
    fi
    success "Retro AIM Server is running."
}

final_steps() {
    printf "%b\n" "${GREEN}
Retro AIM Server setup complete!
===================================
Next Steps:

1. Copy the NSS certs from 'certs/nss/' to each AIM 6.2+ client.

2. Ensure clients can resolve '${OSCAR_HOST}' to your server IP.
   Add the following to each client's hosts file if DNS isn't used:

${YELLOW}127.0.0.1 $OSCAR_HOST${NC}

${GREEN}3. For AIM 6.x client setup instructions, see:
   https://github.com/mk6i/retro-aim-server/blob/main/docs/AIM_6_7.md#aim-62-75-setup

Enjoy!
${NC}" >&2
}

main() {
    check_os || return 1
    check_prereqs || return 1
    resolve_repo_root || return 1
    stop_existing_services || return 1
    build_images || return 1
    setup_ssl_cert || return 1
    generate_nss || return 1
    start_server || return 1
    final_steps
}

main "$@"

