#!/bin/bash
# Calibr Setup Wizard
# Interactive installer for Calibr sports betting prediction system
# Supports both native Python and Docker deployments

set -e

# ============================================================================
# Configuration
# ============================================================================

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

# Set up logging
LOG_DIR="$PROJECT_ROOT/logs"
mkdir -p "$LOG_DIR"
LOG_FILE="$LOG_DIR/setup-$(date +%Y%m%d_%H%M%S).log"

# Redirect stdout/stderr to both console and log file
exec > >(tee -a "$LOG_FILE") 2>&1

# Send trace output (set -x) ONLY to log file on fd 3
exec 3>>"$LOG_FILE"
export BASH_XTRACEFD=3

# Enable verbose command tracing (only goes to log file now)
set -x

echo "==================================================================="
echo "Calibr Setup Wizard"
echo "Started: $(date)"
echo "Full log: $LOG_FILE"
echo "==================================================================="
echo ""

# Source common functions
# shellcheck source=lib/common.sh
source "$SCRIPT_DIR/lib/common.sh"

# ============================================================================
# Global Variables
# ============================================================================

NON_INTERACTIVE=false
DRY_RUN=false
MODE=""
ODDS_API_KEY=""
ENABLE_SSO=false
ENABLE_TELEGRAM=false
ENABLE_ML=false
TELEGRAM_BOT_TOKEN=""
TELEGRAM_CHAT_ID=""
USE_BUNDLED_AUTHENTIK=false
EXTERNAL_AUTHENTIK_URL=""
CALIBR_BASE_URL=""
CALIBR_ALLOWED_HOSTS=""
AUTHENTIK_BASE_URL=""

DETECTED_OS=""
DETECTED_PKG_MANAGER=""
PORT_OVERRIDES=()

# ============================================================================
# Help and Usage
# ============================================================================

show_help() {
    cat << EOF
Calibr Setup Wizard

USAGE:
    $0 [OPTIONS]

OPTIONS:
    -h, --help                  Show this help message
    --non-interactive           Run in non-interactive mode (requires all options)
    --dry-run                   Show what would happen without executing
    --mode MODE                 Deployment mode: native or docker
    --odds-api-key KEY          The Odds API key (required)
    --enable-sso                Enable Authentik SSO (Docker mode only)
    --bundled-authentik         Use bundled Authentik server (with --enable-sso)
    --external-authentik URL    Use external Authentik server URL (with --enable-sso)
    --enable-telegram           Enable Telegram bot notifications
    --enable-ml                 Enable ML prediction models
    --telegram-token TOKEN      Telegram bot token (if --enable-telegram)
    --telegram-chat-id ID       Telegram chat ID (if --enable-telegram)

EXAMPLES:
    # Interactive mode (recommended for first-time setup)
    $0

    # Non-interactive Docker deployment with bundled SSO
    $0 --non-interactive --mode docker --odds-api-key "abc123" --enable-sso --bundled-authentik

    # Non-interactive Docker with external Authentik
    $0 --non-interactive --mode docker --odds-api-key "abc123" --enable-sso --external-authentik "https://auth.example.com"

    # Non-interactive native deployment with ML models
    $0 --non-interactive --mode native --odds-api-key "abc123" --enable-ml

    # Dry run to see what would happen
    $0 --dry-run --mode docker --odds-api-key "abc123" --enable-sso --bundled-authentik

EOF
}

# ============================================================================
# Argument Parsing
# ============================================================================

parse_arguments() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            -h|--help)
                show_help
                exit 0
                ;;
            --non-interactive)
                NON_INTERACTIVE=true
                ;;
            --dry-run)
                DRY_RUN=true
                ;;
            --mode)
                MODE="$2"
                shift
                ;;
            --odds-api-key)
                ODDS_API_KEY="$2"
                shift
                ;;
            --enable-sso)
                ENABLE_SSO=true
                ;;
            --bundled-authentik)
                USE_BUNDLED_AUTHENTIK=true
                ;;
            --external-authentik)
                EXTERNAL_AUTHENTIK_URL="$2"
                shift
                ;;
            --enable-telegram)
                ENABLE_TELEGRAM=true
                ;;
            --enable-ml)
                ENABLE_ML=true
                ;;
            --telegram-token)
                TELEGRAM_BOT_TOKEN="$2"
                shift
                ;;
            --telegram-chat-id)
                TELEGRAM_CHAT_ID="$2"
                shift
                ;;
            *)
                print_error "Unknown option: $1"
                echo "Use --help for usage information"
                exit 1
                ;;
        esac
        shift
    done

    # Validate non-interactive mode
    if [[ "$NON_INTERACTIVE" == true ]]; then
        if [[ -z "$MODE" || -z "$ODDS_API_KEY" ]]; then
            print_error "Non-interactive mode requires --mode and --odds-api-key"
            exit 1
        fi

        if [[ "$MODE" != "native" && "$MODE" != "docker" ]]; then
            print_error "Invalid mode: $MODE (must be 'native' or 'docker')"
            exit 1
        fi

        if [[ "$ENABLE_TELEGRAM" == true ]]; then
            if [[ -z "$TELEGRAM_BOT_TOKEN" || -z "$TELEGRAM_CHAT_ID" ]]; then
                print_error "Telegram enabled but --telegram-token or --telegram-chat-id missing"
                exit 1
            fi
        fi
    fi
}

# ============================================================================
# Welcome Banner
# ============================================================================

show_banner() {
    if [[ "$NON_INTERACTIVE" == true ]]; then
        return
    fi

    cat << "EOF"

   ____      _ _ _
  / ___|__ _| (_) |__  _ __
 | |   / _` | | | '_ \| '__|
 | |__| (_| | | | |_) | |
  \____\__,_|_|_|_.__/|_|

  Sports Betting Prediction System

EOF

    echo "Welcome to the Calibr Setup Wizard!"
    echo ""
    echo "This wizard will guide you through setting up Calibr on your system."
    echo "You can choose between native Python or Docker deployment, and configure"
    echo "optional features like Authentik SSO and Telegram notifications."
    echo ""
}

# ============================================================================
# Platform Detection
# ============================================================================

detect_platform() {
    print_header "Detecting Platform"

    DETECTED_OS=$(detect_os)
    DETECTED_PKG_MANAGER=$(detect_package_manager "$DETECTED_OS")

    local os_name
    os_name=$(get_os_name "$DETECTED_OS")

    if [[ "$DETECTED_OS" == "unknown" ]]; then
        print_warning "Could not detect operating system"
        print_info "Detected OS type: $OSTYPE"
        echo ""
        if [[ "$NON_INTERACTIVE" == true ]]; then
            print_error "Cannot proceed in non-interactive mode on unknown OS"
            exit 1
        fi
        if ! confirm "Continue anyway?"; then
            exit 1
        fi
    else
        print_success "Detected: $os_name ($DETECTED_PKG_MANAGER)"
    fi
}

# ============================================================================
# Mode Selection
# ============================================================================

select_deployment_mode() {
    if [[ -n "$MODE" ]]; then
        print_header "Deployment Mode"
        print_info "Using mode: $MODE"
        return
    fi

    print_header "Deployment Mode"
    echo ""
    echo "How would you like to run Calibr?"
    echo ""
    echo "  1) Native Python"
    echo "     - Best for development and testing"
    echo "     - Runs directly on your system Python"
    echo "     - Uses SQLite database by default"
    echo "     - Easier to debug and modify"
    echo ""
    echo "  2) Docker"
    echo "     - Best for production deployment"
    echo "     - Isolated environment with all dependencies"
    echo "     - Includes PostgreSQL, Redis, Celery workers"
    echo "     - Optional Authentik SSO integration"
    echo ""

    local selection
    selection=$(select_option "Select deployment mode:" \
        "Native Python (development)" \
        "Docker (production)")

    if [[ "$selection" == *"Docker"* ]]; then
        MODE="docker"
    else
        MODE="native"
    fi

    print_success "Selected: $MODE mode"
}

# ============================================================================
# Dependency Checking
# ============================================================================

check_and_install_dependencies() {
    if ! check_dependencies "$MODE" "$DETECTED_PKG_MANAGER"; then
        if [[ "$NON_INTERACTIVE" == true ]]; then
            print_error "Dependency check failed in non-interactive mode"
            exit 1
        fi

        echo ""
        if confirm "Would you like to install missing dependencies?"; then
            install_missing_dependencies
        else
            print_error "Cannot proceed without required dependencies"
            exit 1
        fi
    fi

    # Check port conflicts for Docker mode
    if [[ "$MODE" == "docker" ]]; then
        check_port_conflicts || {
            print_warning "Port conflict check failed, continuing anyway"
        }
    fi
}

check_port_conflicts() {
    local result
    result=$(check_docker_ports "$MODE" "$ENABLE_SSO" 2>&1)
    local port_check_result=$?

    # If no conflicts, return early
    if [[ $port_check_result -eq 0 ]]; then
        return 0
    fi

    # Check if we got valid output
    if [[ ! "$result" =~ CONFLICTS:.*SUGGESTIONS: ]]; then
        print_warning "Port check returned unexpected output, skipping conflict resolution"
        return 0
    fi

    # Parse conflicts and suggestions
    local conflicts_part="${result#*CONFLICTS:}"
    conflicts_part="${conflicts_part%%|*}"
    local suggestions_part="${result#*SUGGESTIONS:}"
    suggestions_part="${suggestions_part%%$'\n'*}"

    # Convert to arrays, handling empty cases
    local conflicts=()
    local suggestions=()

    if [[ -n "$conflicts_part" ]]; then
        IFS='~' read -ra conflicts <<< "$conflicts_part"
    fi

    if [[ -n "$suggestions_part" ]]; then
        IFS='~' read -ra suggestions <<< "$suggestions_part"
    fi

    # Only show if we have actual conflicts
    if [[ ${#conflicts[@]} -eq 0 ]]; then
        return 0
    fi

    echo ""
    print_warning "Port conflicts detected!"
    echo ""
    echo "The following ports are already in use:"
    for conflict in "${conflicts[@]}"; do
        echo "  - $conflict"
    done
    echo ""

    if [[ "$NON_INTERACTIVE" == true ]]; then
        print_error "Port conflicts in non-interactive mode. Please free these ports or use --dry-run to see alternatives."
        exit 1
    fi

    echo "Suggested alternative port configuration:"
    for suggestion in "${suggestions[@]}"; do
        echo "  $suggestion"
    done
    echo ""

    if confirm "Use alternative ports automatically?"; then
        # Store suggestions for use in generate_env_file
        PORT_OVERRIDES=("${suggestions[@]}")
        print_success "Will use alternative ports"
    else
        print_error "Cannot proceed with port conflicts"
        echo ""
        echo "Please either:"
        echo "  1. Stop services using these ports"
        echo "  2. Run with --dry-run to see alternatives and configure manually"
        exit 1
    fi
}

install_missing_dependencies() {
    print_header "Installing Dependencies"

    check_sudo

    if [[ "$MODE" == "docker" ]]; then
        # Install Docker dependencies
        if ! check_command docker; then
            local docker_pkg
            docker_pkg=$(get_package_name "$DETECTED_PKG_MANAGER" "docker")
            if [[ -n "$docker_pkg" ]]; then
                install_package "$DETECTED_PKG_MANAGER" "$docker_pkg"

                # Start Docker service
                case "$DETECTED_PKG_MANAGER" in
                    pacman|dnf)
                        print_step "Starting Docker service..."
                        sudo systemctl enable --now docker
                        ;;
                esac

                # Add user to docker group
                print_step "Adding user to docker group..."
                sudo usermod -aG docker "$USER"
                print_warning "You may need to log out and back in for docker group membership to take effect"
                print_info "Or run: newgrp docker"
            fi
        fi

        if ! check_docker_compose; then
            local compose_pkg
            compose_pkg=$(get_package_name "$DETECTED_PKG_MANAGER" "docker-compose")
            if [[ -n "$compose_pkg" ]]; then
                install_package "$DETECTED_PKG_MANAGER" "$compose_pkg"
            fi
        fi

        if ! check_docker_buildx; then
            print_warning "Docker Buildx not found. Attempting to install..."
            docker buildx install 2>/dev/null || true
        fi
    else
        # Install Python dependencies
        if ! check_python "3.10"; then
            local python_pkg
            python_pkg=$(get_package_name "$DETECTED_PKG_MANAGER" "python3")
            if [[ -n "$python_pkg" ]]; then
                install_package "$DETECTED_PKG_MANAGER" "$python_pkg"
            fi
        fi

        if ! check_python_venv; then
            local venv_pkg
            venv_pkg=$(get_package_name "$DETECTED_PKG_MANAGER" "python3-venv")
            if [[ -n "$venv_pkg" ]]; then
                install_package "$DETECTED_PKG_MANAGER" "$venv_pkg"
            fi
        fi

        if ! check_pip; then
            local pip_pkg
            pip_pkg=$(get_package_name "$DETECTED_PKG_MANAGER" "python3-pip")
            if [[ -n "$pip_pkg" ]]; then
                install_package "$DETECTED_PKG_MANAGER" "$pip_pkg"
            fi
        fi
    fi

    # Re-check dependencies
    echo ""
    if ! check_dependencies "$MODE" "$DETECTED_PKG_MANAGER"; then
        print_error "Dependency installation failed"
        exit 1
    fi
}

# ============================================================================
# SSO Configuration
# ============================================================================

configure_sso_from_scratch() {
    echo ""
    echo "Authentik SSO Setup Options:"
    echo ""
    echo "  1) Bundled Authentik (included with Docker)"
    echo "     - Runs on http://localhost:9000"
    echo "     - Automatically configured"
    echo "     - Requires ~500MB additional disk space"
    echo "     - Recommended for new deployments"
    echo ""
    echo "  2) External Authentik (use existing instance)"
    echo "     - Connect to your own Authentik server"
    echo "     - Requires manual OAuth2 provider setup"
    echo ""

    local sso_choice
    sso_choice=$(select_option "Select SSO configuration:" \
        "Bundled Authentik (recommended)" \
        "External Authentik")

    if [[ "$sso_choice" == *"Bundled"* ]]; then
        ENABLE_SSO=true
        USE_BUNDLED_AUTHENTIK=true
        print_success "Will use bundled Authentik server"

        # Ask about Authentik URL configuration
        echo ""
        local authentik_url_choice
        authentik_url_choice=$(select_option "How will users access Authentik?" \
            "localhost (http://localhost:PORT)" \
            "Custom domain (https://auth.example.com)")

        if [[ "$authentik_url_choice" == *"localhost"* ]]; then
            AUTHENTIK_BASE_URL="http://localhost:\${AUTHENTIK_PORT:-9000}"
            print_info "Authentik will be available at http://localhost:9000"
            print_info "Initial admin setup: http://localhost:9000/if/flow/initial-setup/"
        else
            echo ""
            local authentik_domain
            while [[ -z "$authentik_domain" ]]; do
                read -r -p "Enter Authentik domain (e.g., auth.example.com): " authentik_domain
                if [[ -z "$authentik_domain" ]]; then
                    print_error "Domain cannot be empty"
                fi
            done

            local authentik_protocol
            if confirm "Use HTTPS? (recommended for production)" "y"; then
                authentik_protocol="https"
            else
                authentik_protocol="http"
            fi

            AUTHENTIK_BASE_URL="${authentik_protocol}://${authentik_domain}"
            print_success "Authentik will be available at: $AUTHENTIK_BASE_URL"
            print_info "Make sure your reverse proxy forwards to localhost:\${AUTHENTIK_PORT:-9000}"
        fi
    else
        ENABLE_SSO=true
        USE_BUNDLED_AUTHENTIK=false
        echo ""
        echo "External Authentik Configuration"
        echo ""
        while [[ -z "$EXTERNAL_AUTHENTIK_URL" ]]; do
            read -r -p "Enter your Authentik server URL (e.g., https://auth.example.com): " EXTERNAL_AUTHENTIK_URL
            if ! validate_url "$EXTERNAL_AUTHENTIK_URL"; then
                print_error "Invalid URL format. Please try again."
                EXTERNAL_AUTHENTIK_URL=""
            fi
        done
        # Remove trailing slash
        EXTERNAL_AUTHENTIK_URL="${EXTERNAL_AUTHENTIK_URL%/}"
        print_success "Will connect to external Authentik at $EXTERNAL_AUTHENTIK_URL"
        print_warning "You'll need to configure OAuth2 provider in Authentik admin"
    fi
}

# ============================================================================
# Configuration Collection
# ============================================================================

load_existing_env() {
    if [[ -f "$PROJECT_ROOT/.env" ]]; then
        print_header "Detecting Existing Configuration"
        parse_env_file "$PROJECT_ROOT/.env"
        print_success "Found existing .env file"
        return 0
    fi
    return 1
}

collect_configuration() {
    print_header "Configuration"

    # Try to load existing .env
    local has_existing_env=false
    if load_existing_env; then
        has_existing_env=true
        echo ""
        print_info "Found existing configuration. I'll ask about each setting."
        echo ""
    fi

    # Odds API Key (required)
    if [[ -z "$ODDS_API_KEY" ]]; then
        local existing_key
        existing_key=$(get_env_value "ODDS_API_KEY")

        if [[ -n "$existing_key" ]] && ! is_placeholder "$existing_key"; then
            # Show masked existing value
            local masked
            masked=$(mask_value "$existing_key")
            echo "The Odds API Key: $masked (existing)"
            if confirm "Keep this API key?" "y"; then
                ODDS_API_KEY="$existing_key"
                print_success "Using existing Odds API key"
            else
                while true; do
                    read -r -p "Enter new The Odds API key: " ODDS_API_KEY
                    if validate_api_key "$ODDS_API_KEY"; then
                        break
                    fi
                    print_error "Invalid API key format. Please try again."
                done
            fi
        else
            echo ""
            echo "The Odds API is required for fetching sports odds data."
            echo "Get your free API key at: https://the-odds-api.com/"
            echo ""

            while true; do
                read -r -p "Enter your The Odds API key: " ODDS_API_KEY
                if validate_api_key "$ODDS_API_KEY"; then
                    break
                fi
                print_error "Invalid API key format. Please try again."
            done
        fi
    fi
    if [[ -z "$ODDS_API_KEY" ]] || is_placeholder "$ODDS_API_KEY"; then
        print_error "Valid Odds API key is required"
        exit 1
    fi
    print_success "Odds API key configured"

    # URL Configuration (Docker only)
    if [[ "$MODE" == "docker" ]]; then
        echo ""
        echo "URL Configuration"
        echo ""
        echo "You can configure Calibr to be accessed via:"
        echo "  - localhost (development/testing)"
        echo "  - Custom domain with reverse proxy (production)"
        echo ""

        local url_choice
        url_choice=$(select_option "How will users access Calibr?" \
            "localhost (http://localhost:PORT)" \
            "Custom domain (https://calibr.example.com)")

        if [[ "$url_choice" == *"localhost"* ]]; then
            # Use localhost with port
            CALIBR_BASE_URL="http://localhost:\${WEB_PORT_PROD:-8001}"
            CALIBR_ALLOWED_HOSTS="localhost,127.0.0.1"
            print_success "Using localhost configuration"
        else
            # Custom domain
            echo ""
            local calibr_domain
            while [[ -z "$calibr_domain" ]]; do
                read -r -p "Enter Calibr domain (e.g., calibr.example.com): " calibr_domain
                if [[ -z "$calibr_domain" ]]; then
                    print_error "Domain cannot be empty"
                fi
            done

            local calibr_protocol
            if confirm "Use HTTPS? (recommended for production)" "y"; then
                calibr_protocol="https"
            else
                calibr_protocol="http"
            fi

            CALIBR_BASE_URL="${calibr_protocol}://${calibr_domain}"
            CALIBR_ALLOWED_HOSTS="${calibr_domain},localhost,127.0.0.1"
            print_success "Using custom domain: $CALIBR_BASE_URL"
            print_info "Make sure your reverse proxy forwards to localhost:\${WEB_PORT_PROD:-8001}"
        fi
    fi

    # SSO (Docker only)
    if [[ "$MODE" == "docker" ]] && [[ "$ENABLE_SSO" == false ]]; then
        # Check for existing Authentik configuration
        local existing_oidc_endpoint
        existing_oidc_endpoint=$(get_env_value "OIDC_OP_AUTHORIZATION_ENDPOINT")

        if [[ -n "$existing_oidc_endpoint" ]] && ! is_placeholder "$existing_oidc_endpoint"; then
            echo ""
            echo "Existing Authentik SSO configuration detected:"
            echo "  Endpoint: $existing_oidc_endpoint"
            if confirm "Keep existing SSO configuration?" "y"; then
                ENABLE_SSO=true
                print_success "Using existing SSO configuration"
            else
                configure_sso_from_scratch
            fi
        else
            echo ""
            echo "Authentik SSO provides centralized authentication and user management."
            echo "This is optional and can be configured later if needed."
            echo ""
            if confirm "Enable Authentik SSO integration?"; then
                ENABLE_SSO=true
                configure_sso_from_scratch
            else
                print_info "SSO will be disabled (can be enabled later)"
            fi
        fi
    fi

    # Telegram Bot
    if [[ "$ENABLE_TELEGRAM" == false ]] && [[ "$NON_INTERACTIVE" == false ]]; then
        # Check for existing Telegram config
        local existing_token existing_chat_id
        existing_token=$(get_env_value "TELEGRAM_BOT_TOKEN")
        existing_chat_id=$(get_env_value "TELEGRAM_CHAT_ID")

        # If we have valid existing values, ask if they want to keep
        if [[ -n "$existing_token" ]] && ! is_placeholder "$existing_token" && \
           [[ -n "$existing_chat_id" ]] && ! is_placeholder "$existing_chat_id"; then
            echo ""
            local masked_token masked_chat
            masked_token=$(mask_value "$existing_token")
            masked_chat=$(mask_value "$existing_chat_id")
            echo "Telegram Bot Token: $masked_token (existing)"
            echo "Telegram Chat ID: $masked_chat (existing)"
            if confirm "Keep existing Telegram configuration?" "y"; then
                ENABLE_TELEGRAM=true
                TELEGRAM_BOT_TOKEN="$existing_token"
                TELEGRAM_CHAT_ID="$existing_chat_id"
                print_success "Using existing Telegram configuration"
            else
                if confirm "Configure new Telegram bot?"; then
                    ENABLE_TELEGRAM=true
                    while [[ -z "$TELEGRAM_BOT_TOKEN" ]]; do
                        echo ""
                        echo "Get your bot token from @BotFather on Telegram"
                        read -r -p "Enter Telegram bot token: " TELEGRAM_BOT_TOKEN
                    done
                    while [[ -z "$TELEGRAM_CHAT_ID" ]]; do
                        echo ""
                        echo "Get your chat ID from @userinfobot on Telegram"
                        read -r -p "Enter Telegram chat ID: " TELEGRAM_CHAT_ID
                    done
                    print_success "Telegram bot configured"
                else
                    print_info "Telegram bot will be disabled"
                fi
            fi
        else
            echo ""
            echo "Telegram bot enables real-time notifications for picks and updates."
            echo ""
            if confirm "Enable Telegram bot notifications?"; then
                ENABLE_TELEGRAM=true

                while [[ -z "$TELEGRAM_BOT_TOKEN" ]]; do
                    echo ""
                    echo "Get your bot token from @BotFather on Telegram"
                    read -r -p "Enter Telegram bot token: " TELEGRAM_BOT_TOKEN
                done

                while [[ -z "$TELEGRAM_CHAT_ID" ]]; do
                    echo ""
                    echo "Get your chat ID from @userinfobot on Telegram"
                    read -r -p "Enter Telegram chat ID: " TELEGRAM_CHAT_ID
                done

                print_success "Telegram bot configured"
            else
                print_info "Telegram bot will be disabled (can be enabled later)"
            fi
        fi
    fi

    # ML Models
    if [[ "$ENABLE_ML" == false ]] && [[ "$NON_INTERACTIVE" == false ]]; then
        echo ""
        echo "ML prediction models (XGBoost, LightGBM) enhance prediction accuracy."
        echo "This increases installation time and requires ~500MB additional disk space."
        echo ""
        if confirm "Enable ML prediction models?"; then
            ENABLE_ML=true
            print_success "ML models will be installed"
        else
            print_info "ML models will be disabled (can be enabled later)"
        fi
    fi
}

# ============================================================================
# Environment File Generation
# ============================================================================

generate_env_file() {
    print_header "Generating Configuration"

    cd "$PROJECT_ROOT" || exit 1

    # Backup existing .env
    if [[ -f .env ]]; then
        backup_file .env
    fi

    # Preserve or generate secrets
    local django_secret existing_django_secret
    existing_django_secret=$(get_env_value "DJANGO_SECRET_KEY")
    if [[ -n "$existing_django_secret" ]] && ! is_placeholder "$existing_django_secret"; then
        django_secret="$existing_django_secret"
        print_info "Preserving existing Django secret key"
    else
        django_secret=$(generate_secret 50)
        print_info "Generated new Django secret key"
    fi

    # Preserve or generate DB password
    local db_password existing_db_password
    existing_db_password=$(get_env_value "DB_PASSWORD")
    if [[ -n "$existing_db_password" ]] && ! is_placeholder "$existing_db_password" && [[ "$MODE" == "docker" ]]; then
        db_password="$existing_db_password"
        print_info "Preserving existing database password"
    else
        db_password=$(generate_secret 32)
    fi

    # Generate admin password (always new for security)
    local admin_password
    admin_password=$(generate_secret 16)

    # Preserve Ollama configuration if exists
    local ollama_url ollama_model ollama_timeout
    ollama_url=$(get_env_value "OLLAMA_BASE_URL")
    ollama_model=$(get_env_value "OLLAMA_MODEL")
    ollama_timeout=$(get_env_value "OLLAMA_TIMEOUT")

    # Preserve Authentik secrets if exist
    local authentik_secret authentik_db_password
    authentik_secret=$(get_env_value "AUTHENTIK_SECRET_KEY")
    authentik_db_password=$(get_env_value "AUTHENTIK_POSTGRES_PASSWORD")

    # Create .env file
    cat > .env << EOF
# Calibr Configuration
# Generated by setup.sh on $(date)

# ============================================================================
# API Keys
# ============================================================================

# The Odds API (required)
ODDS_API_KEY=$ODDS_API_KEY

EOF

    # Add Telegram config if enabled
    if [[ "$ENABLE_TELEGRAM" == true ]]; then
        cat >> .env << EOF
# Telegram Bot (optional)
TELEGRAM_BOT_TOKEN=$TELEGRAM_BOT_TOKEN
TELEGRAM_CHAT_ID=$TELEGRAM_CHAT_ID

EOF
    fi

    # Add Django config
    cat >> .env << EOF
# ============================================================================
# Django Configuration
# ============================================================================

DJANGO_SECRET_KEY=$django_secret
DJANGO_DEBUG=false
DJANGO_ALLOWED_HOSTS=${CALIBR_ALLOWED_HOSTS:-localhost,127.0.0.1}

EOF

    # Add Ollama config if exists
    if [[ -n "$ollama_url" ]] && ! is_placeholder "$ollama_url"; then
        cat >> .env << EOF
# ============================================================================
# LLM Configuration (Ollama)
# ============================================================================

OLLAMA_BASE_URL=$ollama_url
EOF
        if [[ -n "$ollama_model" ]] && ! is_placeholder "$ollama_model"; then
            echo "OLLAMA_MODEL=$ollama_model" >> .env
        fi
        if [[ -n "$ollama_timeout" ]] && ! is_placeholder "$ollama_timeout"; then
            echo "OLLAMA_TIMEOUT=$ollama_timeout" >> .env
        fi
        echo "" >> .env
        print_info "Preserved Ollama LLM configuration"
    fi

    # Add Docker-specific config
    if [[ "$MODE" == "docker" ]]; then
        # Extract port overrides if they exist
        local web_port=8001
        local web_port_dev=8000
        local postgres_port=5433
        local valkey_port=6380
        local authentik_port=9000
        local authentik_https_port=9443

        for override in "${PORT_OVERRIDES[@]}"; do
            local key="${override%%=*}"
            local value="${override#*=}"
            case "$key" in
                WEB_PORT_PROD) web_port="$value" ;;
                WEB_PORT) web_port_dev="$value" ;;
                POSTGRES_PORT) postgres_port="$value" ;;
                VALKEY_PORT) valkey_port="$value" ;;
                AUTHENTIK_PORT) authentik_port="$value" ;;
                AUTHENTIK_PORT_HTTPS) authentik_https_port="$value" ;;
            esac
        done

        cat >> .env << EOF
# ============================================================================
# Port Configuration
# ============================================================================

# Web application ports (external)
WEB_PORT=$web_port_dev
WEB_PORT_PROD=$web_port

# Database port (external)
POSTGRES_PORT=$postgres_port

# Cache port (external)
VALKEY_PORT=$valkey_port

# ============================================================================
# Application URLs
# ============================================================================

# Base URL for Calibr web application
CALIBR_BASE_URL=${CALIBR_BASE_URL:-http://localhost:$web_port}

# Base URL for Authentik server (if using SSO)
AUTHENTIK_BASE_URL=${AUTHENTIK_BASE_URL:-http://localhost:\${AUTHENTIK_PORT:-9000}}

EOF

        if [[ "$ENABLE_SSO" == true ]]; then
            cat >> .env << EOF
# Authentik ports (external)
AUTHENTIK_PORT=$authentik_port
AUTHENTIK_PORT_HTTPS=$authentik_https_port

EOF
        fi

        cat >> .env << EOF
# ============================================================================
# Database (PostgreSQL for Docker)
# ============================================================================

DB_ENGINE=postgres
DB_NAME=calibr
DB_USER=calibr
DB_PASSWORD=$db_password
DB_HOST=db
DB_PORT=5432

# ============================================================================
# Cache (Redis/Valkey)
# ============================================================================

REDIS_URL=redis://valkey:6379/0
CELERY_BROKER_URL=redis://valkey:6379/1

EOF

        # Add SSO config if enabled
        if [[ "$ENABLE_SSO" == true ]]; then
            # Always generate new secrets or preserve existing valid ones
            if [[ -z "$authentik_secret" ]] || is_placeholder "$authentik_secret" || [[ ${#authentik_secret} -lt 20 ]]; then
                authentik_secret=$(generate_secret 60)
                print_info "Generated new Authentik secret key (60 chars)"
            else
                print_info "Preserved existing Authentik secret key"
            fi

            if [[ -z "$authentik_db_password" ]] || is_placeholder "$authentik_db_password" || [[ ${#authentik_db_password} -lt 16 ]]; then
                authentik_db_password=$(generate_secret 32)
                print_info "Generated new Authentik database password (32 chars)"
            else
                print_info "Preserved existing Authentik database password"
            fi

            # Ensure secrets are not empty (failsafe)
            if [[ -z "$authentik_secret" ]]; then
                authentik_secret=$(generate_secret 60)
                print_warning "Failsafe: Generated Authentik secret key"
            fi
            if [[ -z "$authentik_db_password" ]]; then
                authentik_db_password=$(generate_secret 32)
                print_warning "Failsafe: Generated Authentik database password"
            fi

            # Set OIDC endpoints based on configuration
            local auth_base_url
            local auth_type="bundled"
            if [[ -n "$AUTHENTIK_BASE_URL" ]]; then
                # Use the URL configured during setup
                auth_base_url="$AUTHENTIK_BASE_URL"
                if [[ "$USE_BUNDLED_AUTHENTIK" == true ]]; then
                    print_info "Configured bundled Authentik endpoint: $auth_base_url"
                else
                    auth_type="external"
                    print_info "Configured external Authentik endpoint: $auth_base_url"
                fi
            elif [[ -n "$EXTERNAL_AUTHENTIK_URL" ]]; then
                # External Authentik
                auth_type="external"
                auth_base_url="$EXTERNAL_AUTHENTIK_URL"
                print_info "Configured for external Authentik: $auth_base_url"
            else
                # Preserve existing or use default
                local existing_endpoint
                existing_endpoint=$(get_env_value "OIDC_OP_AUTHORIZATION_ENDPOINT")
                if [[ -n "$existing_endpoint" ]] && ! is_placeholder "$existing_endpoint"; then
                    # Extract base URL from existing endpoint
                    auth_base_url=$(echo "$existing_endpoint" | sed -E 's|(https?://[^/]+).*|\1|')
                    print_info "Preserved existing Authentik endpoint ($auth_base_url)"
                else
                    auth_base_url="http://localhost:9000"
                    print_info "Using default bundled Authentik (localhost:9000)"
                fi
            fi

            # Write Authentik configuration
            print_info "Writing Authentik secrets to .env (secret: ${#authentik_secret} chars, password: ${#authentik_db_password} chars)"

            cat >> .env << EOF
# ============================================================================
# Authentik SSO
# ============================================================================

# Authentik server secrets (required for SSO)
AUTHENTIK_SECRET_KEY=$authentik_secret
AUTHENTIK_POSTGRES_PASSWORD=$authentik_db_password

# OAuth2 / OIDC Configuration
# OIDC will be disabled until you complete Authentik setup
OIDC_ENABLED=false
OIDC_RP_CLIENT_ID=calibr
OIDC_RP_CLIENT_SECRET=change-after-authentik-setup

# Authentik endpoints (automatically configured)
OIDC_OP_AUTHORIZATION_ENDPOINT=$auth_base_url/application/o/authorize/
OIDC_OP_TOKEN_ENDPOINT=$auth_base_url/application/o/token/
OIDC_OP_USER_ENDPOINT=$auth_base_url/application/o/userinfo/
OIDC_OP_JWKS_ENDPOINT=$auth_base_url/application/o/calibr/jwks/
OIDC_OP_LOGOUT_ENDPOINT=$auth_base_url/application/o/calibr/end-session/

EOF
        fi
    else
        cat >> .env << EOF
# ============================================================================
# Database (SQLite for Native)
# ============================================================================

DB_ENGINE=sqlite
DATABASE_PATH=data/db.sqlite3

EOF
    fi

    # Add ML config if enabled
    if [[ "$ENABLE_ML" == true ]]; then
        cat >> .env << EOF
# ============================================================================
# Machine Learning Models
# ============================================================================

ENABLE_ML_MODELS=true

EOF
    fi

    chmod 600 .env
    print_success "Created .env file"

    # Save credentials
    if [[ "$MODE" == "docker" ]]; then
        cat > .admin-credentials << EOF
Calibr Admin Credentials
Generated: $(date)

Web App: http://localhost:8000
Admin Username: admin
Admin Password: $admin_password

Database Password: $db_password

EOF
        chmod 600 .admin-credentials
        print_success "Saved credentials to .admin-credentials"
    fi
}

# ============================================================================
# Deployment
# ============================================================================

setup_authentik_blueprint() {
    if [[ "$ENABLE_SSO" != true ]] || [[ "$USE_BUNDLED_AUTHENTIK" != true ]]; then
        return
    fi

    print_header "Configuring Authentik Blueprint"

    # Create blueprints directory
    mkdir -p "$PROJECT_ROOT/docker/authentik-blueprints"

    # Copy blueprint file
    if [[ -f "$PROJECT_ROOT/docker/authentik-blueprint-calibr.yaml" ]]; then
        cp "$PROJECT_ROOT/docker/authentik-blueprint-calibr.yaml" \
           "$PROJECT_ROOT/docker/authentik-blueprints/calibr.yaml"
        print_success "Blueprint configured for auto-import"
        print_info "OAuth2 provider will be created automatically on Authentik first start"
    else
        print_warning "Blueprint template not found, skipping auto-configuration"
    fi

    # Generate docker-compose override for blueprint mounting
    if [[ ! -f "$PROJECT_ROOT/docker-compose.authentik.yml" ]]; then
        cat > "$PROJECT_ROOT/docker-compose.authentik.yml" << 'EOF'
# Auto-generated by setup.sh - Authentik blueprint auto-import
# Include with: docker compose -f docker-compose.yml -f docker-compose.authentik.yml up -d
version: '3.8'

services:
  authentik_server:
    volumes:
      - ./docker/authentik-blueprints:/blueprints/custom:ro

  authentik_worker:
    volumes:
      - ./docker/authentik-blueprints:/blueprints/custom:ro
EOF
        print_success "Created docker-compose.authentik.yml for blueprint mounting"
        print_info "Blueprints will be auto-imported on Authentik startup"
    fi
}

run_deployment() {
    if [[ "$DRY_RUN" == true ]]; then
        print_header "Dry Run - Deployment"
        print_info "Would execute: $MODE deployment"
        return
    fi

    print_header "Deploying Calibr"

    cd "$PROJECT_ROOT" || exit 1

    # Setup Authentik blueprint if SSO enabled
    if [[ "$MODE" == "docker" ]]; then
        setup_authentik_blueprint
    fi

    if [[ "$MODE" == "native" ]]; then
        print_step "Running native Python installer..."
        "$SCRIPT_DIR/install.sh"
    else
        print_step "Running Docker quick-start..."

        # Pass --with-sso flag if SSO enabled
        if [[ "$ENABLE_SSO" == true ]]; then
            "$PROJECT_ROOT/docker/quick-start.sh" --with-sso
        else
            "$PROJECT_ROOT/docker/quick-start.sh"
        fi
    fi
}

# ============================================================================
# Post-Installation
# ============================================================================

show_post_install_info() {
    print_header "Installation Complete!"

    echo ""
    echo "Calibr has been successfully installed!"
    echo ""

    if [[ "$MODE" == "docker" ]]; then
        # Get ports from .env or use defaults
        local web_port
        local authentik_port
        web_port=$(get_env_value "WEB_PORT")
        web_port="${web_port:-8000}"
        authentik_port=$(get_env_value "AUTHENTIK_PORT")
        authentik_port="${authentik_port:-9000}"

        cat << EOF
🌐 Web Application:  http://localhost:$web_port
👤 Admin Login:      Check .admin-credentials file

📋 Next Steps:
  1. Access the web app at http://localhost:8000
  2. Log in with credentials from .admin-credentials
  3. Configure league thresholds in Django admin
  4. View predictions and place bets!

🔧 Managing Services:
  Start:    docker compose up -d
  Stop:     docker compose down
  Logs:     docker compose logs -f
  Restart:  docker compose restart

EOF

        if [[ "$ENABLE_SSO" == true ]]; then
            if [[ "$USE_BUNDLED_AUTHENTIK" == true ]]; then
                cat << EOF
🔐 Authentik SSO Setup (Bundled Server - Auto-Configured!)

Authentik OAuth2 provider has been pre-configured via blueprint!
You only need to complete initial setup and get the client secret:

Step 1: Create Authentik Admin Account
  URL: http://localhost:$authentik_port/if/flow/initial-setup/

  Create your Authentik admin account (recommended username: akadmin)
  Note: This is separate from Calibr admin - it manages SSO

Step 2: Verify Auto-Configuration
  1. Log into Authentik admin: http://localhost:$authentik_port
  2. Go to Applications → Applications
  3. You should see "Calibr Sports Betting" application (auto-created!)
  4. Go to Applications → Providers
  5. Click on "calibr" provider
  6. Copy the Client Secret (shown once)

Step 3: Enable OIDC in Calibr
  1. Edit .env file:
     - Set OIDC_ENABLED=true
     - Set OIDC_RP_CLIENT_SECRET=<paste-secret-from-step-2>
  2. Restart: docker compose restart web

Step 4: Test SSO Login
  1. Visit http://localhost:$web_port
  2. Click "Login with SSO"
  3. Authenticate with your Authentik credentials
  4. Grant access to Calibr

✨ The OAuth2 provider and application were created automatically!
   You only needed to create the admin account and copy the secret.

📚 Full Setup Guide: docs/06-operations/07-authentik-setup.md
🔧 Blueprint Location: docker/authentik-blueprints/calibr.yaml

EOF
            else
                cat << EOF
🔐 Authentik SSO Setup (External Server)

You configured an external Authentik server.

Complete the setup:
  1. Create OAuth2 provider in your Authentik admin
  2. Use Client ID: calibr
  3. Add redirect URI: http://localhost:8000/oidc/callback/
  4. Copy the Client Secret
  5. Update .env:
     - Set OIDC_ENABLED=true
     - Set OIDC_RP_CLIENT_SECRET=<your-client-secret>
  6. Restart: docker compose restart web

📚 Detailed Guide: docs/06-operations/07-authentik-setup.md

EOF
            fi
        fi
    else
        cat << EOF
🌐 Web Application:
  Start:   cd packages/webapp && python manage.py runserver
  Access:  http://localhost:8000

📋 Next Steps:
  1. Activate the virtual environment: source venv/bin/activate
  2. Start the web app (see command above)
  3. Configure league thresholds in Django admin
  4. View predictions and place bets!

🔧 Database:
  Location:  data/db.sqlite3
  Backup:    cp data/db.sqlite3 data/db.sqlite3.backup

EOF
    fi

    cat << EOF
📚 Documentation:
  Quick Start:  README.md
  Full Docs:    docs/README.md
  Web App:      docs/03-user-guide/02-web-app.md

🐛 Troubleshooting:
  Issues:  docs/03-user-guide/04-troubleshooting.md
  Support: https://github.com/noahwoltje/sports_betting_bot/issues

EOF

    if [[ "$NON_INTERACTIVE" == false ]]; then
        echo ""
        if [[ "$MODE" == "docker" ]]; then
            if command -v xdg-open >/dev/null 2>&1; then
                if confirm "Open web app in browser?"; then
                    xdg-open http://localhost:8000 2>/dev/null || true
                fi
            fi
        fi
    fi
}

# ============================================================================
# Main Execution
# ============================================================================

main() {
    parse_arguments "$@"

    show_banner

    detect_platform

    select_deployment_mode

    check_and_install_dependencies

    collect_configuration

    generate_env_file

    run_deployment

    show_post_install_info

    echo ""
    print_success "Setup complete!"
    echo ""
    echo "==================================================================="
    echo "Setup completed: $(date)"
    echo "Full log saved to: $LOG_FILE"
    echo "==================================================================="
}

# Run main function
main "$@"
