#!/usr/bin/env bash
#
# BamBuddy Docker Installation Script
# Supports: Linux (all distros), macOS
#
# Usage:
#   Interactive:  curl -fsSL https://raw.githubusercontent.com/maziggy/bambuddy/main/install/docker-install.sh -o docker-install.sh && chmod +x docker-install.sh && ./docker-install.sh
#   Unattended:   ./docker-install.sh --path /opt/bambuddy --port 8000 --yes
#
# Options:
#   --path PATH        Installation directory (default: /opt/bambuddy)
#   --port PORT        Port to expose (default: 8000)
#   --tz TIMEZONE      Timezone (default: system timezone or UTC)
#   --build            Build from source instead of using pre-built image
#   --yes, -y          Non-interactive mode, accept defaults
#   --redirect-990     (Deprecated, no longer needed — FTP binds to port 990 directly)
#   --help, -h         Show this help message
#

set -e

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

# Default values
DEFAULT_INSTALL_PATH="/opt/bambuddy"
DEFAULT_PORT="8000"

# Script variables
INSTALL_PATH=""
PORT=""
TIMEZONE=""
BUILD_FROM_SOURCE="false"
NON_INTERACTIVE="false"
OS_TYPE=""
DOCKER_CMD=""
REDIRECT_990="false"

# -----------------------------------------------------------------------------
# Helper Functions
# -----------------------------------------------------------------------------

print_banner() {
    echo -e "${CYAN}"
    echo "╔════════════════════════════════════════════════════════╗"
    echo "║                                                        ║"
    echo "║   ____                  _               _     _        ║"
    echo "║  | __ )  __ _ _ __ ___ | |__  _   _  __| | __| |_   _  ║"
    echo "║  |  _ \\ / _\` | '_ \` _ \\| '_ \\| | | |/ _\` |/ _\` | | | | ║"
    echo "║  | |_) | (_| | | | | | | |_) | |_| | (_| | (_| | |_| | ║"
    echo "║  |____/ \\__,_|_| |_| |_|_.__/ \\__,_|\\__,_|\\__,_|\\__, | ║"
    echo "║                                                 |___/  ║"
    echo "║                                                        ║"
    echo "║            Docker Installation Script                  ║"
    echo "║                                                        ║"
    echo "╚════════════════════════════════════════════════════════╝"
    echo -e "${NC}"
}

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"
}

prompt() {
    local prompt_text="$1"
    local default_value="$2"
    local var_name="$3"

    if [[ "$NON_INTERACTIVE" == "true" ]]; then
        eval "$var_name=\"$default_value\""
        return
    fi

    if [[ -n "$default_value" ]]; then
        echo -en "${BOLD}$prompt_text${NC} [${CYAN}$default_value${NC}]: "
    else
        echo -en "${BOLD}$prompt_text${NC}: "
    fi

    read -r input
    if [[ -z "$input" ]]; then
        eval "$var_name=\"$default_value\""
    else
        eval "$var_name=\"$input\""
    fi
}

prompt_yes_no() {
    local prompt_text="$1"
    local default="$2"  # y or n

    if [[ "$NON_INTERACTIVE" == "true" ]]; then
        [[ "$default" == "y" ]] && return 0 || return 1
    fi

    local yn_hint="[y/n]"
    [[ "$default" == "y" ]] && yn_hint="[Y/n]"
    [[ "$default" == "n" ]] && yn_hint="[y/N]"

    while true; do
        echo -en "${BOLD}$prompt_text${NC} $yn_hint: "
        read -r yn
        [[ -z "$yn" ]] && yn="$default"
        case "$yn" in
            [Yy]* ) return 0;;
            [Nn]* ) return 1;;
            * ) echo "Please answer yes or no.";;
        esac
    done
}

show_help() {
    echo "BamBuddy Docker Installation Script"
    echo ""
    echo "Usage: $0 [OPTIONS]"
    echo ""
    echo "Options:"
    echo "  --path PATH        Installation directory (default: /opt/bambuddy)"
    echo "  --port PORT        Port to expose (default: 8000)"
    echo "  --tz TIMEZONE      Timezone (default: system timezone or UTC)"
    echo "  --build            Build from source instead of using pre-built image"
    echo "  --yes, -y          Non-interactive mode, accept defaults"
    echo "  --redirect-990     (Deprecated, no longer needed)"
    echo "  --help, -h         Show this help message"
    echo ""
    echo "Examples:"
    echo "  Interactive installation:"
    echo "    ./docker-install.sh"
    echo ""
    echo "  Unattended installation with custom settings:"
    echo "    ./docker-install.sh --path /srv/bambuddy --port 3000 --tz America/New_York --yes"
    echo ""
    echo "  Build from source:"
    echo "    ./docker-install.sh --build --yes"
    exit 0
}

# -----------------------------------------------------------------------------
# System Detection
# -----------------------------------------------------------------------------

detect_os() {
    if [[ "$OSTYPE" == "darwin"* ]]; then
        OS_TYPE="macos"
        return
    fi

    if [[ -f /etc/os-release ]]; then
        OS_TYPE="linux"
    else
        log_error "Cannot detect operating system"
        exit 1
    fi
}

detect_docker() {
    # Check for docker compose (v2) or docker-compose (v1)
    if docker compose version &>/dev/null 2>&1; then
        DOCKER_CMD="docker compose"
        log_success "Found Docker Compose v2"
        return 0
    elif docker-compose --version &>/dev/null 2>&1; then
        DOCKER_CMD="docker-compose"
        log_success "Found Docker Compose v1"
        return 0
    fi
    return 1
}

detect_timezone() {
    if [[ -n "$TIMEZONE" ]]; then
        return 0
    fi

    # Try to get system timezone (with error handling for set -e)
    TIMEZONE=""
    if [[ -f /etc/timezone ]]; then
        TIMEZONE=$(cat /etc/timezone 2>/dev/null) || true
    fi

    if [[ -z "$TIMEZONE" ]] && [[ -L /etc/localtime ]]; then
        TIMEZONE=$(readlink /etc/localtime 2>/dev/null | sed 's|.*/zoneinfo/||') || true
    fi

    if [[ -z "$TIMEZONE" ]] && command -v timedatectl &>/dev/null; then
        TIMEZONE=$(timedatectl show --property=Timezone --value 2>/dev/null) || true
    fi

    # Default to UTC if not found (use if/then to avoid set -e issue with &&)
    if [[ -z "$TIMEZONE" ]]; then
        TIMEZONE="UTC"
    fi
    return 0
}

# -----------------------------------------------------------------------------
# Installation Functions
# -----------------------------------------------------------------------------

install_docker() {
    log_info "Docker not found, installing..."

    case "$OS_TYPE" in
        linux)
            # Use Docker's convenience script
            curl -fsSL https://get.docker.com | sh

            # Add current user to docker group
            if [[ -n "$SUDO_USER" ]]; then
                sudo usermod -aG docker "$SUDO_USER"
                log_warn "Added $SUDO_USER to docker group. You may need to log out and back in."
            else
                sudo usermod -aG docker "$USER"
                log_warn "Added $USER to docker group. You may need to log out and back in."
            fi

            # Start Docker service
            sudo systemctl enable docker
            sudo systemctl start docker
            ;;
        macos)
            log_error "Docker Desktop not found."
            log_error "Please install Docker Desktop for Mac from: https://www.docker.com/products/docker-desktop"
            exit 1
            ;;
    esac

    log_success "Docker installed"
}

create_install_dir() {
    log_info "Creating installation directory..."

    mkdir -p "$INSTALL_PATH"
    cd "$INSTALL_PATH"

    log_success "Directory created: $INSTALL_PATH"
}

download_compose_file() {
    log_info "Downloading docker-compose.yml..."

    if [[ "$BUILD_FROM_SOURCE" == "true" ]]; then
        # Clone the full repo for building
        if [[ -d ".git" ]]; then
            log_info "Existing repository found, updating..."
            git fetch origin
            git reset --hard origin/main
        else
            git clone https://github.com/maziggy/bambuddy.git .
        fi
    else
        # Just download the compose file
        curl -fsSL -o docker-compose.yml \
            https://raw.githubusercontent.com/maziggy/bambuddy/main/docker-compose.yml
    fi

    log_success "docker-compose.yml ready"
}

create_env_file() {
    log_info "Creating environment configuration..."

    cat > .env << EOF
# BamBuddy Docker Configuration
# Generated by docker-install.sh on $(date)

# Port BamBuddy runs on
PORT=$PORT

# Timezone
TZ=$TIMEZONE
EOF

    log_success "Environment file created"
}

customize_compose() {
    # Detect if we need to disable host networking (macOS/Windows in Docker Desktop)
    if [[ "$OS_TYPE" == "macos" ]]; then
        log_warn "Docker Desktop detected. Host networking is not supported."
        log_info "Modifying docker-compose.yml for port mapping..."

        # Create a modified compose file for macOS
        if [[ -f docker-compose.yml ]]; then
            # Comment out network_mode: host and uncomment ports section
            sed -i.bak \
                -e 's/^[[:space:]]*network_mode: host/#    network_mode: host/' \
                -e 's/^[[:space:]]*#ports:/    ports:/' \
                -e 's/^[[:space:]]*#[[:space:]]*- "\${PORT:-8000}:8000"/      - "\${PORT:-8000}:8000"/' \
                docker-compose.yml

            log_warn "Printer discovery may not work. Add printers manually by IP address."
        fi
    fi
}

start_container() {
    log_info "Starting BamBuddy..."

    if [[ "$BUILD_FROM_SOURCE" == "true" ]]; then
        $DOCKER_CMD up -d --build
    else
        $DOCKER_CMD up -d
    fi

    # Wait for container to start
    log_info "Waiting for container to start..."
    local max_attempts=15
    local attempt=0

    while [[ $attempt -lt $max_attempts ]]; do
        # Check if container is running (Up)
        if $DOCKER_CMD ps | grep -q "Up"; then
            log_success "BamBuddy container is running"
            return 0
        fi

        # Check if container failed
        if $DOCKER_CMD ps -a | grep -q "Exited"; then
            log_error "Container failed to start"
            log_info "Check logs with: $DOCKER_CMD logs bambuddy"
            return 1
        fi

        sleep 2
        ((attempt++))
    done

    log_warn "Container may still be starting. Check with: $DOCKER_CMD ps"
}

# -----------------------------------------------------------------------------
# Main Installation Flow
# -----------------------------------------------------------------------------

parse_args() {
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --path)
                INSTALL_PATH="$2"
                shift 2
                ;;
            --port)
                PORT="$2"
                shift 2
                ;;
            --tz)
                TIMEZONE="$2"
                shift 2
                ;;
            --build)
                BUILD_FROM_SOURCE="true"
                shift
                ;;
            --yes|-y)
                NON_INTERACTIVE="true"
                shift
                ;;
            --redirect-990)
                REDIRECT_990="true"
                shift
                ;;
            --help|-h)
                show_help
                ;;
            *)
                log_error "Unknown option: $1"
                show_help
                ;;
        esac
    done
}

check_sudo() {
    if ! command -v sudo &>/dev/null; then
        log_error "sudo is required for iptables redirect but is not installed. Skipping iptables redirect."
        return 1
    fi
    if ! command -v iptables &>/dev/null; then
        log_error "iptables is required for iptables redirect but is not installed. Skipping iptables redirect."
        return 1
    fi
    return 0
}

configure_iptables_redirect() {
    # Deprecated: FTP now binds directly to port 990 (requires CAP_NET_BIND_SERVICE).
    # The iptables 990→9990 redirect is no longer needed and caused issues with
    # multi-VP setups (REDIRECT rewrites dest IP to the interface's primary address).
    if [[ "$REDIRECT_990" == "true" ]]; then
        log_warn "The --redirect-990 flag is deprecated. FTP now binds directly to port 990."
        log_warn "No iptables redirect is needed. Skipping."
    fi
}

gather_config() {
    echo ""
    echo -e "${BOLD}Installation Configuration${NC}"
    echo -e "${CYAN}─────────────────────────────────────────${NC}"
    echo ""

    # Installation path
    [[ -z "$INSTALL_PATH" ]] && prompt "Installation directory" "$DEFAULT_INSTALL_PATH" INSTALL_PATH

    # Port
    [[ -z "$PORT" ]] && prompt "Port to expose" "$DEFAULT_PORT" PORT

    # Timezone
    detect_timezone
    prompt "Timezone" "$TIMEZONE" TIMEZONE

    # Build from source?
    if [[ "$BUILD_FROM_SOURCE" != "true" ]] && [[ "$NON_INTERACTIVE" != "true" ]]; then
        if prompt_yes_no "Build from source? (No = use pre-built image)" "n"; then
            BUILD_FROM_SOURCE="true"
        fi
    fi

    # Confirm
    echo ""
    echo -e "${BOLD}Installation Summary${NC}"
    echo -e "${CYAN}─────────────────────────────────────────${NC}"
    echo -e "  Install path:  ${GREEN}$INSTALL_PATH${NC}"
    echo -e "  Port:          ${GREEN}$PORT${NC}"
    echo -e "  Timezone:      ${GREEN}$TIMEZONE${NC}"
    echo -e "  Build source:  ${GREEN}$BUILD_FROM_SOURCE${NC}"
    echo -e "  Redirect 990:  ${GREEN}$REDIRECT_990${NC}"
    echo ""

    if ! prompt_yes_no "Proceed with installation?" "y"; then
        echo "Installation cancelled."
        exit 0
    fi
}

main() {
    parse_args "$@"
    print_banner

    # Check if running via pipe (curl | bash) - interactive mode won't work
    if [[ ! -t 0 ]] && [[ "$NON_INTERACTIVE" != "true" ]]; then
        log_error "Interactive mode requires a terminal."
        log_info "When using 'curl | bash', you must use non-interactive mode:"
        echo ""
        echo "    curl -fsSL URL | bash -s -- --yes"
        echo ""
        log_info "Or download and run directly:"
        echo ""
        echo "    curl -fsSL URL -o docker-install.sh && chmod +x docker-install.sh && ./docker-install.sh"
        echo ""
        exit 1
    fi

    # Detect system
    log_info "Detecting system..."
    detect_os
    log_success "Detected: $OS_TYPE"

    # Check for Docker
    if ! command -v docker &>/dev/null; then
        install_docker
    fi

    if ! detect_docker; then
        log_error "Docker Compose not found. Please install Docker Compose."
        exit 1
    fi

    # Check if Docker daemon is running
    if ! docker info &>/dev/null; then
        log_error "Docker daemon is not running. Please start Docker and try again."
        exit 1
    fi

    # Gather configuration
    gather_config

    # Install steps
    echo ""
    echo -e "${BOLD}Starting Installation${NC}"
    echo -e "${CYAN}─────────────────────────────────────────${NC}"
    echo ""

    create_install_dir
    download_compose_file
    create_env_file
    customize_compose
    start_container
    configure_iptables_redirect

    # Done!
    echo ""
    echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
    echo -e "${GREEN}║                                                              ║${NC}"
    echo -e "${GREEN}║              Installation Complete!                          ║${NC}"
    echo -e "${GREEN}║                                                              ║${NC}"
    echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"
    echo ""
    local ip_addr
    ip_addr=$(hostname -I 2>/dev/null | awk '{print $1}') || ip_addr="<your-ip>"
    echo -e "  ${BOLD}Access BamBuddy:${NC}  ${CYAN}http://localhost:$PORT${NC}"
    echo -e "                    ${CYAN}http://$ip_addr:$PORT${NC} (from other devices)"
    echo ""
    echo -e "  ${BOLD}Manage container:${NC}"
    echo -e "    Status:  cd $INSTALL_PATH && $DOCKER_CMD ps"
    echo -e "    Logs:    cd $INSTALL_PATH && $DOCKER_CMD logs -f bambuddy"
    echo -e "    Stop:    cd $INSTALL_PATH && $DOCKER_CMD down"
    echo -e "    Start:   cd $INSTALL_PATH && $DOCKER_CMD up -d"
    echo -e "    Restart: cd $INSTALL_PATH && $DOCKER_CMD restart"
    echo ""
    echo -e "  ${BOLD}Update BamBuddy:${NC}"
    if [[ "$BUILD_FROM_SOURCE" == "true" ]]; then
        echo -e "    cd $INSTALL_PATH && git pull && $DOCKER_CMD up -d --build"
    else
        echo -e "    cd $INSTALL_PATH && $DOCKER_CMD pull && $DOCKER_CMD up -d"
    fi
    echo ""
    echo -e "  ${BOLD}Data location:${NC}  Docker volumes (bambuddy_data, bambuddy_logs)"
    echo ""
    echo -e "  ${BOLD}Documentation:${NC}  ${CYAN}https://wiki.bambuddy.cool${NC}"
    echo ""

    # Warn about iptables persistence
    if [[ "$REDIRECT_990" == "true" ]] && [[ "$OS_TYPE" == "linux" ]]; then
        echo -e "  ${YELLOW}Note:${NC} iptables redirect rules do NOT survive reboot."
        echo -e "        Install 'iptables-persistent' if persistence is required."
        echo ""
    fi

    if [[ "$OS_TYPE" == "macos" ]]; then
        echo -e "  ${YELLOW}Note:${NC} Printer discovery may not work with Docker Desktop."
        echo -e "        Add printers manually using their IP address."
        echo ""
    fi
}

main "$@"
