#!/bin/bash

# Rustelo Project Installer
# Comprehensive installation script for the Rustelo Rust web application framework

set -e

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

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$SCRIPT_DIR"
TEMPLATE_DIR="$PROJECT_ROOT/template"
INSTALL_LOG="$PROJECT_ROOT/install.log"
TEMP_DIR=$(mktemp -d)

# Installation options
INSTALL_TYPE="full"
ENVIRONMENT="dev"
ENABLE_TLS=false
ENABLE_AUTH=true
ENABLE_CONTENT_DB=true
ENABLE_OAUTH=false
SKIP_DEPS=false
FORCE_REINSTALL=false
QUIET=false
PROJECT_NAME="my-rustelo-app"
INSTALL_DIR=""

# Dependency versions
RUST_MIN_VERSION="1.75.0"
NODE_MIN_VERSION="18.0.0"
CARGO_LEPTOS_VERSION="0.2.17"

# Trap to cleanup on exit
trap cleanup EXIT

cleanup() {
    if [ -d "$TEMP_DIR" ]; then
        rm -rf "$TEMP_DIR"
    fi
}

# Logging functions
log() {
    echo -e "${GREEN}[INFO]${NC} $1" | tee -a "$INSTALL_LOG"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1" | tee -a "$INSTALL_LOG"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1" | tee -a "$INSTALL_LOG"
}

log_debug() {
    if [ "$QUIET" != true ]; then
        echo -e "${CYAN}[DEBUG]${NC} $1" | tee -a "$INSTALL_LOG"
    fi
}

print_header() {
    echo -e "${BLUE}$1${NC}"
}

print_step() {
    echo -e "${PURPLE}➤${NC} $1"
}

print_success() {
    echo -e "${GREEN}✓${NC} $1"
}

print_banner() {
    echo -e "${WHITE}"
    echo "╭─────────────────────────────────────────────────────────────╮"
    echo "│                     RUSTELO INSTALLER                       │"
    echo "│                                                             │"
    echo "│  A modern Rust web application framework built with Leptos │"
    echo "│                                                             │"
    echo "╰─────────────────────────────────────────────────────────────╯"
    echo -e "${NC}"
}

# Version comparison function
version_compare() {
    local version1="$1"
    local version2="$2"

    # Convert versions to comparable format
    local IFS=.
    local ver1=($version1)
    local ver2=($version2)

    # Compare major version
    if [ ${ver1[0]} -gt ${ver2[0]} ]; then
        return 0
    elif [ ${ver1[0]} -lt ${ver2[0]} ]; then
        return 1
    fi

    # Compare minor version
    if [ ${ver1[1]} -gt ${ver2[1]} ]; then
        return 0
    elif [ ${ver1[1]} -lt ${ver2[1]} ]; then
        return 1
    fi

    # Compare patch version
    if [ ${ver1[2]} -ge ${ver2[2]} ]; then
        return 0
    else
        return 1
    fi
}

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

# Function to get system information
get_system_info() {
    if [[ "$OSTYPE" == "linux-gnu"* ]]; then
        echo "linux"
    elif [[ "$OSTYPE" == "darwin"* ]]; then
        echo "macos"
    elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then
        echo "windows"
    else
        echo "unknown"
    fi
}

# Function to check system requirements
check_system_requirements() {
    print_step "Checking system requirements..."

    local system=$(get_system_info)
    log_debug "Detected system: $system"

    # Check for required tools
    local missing_tools=()

    if ! command_exists "curl" && ! command_exists "wget"; then
        missing_tools+=("curl or wget")
    fi

    if ! command_exists "git"; then
        missing_tools+=("git")
    fi

    if ! command_exists "openssl"; then
        missing_tools+=("openssl")
    fi

    if [ ${#missing_tools[@]} -gt 0 ]; then
        log_error "Missing required system tools: ${missing_tools[*]}"
        echo "Please install these tools before continuing."
        exit 1
    fi

    print_success "System requirements check passed"
}

# Function to install Rust
install_rust() {
    print_step "Checking Rust installation..."

    if command_exists "rustc" && command_exists "cargo"; then
        local rust_version=$(rustc --version | cut -d' ' -f2)
        log_debug "Found Rust version: $rust_version"

        if version_compare "$rust_version" "$RUST_MIN_VERSION"; then
            print_success "Rust $rust_version is already installed"
            return 0
        else
            log_warn "Rust version $rust_version is too old (minimum: $RUST_MIN_VERSION)"
        fi
    fi

    if [ "$SKIP_DEPS" = true ]; then
        log_warn "Skipping Rust installation due to --skip-deps flag"
        return 0
    fi

    log "Installing Rust..."

    # Download and install Rust
    if command_exists "curl"; then
        curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
    elif command_exists "wget"; then
        wget -qO- https://sh.rustup.rs | sh -s -- -y
    else
        log_error "Neither curl nor wget found for Rust installation"
        exit 1
    fi

    # Source the cargo environment
    source "$HOME/.cargo/env"

    # Verify installation
    if command_exists "rustc" && command_exists "cargo"; then
        local rust_version=$(rustc --version | cut -d' ' -f2)
        print_success "Rust $rust_version installed successfully"
    else
        log_error "Rust installation failed"
        exit 1
    fi
}

# Function to install Node.js
install_nodejs() {
    print_step "Checking Node.js installation..."

    if command_exists "node" && command_exists "npm"; then
        local node_version=$(node --version | sed 's/v//')
        log_debug "Found Node.js version: $node_version"

        if version_compare "$node_version" "$NODE_MIN_VERSION"; then
            print_success "Node.js $node_version is already installed"
            return 0
        else
            log_warn "Node.js version $node_version is too old (minimum: $NODE_MIN_VERSION)"
        fi
    fi

    if [ "$SKIP_DEPS" = true ]; then
        log_warn "Skipping Node.js installation due to --skip-deps flag"
        return 0
    fi

    log "Installing Node.js..."

    local system=$(get_system_info)

    case $system in
        "linux")
            # Install Node.js via NodeSource repository
            curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
            sudo apt-get install -y nodejs
            ;;
        "macos")
            # Install Node.js via Homebrew if available, otherwise download
            if command_exists "brew"; then
                brew install node
            else
                log_warn "Homebrew not found. Please install Node.js manually from https://nodejs.org/"
                exit 1
            fi
            ;;
        "windows")
            log_warn "Please install Node.js manually from https://nodejs.org/"
            exit 1
            ;;
        *)
            log_warn "Unknown system. Please install Node.js manually from https://nodejs.org/"
            exit 1
            ;;
    esac

    # Verify installation
    if command_exists "node" && command_exists "npm"; then
        local node_version=$(node --version | sed 's/v//')
        print_success "Node.js $node_version installed successfully"
    else
        log_error "Node.js installation failed"
        exit 1
    fi
}

# Function to install Rust tools
install_rust_tools() {
    print_step "Installing Rust tools..."

    # Install cargo-leptos
    if command_exists "cargo-leptos"; then
        print_success "cargo-leptos is already installed"
    else
        log "Installing cargo-leptos..."
        cargo install cargo-leptos
        print_success "cargo-leptos installed"
    fi

    # Install other useful tools
    local tools=("cargo-watch" "cargo-audit" "cargo-outdated")

    for tool in "${tools[@]}"; do
        if command_exists "$tool"; then
            log_debug "$tool is already installed"
        else
            log "Installing $tool..."
            cargo install "$tool" || log_warn "Failed to install $tool"
        fi
    done
}

# Function to create project directory
create_project() {
    print_step "Setting up project: $PROJECT_NAME"

    # Determine installation directory
    if [ -z "$INSTALL_DIR" ]; then
        INSTALL_DIR="$PWD/$PROJECT_NAME"
    fi

    # Create project directory
    if [ -d "$INSTALL_DIR" ]; then
        if [ "$FORCE_REINSTALL" = true ]; then
            log_warn "Removing existing project directory: $INSTALL_DIR"
            rm -rf "$INSTALL_DIR"
        else
            log_error "Project directory already exists: $INSTALL_DIR"
            echo "Use --force to overwrite or choose a different name/location"
            exit 1
        fi
    fi

    log "Creating project directory: $INSTALL_DIR"
    mkdir -p "$INSTALL_DIR"

    # Copy template files
    log "Copying template files..."
    cp -r "$TEMPLATE_DIR"/* "$INSTALL_DIR"/ || {
        log_error "Failed to copy template files"
        exit 1
    }

    # Copy additional files
    if [ -f "$PROJECT_ROOT/README.md" ]; then
        cp "$PROJECT_ROOT/README.md" "$INSTALL_DIR/"
    fi

    print_success "Project files copied to $INSTALL_DIR"
}

# Function to configure project
configure_project() {
    print_step "Configuring project..."

    cd "$INSTALL_DIR"

    # Create .env file
    if [ ! -f ".env" ]; then
        log "Creating .env file..."
        cat > ".env" << EOF
# Environment Configuration
ENVIRONMENT=$ENVIRONMENT

# Server Configuration
SERVER_HOST=127.0.0.1
SERVER_PORT=3030
SERVER_PROTOCOL=$([ "$ENABLE_TLS" = true ] && echo "https" || echo "http")

# Database Configuration
DATABASE_URL=postgresql://dev:dev@localhost:5432/${PROJECT_NAME}_${ENVIRONMENT}

# Session Configuration
SESSION_SECRET=$(openssl rand -base64 32)

# Features
ENABLE_AUTH=$ENABLE_AUTH
ENABLE_CONTENT_DB=$ENABLE_CONTENT_DB
ENABLE_TLS=$ENABLE_TLS
ENABLE_OAUTH=$ENABLE_OAUTH

# OAuth Configuration (if enabled)
# GOOGLE_CLIENT_ID=
# GOOGLE_CLIENT_SECRET=
# GITHUB_CLIENT_ID=
# GITHUB_CLIENT_SECRET=

# Email Configuration
# SMTP_HOST=
# SMTP_PORT=587
# SMTP_USERNAME=
# SMTP_PASSWORD=
# FROM_EMAIL=
# FROM_NAME=

# Logging
LOG_LEVEL=info
RUST_LOG=info
EOF
        print_success ".env file created"
    else
        log_warn ".env file already exists, skipping creation"
    fi

    # Update Cargo.toml with project name
    if [ -f "Cargo.toml" ]; then
        sed -i.bak "s/name = \"rustelo\"/name = \"$PROJECT_NAME\"/" Cargo.toml
        rm -f Cargo.toml.bak
        log_debug "Updated project name in Cargo.toml"
    fi

    # Create necessary directories
    mkdir -p public uploads logs cache config data backups

    if [ "$ENABLE_TLS" = true ]; then
        mkdir -p certs
        log_debug "Created certs directory for TLS"
    fi

    print_success "Project configured"
}

# Function to install dependencies
install_dependencies() {
    print_step "Installing project dependencies..."

    cd "$INSTALL_DIR"

    # Install Rust dependencies
    log "Installing Rust dependencies..."
    cargo fetch || {
        log_error "Failed to fetch Rust dependencies"
        exit 1
    }

    # Install Node.js dependencies
    if [ -f "package.json" ]; then
        log "Installing Node.js dependencies..."

        # Prefer pnpm, then npm
        if command_exists "pnpm"; then
            pnpm install || {
                log_error "Failed to install Node.js dependencies with pnpm"
                exit 1
            }
        elif command_exists "npm"; then
            npm install || {
                log_error "Failed to install Node.js dependencies with npm"
                exit 1
            }
        else
            log_error "Neither pnpm nor npm found"
            exit 1
        fi
    fi

    print_success "Dependencies installed"
}

# Function to build the project
build_project() {
    print_step "Building project..."

    cd "$INSTALL_DIR"

    # Build CSS
    log "Building CSS..."
    if command_exists "pnpm"; then
        pnpm run build:css || log_warn "Failed to build CSS"
    elif command_exists "npm"; then
        npm run build:css || log_warn "Failed to build CSS"
    fi

    # Build Rust project
    log "Building Rust project..."
    cargo build || {
        log_error "Failed to build Rust project"
        exit 1
    }

    print_success "Project built successfully"
}

# Function to generate TLS certificates
generate_tls_certs() {
    if [ "$ENABLE_TLS" != true ]; then
        return 0
    fi

    print_step "Generating TLS certificates..."

    cd "$INSTALL_DIR"

    if [ -f "certs/server.crt" ] && [ -f "certs/server.key" ]; then
        log_warn "TLS certificates already exist, skipping generation"
        return 0
    fi

    if [ -f "scripts/generate_certs.sh" ]; then
        log "Running certificate generation script..."
        cd scripts
        ./generate_certs.sh
        cd ..
        print_success "TLS certificates generated"
    else
        log "Generating self-signed certificates..."
        openssl req -x509 -newkey rsa:4096 -keyout certs/server.key -out certs/server.crt -days 365 -nodes -subj "/CN=localhost"
        print_success "Self-signed TLS certificates generated"
    fi
}

# Function to run setup scripts
run_setup_scripts() {
    print_step "Running setup scripts..."

    cd "$INSTALL_DIR"

    # Run configuration setup
    if [ -f "scripts/setup-config.sh" ]; then
        log "Running configuration setup..."
        bash scripts/setup-config.sh -e "$ENVIRONMENT" -f || log_warn "Configuration setup failed"
    fi

    # Run feature configuration
    if [ -f "scripts/configure-features.sh" ]; then
        log "Configuring features..."
        bash scripts/configure-features.sh || log_warn "Feature configuration failed"
    fi

    print_success "Setup scripts completed"
}

# Function to run post-installation tasks
post_install() {
    print_step "Running post-installation tasks..."

    cd "$INSTALL_DIR"

    # Create systemd service file (Linux only)
    if [ "$(get_system_info)" = "linux" ] && [ "$ENVIRONMENT" = "prod" ]; then
        log "Creating systemd service file..."
        cat > "$PROJECT_NAME.service" << EOF
[Unit]
Description=$PROJECT_NAME Web Application
After=network.target

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=$INSTALL_DIR
ExecStart=$INSTALL_DIR/target/release/server
Restart=always
RestartSec=10
Environment=RUST_LOG=info

[Install]
WantedBy=multi-user.target
EOF
        log_debug "Systemd service file created: $PROJECT_NAME.service"
    fi

    # Create startup script
    cat > "start.sh" << EOF
#!/bin/bash
cd "\$(dirname "\$0")"
cargo leptos watch
EOF
    chmod +x "start.sh"

    # Create production startup script
    cat > "start-prod.sh" << EOF
#!/bin/bash
cd "\$(dirname "\$0")"
cargo leptos build --release
./target/release/server
EOF
    chmod +x "start-prod.sh"

    print_success "Post-installation tasks completed"
}

# Function to display final instructions
display_instructions() {
    echo
    print_header "╭─────────────────────────────────────────────────────────────╮"
    print_header "│                    INSTALLATION COMPLETE                    │"
    print_header "╰─────────────────────────────────────────────────────────────╯"
    echo

    print_success "Project '$PROJECT_NAME' has been successfully installed!"
    echo
    echo -e "${WHITE}Project Location:${NC} $INSTALL_DIR"
    echo -e "${WHITE}Environment:${NC} $ENVIRONMENT"
    echo -e "${WHITE}Features:${NC}"
    echo "  - Authentication: $ENABLE_AUTH"
    echo "  - Content Database: $ENABLE_CONTENT_DB"
    echo "  - TLS/HTTPS: $ENABLE_TLS"
    echo "  - OAuth: $ENABLE_OAUTH"
    echo
    echo -e "${WHITE}Next Steps:${NC}"
    echo "1. Navigate to your project:"
    echo "   cd $INSTALL_DIR"
    echo
    echo "2. Review and customize your configuration:"
    echo "   - Edit .env file for environment variables"
    echo "   - Review config.toml for detailed settings"
    echo
    echo "3. Start the development server:"
    echo "   ./start.sh"
    echo "   # or manually: cargo leptos watch"
    echo
    echo "4. Open your browser to:"
    if [ "$ENABLE_TLS" = true ]; then
        echo "   https://127.0.0.1:3030"
    else
        echo "   http://127.0.0.1:3030"
    fi
    echo
    echo -e "${WHITE}Available Commands:${NC}"
    echo "  cargo leptos watch     - Start development server with hot reload"
    echo "  cargo leptos build     - Build for production"
    echo "  cargo build           - Build Rust code only"
    echo "  npm run build:css     - Build CSS only"
    echo "  npm run dev           - Watch CSS changes"
    echo

    if [ "$ENABLE_TLS" = true ]; then
        echo -e "${YELLOW}Note:${NC} Self-signed certificates were generated for HTTPS."
        echo "Your browser will show a security warning. This is normal for development."
        echo
    fi

    if [ "$ENVIRONMENT" = "prod" ]; then
        echo -e "${YELLOW}Production Notes:${NC}"
        echo "- Update SESSION_SECRET in .env with a secure value"
        echo "- Configure your database connection string"
        echo "- Set up proper TLS certificates for production"
        echo "- Review all security settings in config.toml"
        echo
    fi

    echo -e "${WHITE}Documentation:${NC}"
    echo "- README.md - General project information"
    echo "- CONFIG_README.md - Configuration guide"
    echo "- DAISYUI_INTEGRATION.md - UI components guide"
    echo
    echo -e "${WHITE}Support:${NC}"
    echo "- Check the logs: $INSTALL_LOG"
    echo "- Run diagnostics: cargo run --bin config_tool -- validate"
    echo
    print_success "Happy coding with Rustelo! 🚀"
}

# Function to show usage information
show_usage() {
    echo "Rustelo Project Installer"
    echo
    echo "Usage: $0 [OPTIONS]"
    echo
    echo "Options:"
    echo "  -h, --help              Show this help message"
    echo "  -t, --type TYPE         Installation type (full, minimal, custom) [default: full]"
    echo "  -e, --env ENV           Environment (dev, prod) [default: dev]"
    echo "  -n, --name NAME         Project name [default: my-rustelo-app]"
    echo "  -d, --dir DIR           Installation directory [default: ./<project-name>]"
    echo "  --enable-tls            Enable TLS/HTTPS support"
    echo "  --enable-oauth          Enable OAuth authentication"
    echo "  --disable-auth          Disable authentication features"
    echo "  --disable-content-db    Disable content database features"
    echo "  --skip-deps             Skip dependency installation"
    echo "  --force                 Force reinstallation (overwrite existing)"
    echo "  --quiet                 Suppress debug output"
    echo
    echo "Installation Types:"
    echo "  full      - Complete installation with all features"
    echo "  minimal   - Basic installation with core features only"
    echo "  custom    - Interactive selection of features"
    echo
    echo "Examples:"
    echo "  $0                                    # Full installation with defaults"
    echo "  $0 -n my-blog -e prod --enable-tls   # Production blog with HTTPS"
    echo "  $0 -t minimal --disable-auth         # Minimal installation without auth"
    echo "  $0 --custom                          # Interactive feature selection"
}

# Function for custom installation
custom_install() {
    print_header "Custom Installation Configuration"
    echo

    # Project name
    echo -n "Project name [$PROJECT_NAME]: "
    read -r input
    if [ -n "$input" ]; then
        PROJECT_NAME="$input"
    fi

    # Environment
    echo -n "Environment (dev/prod) [$ENVIRONMENT]: "
    read -r input
    if [ -n "$input" ]; then
        ENVIRONMENT="$input"
    fi

    # Features
    echo -n "Enable authentication? (y/N): "
    read -r input
    if [[ "$input" =~ ^[Yy]$ ]]; then
        ENABLE_AUTH=true
    else
        ENABLE_AUTH=false
    fi

    echo -n "Enable content database? (y/N): "
    read -r input
    if [[ "$input" =~ ^[Yy]$ ]]; then
        ENABLE_CONTENT_DB=true
    else
        ENABLE_CONTENT_DB=false
    fi

    echo -n "Enable TLS/HTTPS? (y/N): "
    read -r input
    if [[ "$input" =~ ^[Yy]$ ]]; then
        ENABLE_TLS=true
    else
        ENABLE_TLS=false
    fi

    if [ "$ENABLE_AUTH" = true ]; then
        echo -n "Enable OAuth authentication? (y/N): "
        read -r input
        if [[ "$input" =~ ^[Yy]$ ]]; then
            ENABLE_OAUTH=true
        else
            ENABLE_OAUTH=false
        fi
    fi

    echo -n "Skip dependency installation? (y/N): "
    read -r input
    if [[ "$input" =~ ^[Yy]$ ]]; then
        SKIP_DEPS=true
    else
        SKIP_DEPS=false
    fi

    echo
    echo "Configuration Summary:"
    echo "  Project Name: $PROJECT_NAME"
    echo "  Environment: $ENVIRONMENT"
    echo "  Authentication: $ENABLE_AUTH"
    echo "  Content Database: $ENABLE_CONTENT_DB"
    echo "  TLS/HTTPS: $ENABLE_TLS"
    echo "  OAuth: $ENABLE_OAUTH"
    echo "  Skip Dependencies: $SKIP_DEPS"
    echo
    echo -n "Proceed with installation? (Y/n): "
    read -r input
    if [[ "$input" =~ ^[Nn]$ ]]; then
        echo "Installation cancelled."
        exit 0
    fi
}

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_usage
            exit 0
            ;;
        -t|--type)
            INSTALL_TYPE="$2"
            shift 2
            ;;
        -e|--env)
            ENVIRONMENT="$2"
            shift 2
            ;;
        -n|--name)
            PROJECT_NAME="$2"
            shift 2
            ;;
        -d|--dir)
            INSTALL_DIR="$2"
            shift 2
            ;;
        --enable-tls)
            ENABLE_TLS=true
            shift
            ;;
        --enable-oauth)
            ENABLE_OAUTH=true
            shift
            ;;
        --disable-auth)
            ENABLE_AUTH=false
            shift
            ;;
        --disable-content-db)
            ENABLE_CONTENT_DB=false
            shift
            ;;
        --skip-deps)
            SKIP_DEPS=true
            shift
            ;;
        --force)
            FORCE_REINSTALL=true
            shift
            ;;
        --quiet)
            QUIET=true
            shift
            ;;
        *)
            log_error "Unknown option: $1"
            show_usage
            exit 1
            ;;
    esac
done

# Validate arguments
case "$INSTALL_TYPE" in
    "full"|"minimal"|"custom")
        ;;
    *)
        log_error "Invalid installation type: $INSTALL_TYPE"
        exit 1
        ;;
esac

case "$ENVIRONMENT" in
    "dev"|"prod")
        ;;
    *)
        log_error "Invalid environment: $ENVIRONMENT"
        exit 1
        ;;
esac

# Configure installation type
case "$INSTALL_TYPE" in
    "minimal")
        ENABLE_AUTH=false
        ENABLE_CONTENT_DB=false
        ENABLE_TLS=false
        ENABLE_OAUTH=false
        ;;
    "custom")
        custom_install
        ;;
    "full")
        # Use default values
        ;;
esac

# Main installation process
main() {
    print_banner

    # Initialize log
    echo "Installation started at $(date)" > "$INSTALL_LOG"

    # Check if we're in the right directory
    if [ ! -d "$TEMPLATE_DIR" ]; then
        log_error "Template directory not found: $TEMPLATE_DIR"
        log_error "Please run this script from the Rustelo project root"
        exit 1
    fi

    # Run installation steps
    check_system_requirements
    install_rust
    install_nodejs
    install_rust_tools
    create_project
    configure_project
    install_dependencies
    build_project
    generate_tls_certs
    run_setup_scripts
    post_install

    # Display final instructions
    display_instructions

    log "Installation completed successfully at $(date)"
}

# Run main function
main "$@"
