# Rustelo Project Installer for Windows
# PowerShell script for installing and setting up Rustelo projects

param(
    [string]$ProjectName = "my-rustelo-app",
    [string]$Environment = "dev",
    [string]$InstallDir = "",
    [switch]$EnableTLS,
    [switch]$EnableOAuth,
    [switch]$DisableAuth,
    [switch]$DisableContentDB,
    [switch]$SkipDeps,
    [switch]$Force,
    [switch]$Quiet,
    [switch]$Help
)

# Set error action preference
$ErrorActionPreference = "Stop"

# Colors for output
$Colors = @{
    Red = "Red"
    Green = "Green"
    Yellow = "Yellow"
    Blue = "Blue"
    Purple = "Magenta"
    Cyan = "Cyan"
    White = "White"
}

# Configuration
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$ProjectRoot = $ScriptDir
$TemplateDir = Join-Path $ProjectRoot "template"
$InstallLog = Join-Path $ProjectRoot "install.log"

# Installation options
$ENABLE_AUTH = -not $DisableAuth
$ENABLE_CONTENT_DB = -not $DisableContentDB
$ENABLE_TLS = $EnableTLS
$ENABLE_OAUTH = $EnableOAuth

# Dependency versions
$RUST_MIN_VERSION = "1.75.0"
$NODE_MIN_VERSION = "18.0.0"

# Logging functions
function Write-Log {
    param([string]$Message, [string]$Level = "INFO")

    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "[$timestamp] [$Level] $Message"

    switch ($Level) {
        "INFO" { Write-Host "[INFO] $Message" -ForegroundColor $Colors.Green }
        "WARN" { Write-Host "[WARN] $Message" -ForegroundColor $Colors.Yellow }
        "ERROR" { Write-Host "[ERROR] $Message" -ForegroundColor $Colors.Red }
        "DEBUG" {
            if (-not $Quiet) {
                Write-Host "[DEBUG] $Message" -ForegroundColor $Colors.Cyan
            }
        }
    }

    Add-Content -Path $InstallLog -Value $logEntry
}

function Write-Header {
    param([string]$Message)
    Write-Host $Message -ForegroundColor $Colors.Blue
}

function Write-Step {
    param([string]$Message)
    Write-Host "➤ $Message" -ForegroundColor $Colors.Purple
}

function Write-Success {
    param([string]$Message)
    Write-Host "✓ $Message" -ForegroundColor $Colors.Green
}

function Write-Banner {
    Write-Host ""
    Write-Host "╭─────────────────────────────────────────────────────────────╮" -ForegroundColor $Colors.White
    Write-Host "│                     RUSTELO INSTALLER                       │" -ForegroundColor $Colors.White
    Write-Host "│                                                             │" -ForegroundColor $Colors.White
    Write-Host "│  A modern Rust web application framework built with Leptos │" -ForegroundColor $Colors.White
    Write-Host "│                                                             │" -ForegroundColor $Colors.White
    Write-Host "╰─────────────────────────────────────────────────────────────╯" -ForegroundColor $Colors.White
    Write-Host ""
}

# Function to check if a command exists
function Test-Command {
    param([string]$Command)
    return (Get-Command $Command -ErrorAction SilentlyContinue) -ne $null
}

# Function to compare versions
function Compare-Version {
    param([string]$Version1, [string]$Version2)

    $v1 = [version]$Version1
    $v2 = [version]$Version2

    return $v1 -ge $v2
}

# Function to check system requirements
function Test-SystemRequirements {
    Write-Step "Checking system requirements..."

    $missingTools = @()

    if (-not (Test-Command "git")) {
        $missingTools += "git"
    }

    if ($missingTools.Count -gt 0) {
        Write-Log "Missing required system tools: $($missingTools -join ', ')" -Level "ERROR"
        Write-Host "Please install these tools before continuing."
        exit 1
    }

    Write-Success "System requirements check passed"
}

# Function to install Rust
function Install-Rust {
    Write-Step "Checking Rust installation..."

    if ((Test-Command "rustc") -and (Test-Command "cargo")) {
        $rustVersion = (rustc --version).Split()[1]
        Write-Log "Found Rust version: $rustVersion" -Level "DEBUG"

        if (Compare-Version $rustVersion $RUST_MIN_VERSION) {
            Write-Success "Rust $rustVersion is already installed"
            return
        } else {
            Write-Log "Rust version $rustVersion is too old (minimum: $RUST_MIN_VERSION)" -Level "WARN"
        }
    }

    if ($SkipDeps) {
        Write-Log "Skipping Rust installation due to -SkipDeps flag" -Level "WARN"
        return
    }

    Write-Log "Installing Rust..."

    # Download and install Rust
    $rustupUrl = "https://win.rustup.rs/x86_64"
    $rustupPath = Join-Path $env:TEMP "rustup-init.exe"

    try {
        Invoke-WebRequest -Uri $rustupUrl -OutFile $rustupPath
        & $rustupPath -y

        # Add Cargo to PATH for current session
        $env:PATH = "$env:USERPROFILE\.cargo\bin;$env:PATH"

        # Verify installation
        if ((Test-Command "rustc") -and (Test-Command "cargo")) {
            $rustVersion = (rustc --version).Split()[1]
            Write-Success "Rust $rustVersion installed successfully"
        } else {
            Write-Log "Rust installation failed" -Level "ERROR"
            exit 1
        }
    } catch {
        Write-Log "Failed to install Rust: $_" -Level "ERROR"
        exit 1
    } finally {
        if (Test-Path $rustupPath) {
            Remove-Item $rustupPath -Force
        }
    }
}

# Function to install Node.js
function Install-NodeJS {
    Write-Step "Checking Node.js installation..."

    if ((Test-Command "node") -and (Test-Command "npm")) {
        $nodeVersion = (node --version).TrimStart('v')
        Write-Log "Found Node.js version: $nodeVersion" -Level "DEBUG"

        if (Compare-Version $nodeVersion $NODE_MIN_VERSION) {
            Write-Success "Node.js $nodeVersion is already installed"
            return
        } else {
            Write-Log "Node.js version $nodeVersion is too old (minimum: $NODE_MIN_VERSION)" -Level "WARN"
        }
    }

    if ($SkipDeps) {
        Write-Log "Skipping Node.js installation due to -SkipDeps flag" -Level "WARN"
        return
    }

    Write-Log "Node.js installation required"
    Write-Host "Please install Node.js manually from https://nodejs.org/"
    Write-Host "Then run this script again."
    exit 1
}

# Function to install Rust tools
function Install-RustTools {
    Write-Step "Installing Rust tools..."

    if (Test-Command "cargo-leptos") {
        Write-Success "cargo-leptos is already installed"
    } else {
        Write-Log "Installing cargo-leptos..."
        cargo install cargo-leptos
        Write-Success "cargo-leptos installed"
    }

    # Install other useful tools
    $tools = @("cargo-watch", "cargo-audit", "cargo-outdated")

    foreach ($tool in $tools) {
        if (Test-Command $tool) {
            Write-Log "$tool is already installed" -Level "DEBUG"
        } else {
            Write-Log "Installing $tool..."
            try {
                cargo install $tool
            } catch {
                Write-Log "Failed to install $tool" -Level "WARN"
            }
        }
    }
}

# Function to create project
function New-Project {
    Write-Step "Setting up project: $ProjectName"

    # Determine installation directory
    if (-not $InstallDir) {
        $InstallDir = Join-Path (Get-Location) $ProjectName
    }

    # Create project directory
    if (Test-Path $InstallDir) {
        if ($Force) {
            Write-Log "Removing existing project directory: $InstallDir" -Level "WARN"
            Remove-Item $InstallDir -Recurse -Force
        } else {
            Write-Log "Project directory already exists: $InstallDir" -Level "ERROR"
            Write-Host "Use -Force to overwrite or choose a different name/location"
            exit 1
        }
    }

    Write-Log "Creating project directory: $InstallDir"
    New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null

    # Copy template files
    Write-Log "Copying template files..."
    try {
        Copy-Item -Path "$TemplateDir\*" -Destination $InstallDir -Recurse -Force
    } catch {
        Write-Log "Failed to copy template files: $_" -Level "ERROR"
        exit 1
    }

    # Copy additional files
    $readmePath = Join-Path $ProjectRoot "README.md"
    if (Test-Path $readmePath) {
        Copy-Item -Path $readmePath -Destination $InstallDir -Force
    }

    Write-Success "Project files copied to $InstallDir"
}

# Function to configure project
function Set-ProjectConfiguration {
    Write-Step "Configuring project..."

    Set-Location $InstallDir

    # Create .env file
    $envPath = ".env"
    if (-not (Test-Path $envPath)) {
        Write-Log "Creating .env file..."

        $sessionSecret = -join ((1..32) | ForEach-Object { [char]((65..90) + (97..122) | Get-Random) })

        $envContent = @"
# Environment Configuration
ENVIRONMENT=$Environment

# Server Configuration
SERVER_HOST=127.0.0.1
SERVER_PORT=3030
SERVER_PROTOCOL=$( if ($ENABLE_TLS) { "https" } else { "http" } )

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

# Session Configuration
SESSION_SECRET=$sessionSecret

# 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
"@

        Set-Content -Path $envPath -Value $envContent
        Write-Success ".env file created"
    } else {
        Write-Log ".env file already exists, skipping creation" -Level "WARN"
    }

    # Update Cargo.toml with project name
    $cargoPath = "Cargo.toml"
    if (Test-Path $cargoPath) {
        $content = Get-Content $cargoPath
        $content = $content -replace 'name = "rustelo"', "name = `"$ProjectName`""
        Set-Content -Path $cargoPath -Value $content
        Write-Log "Updated project name in Cargo.toml" -Level "DEBUG"
    }

    # Create necessary directories
    $dirs = @("public", "uploads", "logs", "cache", "config", "data", "backups")
    foreach ($dir in $dirs) {
        if (-not (Test-Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force | Out-Null
        }
    }

    if ($ENABLE_TLS) {
        if (-not (Test-Path "certs")) {
            New-Item -ItemType Directory -Path "certs" -Force | Out-Null
        }
        Write-Log "Created certs directory for TLS" -Level "DEBUG"
    }

    Write-Success "Project configured"
}

# Function to install dependencies
function Install-Dependencies {
    Write-Step "Installing project dependencies..."

    Set-Location $InstallDir

    # Install Rust dependencies
    Write-Log "Installing Rust dependencies..."
    try {
        cargo fetch
    } catch {
        Write-Log "Failed to fetch Rust dependencies: $_" -Level "ERROR"
        exit 1
    }

    # Install Node.js dependencies
    if (Test-Path "package.json") {
        Write-Log "Installing Node.js dependencies..."

        try {
            if (Test-Command "pnpm") {
                pnpm install
            } elseif (Test-Command "npm") {
                npm install
            } else {
                Write-Log "Neither pnpm nor npm found" -Level "ERROR"
                exit 1
            }
        } catch {
            Write-Log "Failed to install Node.js dependencies: $_" -Level "ERROR"
            exit 1
        }
    }

    Write-Success "Dependencies installed"
}

# Function to build project
function Build-Project {
    Write-Step "Building project..."

    Set-Location $InstallDir

    # Build CSS
    Write-Log "Building CSS..."
    try {
        if (Test-Command "pnpm") {
            pnpm run build:css
        } elseif (Test-Command "npm") {
            npm run build:css
        }
    } catch {
        Write-Log "Failed to build CSS" -Level "WARN"
    }

    # Build Rust project
    Write-Log "Building Rust project..."
    try {
        cargo build
    } catch {
        Write-Log "Failed to build Rust project: $_" -Level "ERROR"
        exit 1
    }

    Write-Success "Project built successfully"
}

# Function to create startup scripts
function New-StartupScripts {
    Write-Step "Creating startup scripts..."

    Set-Location $InstallDir

    # Create development start script
    $startScript = @"
@echo off
cd /d "%~dp0"
cargo leptos watch
pause
"@

    Set-Content -Path "start.bat" -Value $startScript

    # Create production start script
    $startProdScript = @"
@echo off
cd /d "%~dp0"
cargo leptos build --release
.\target\release\server.exe
pause
"@

    Set-Content -Path "start-prod.bat" -Value $startProdScript

    # Create PowerShell start script
    $startPsScript = @"
# Start development server
Set-Location (Split-Path -Parent `$MyInvocation.MyCommand.Path)
cargo leptos watch
"@

    Set-Content -Path "start.ps1" -Value $startPsScript

    Write-Success "Startup scripts created"
}

# Function to display final instructions
function Show-Instructions {
    Write-Host ""
    Write-Header "╭─────────────────────────────────────────────────────────────╮"
    Write-Header "│                    INSTALLATION COMPLETE                    │"
    Write-Header "╰─────────────────────────────────────────────────────────────╯"
    Write-Host ""

    Write-Success "Project '$ProjectName' has been successfully installed!"
    Write-Host ""
    Write-Host "Project Location: " -NoNewline
    Write-Host $InstallDir -ForegroundColor $Colors.White
    Write-Host "Environment: " -NoNewline
    Write-Host $Environment -ForegroundColor $Colors.White
    Write-Host "Features:"
    Write-Host "  - Authentication: $ENABLE_AUTH"
    Write-Host "  - Content Database: $ENABLE_CONTENT_DB"
    Write-Host "  - TLS/HTTPS: $ENABLE_TLS"
    Write-Host "  - OAuth: $ENABLE_OAUTH"
    Write-Host ""
    Write-Host "Next Steps:" -ForegroundColor $Colors.White
    Write-Host "1. Navigate to your project:"
    Write-Host "   cd $InstallDir"
    Write-Host ""
    Write-Host "2. Review and customize your configuration:"
    Write-Host "   - Edit .env file for environment variables"
    Write-Host "   - Review config.toml for detailed settings"
    Write-Host ""
    Write-Host "3. Start the development server:"
    Write-Host "   .\start.bat (or .\start.ps1)"
    Write-Host "   # or manually: cargo leptos watch"
    Write-Host ""
    Write-Host "4. Open your browser to:"
    if ($ENABLE_TLS) {
        Write-Host "   https://127.0.0.1:3030"
    } else {
        Write-Host "   http://127.0.0.1:3030"
    }
    Write-Host ""
    Write-Host "Available Commands:" -ForegroundColor $Colors.White
    Write-Host "  cargo leptos watch     - Start development server with hot reload"
    Write-Host "  cargo leptos build     - Build for production"
    Write-Host "  cargo build           - Build Rust code only"
    Write-Host "  npm run build:css     - Build CSS only"
    Write-Host "  npm run dev           - Watch CSS changes"
    Write-Host ""

    if ($ENABLE_TLS) {
        Write-Host "Note: " -ForegroundColor $Colors.Yellow -NoNewline
        Write-Host "Self-signed certificates were generated for HTTPS."
        Write-Host "Your browser will show a security warning. This is normal for development."
        Write-Host ""
    }

    if ($Environment -eq "prod") {
        Write-Host "Production Notes:" -ForegroundColor $Colors.Yellow
        Write-Host "- Update SESSION_SECRET in .env with a secure value"
        Write-Host "- Configure your database connection string"
        Write-Host "- Set up proper TLS certificates for production"
        Write-Host "- Review all security settings in config.toml"
        Write-Host ""
    }

    Write-Host "Documentation:" -ForegroundColor $Colors.White
    Write-Host "- README.md - General project information"
    Write-Host "- CONFIG_README.md - Configuration guide"
    Write-Host "- DAISYUI_INTEGRATION.md - UI components guide"
    Write-Host ""
    Write-Host "Support:" -ForegroundColor $Colors.White
    Write-Host "- Check the logs: $InstallLog"
    Write-Host "- Run diagnostics: cargo run --bin config_tool -- validate"
    Write-Host ""
    Write-Success "Happy coding with Rustelo! 🚀"
}

# Function to show usage
function Show-Usage {
    Write-Host "Rustelo Project Installer for Windows"
    Write-Host ""
    Write-Host "Usage: .\install.ps1 [OPTIONS]"
    Write-Host ""
    Write-Host "Options:"
    Write-Host "  -ProjectName <name>     Project name [default: my-rustelo-app]"
    Write-Host "  -Environment <env>      Environment (dev, prod) [default: dev]"
    Write-Host "  -InstallDir <path>      Installation directory [default: .\<project-name>]"
    Write-Host "  -EnableTLS              Enable TLS/HTTPS support"
    Write-Host "  -EnableOAuth            Enable OAuth authentication"
    Write-Host "  -DisableAuth            Disable authentication features"
    Write-Host "  -DisableContentDB       Disable content database features"
    Write-Host "  -SkipDeps               Skip dependency installation"
    Write-Host "  -Force                  Force reinstallation (overwrite existing)"
    Write-Host "  -Quiet                  Suppress debug output"
    Write-Host "  -Help                   Show this help message"
    Write-Host ""
    Write-Host "Examples:"
    Write-Host "  .\install.ps1                                    # Default installation"
    Write-Host "  .\install.ps1 -ProjectName my-blog -EnableTLS   # Blog with HTTPS"
    Write-Host "  .\install.ps1 -Environment prod                 # Production setup"
}

# Main installation function
function Start-Installation {
    Write-Banner

    # Initialize log
    "Installation started at $(Get-Date)" | Out-File -FilePath $InstallLog -Encoding UTF8

    # Check if we're in the right directory
    if (-not (Test-Path $TemplateDir)) {
        Write-Log "Template directory not found: $TemplateDir" -Level "ERROR"
        Write-Log "Please run this script from the Rustelo project root" -Level "ERROR"
        exit 1
    }

    # Run installation steps
    Test-SystemRequirements
    Install-Rust
    Install-NodeJS
    Install-RustTools
    New-Project
    Set-ProjectConfiguration
    Install-Dependencies
    Build-Project
    New-StartupScripts

    # Display final instructions
    Show-Instructions

    Write-Log "Installation completed successfully at $(Get-Date)"
}

# Main execution
if ($Help) {
    Show-Usage
    exit 0
}

# Validate parameters
if ($Environment -notin @("dev", "prod")) {
    Write-Log "Invalid environment: $Environment" -Level "ERROR"
    exit 1
}

# Run main installation
try {
    Start-Installation
} catch {
    Write-Log "Installation failed: $_" -Level "ERROR"
    exit 1
}
