<#
.SYNOPSIS
    ROA2WEB - Initial Installation Script for Windows Server + IIS

.DESCRIPTION
    This script performs complete installation of ROA2WEB on Windows Server:
    - Checks prerequisites (Admin rights, IIS)
    - Installs Python 3.11+ if needed
    - Installs NSSM (service manager)
    - Installs IIS URL Rewrite and ARR modules
    - Creates directory structure
    - Installs Python dependencies
    - Creates Windows Service for backend
    - Configures IIS website
    - Starts all services

.PARAMETER InstallPath
    Installation path (default: C:\inetpub\wwwroot\roa2web)

.PARAMETER PythonVersion
    Python version to install (default: 3.11.9)

.PARAMETER ServicePort
    Backend service port (default: 8000)

.PARAMETER SkipPython
    Skip Python installation (use existing Python)

.PARAMETER SkipIIS
    Skip IIS configuration

.EXAMPLE
    .\Install-ROA2WEB.ps1
    Standard installation with defaults

.EXAMPLE
    .\Install-ROA2WEB.ps1 -InstallPath "D:\Apps\roa2web" -ServicePort 8001
    Custom installation path and port

.NOTES
    Author: ROA2WEB Team
    Requires: PowerShell 5.1+, Administrator privileges
#>

[CmdletBinding()]
param(
    [string]$InstallPath = "C:\inetpub\wwwroot\roa2web",
    [string]$PythonVersion = "3.11.9",
    [int]$ServicePort = 8000,
    [string]$IISSiteName = "Default Web Site",
    [string]$IISAppName = "roa2web",
    [switch]$CreateNewSite,
    [switch]$SkipPython,
    [switch]$SkipIIS
)

# Strict error handling
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"

# =============================================================================
# CONFIGURATION
# =============================================================================

$script:Config = @{
    AppName = "ROA2WEB"
    ServiceName = "ROA2WEB-Backend"
    ServiceDisplayName = "ROA2WEB Unified Backend Service"
    ServiceDescription = "Unified FastAPI backend for ROA2WEB ERP - includes Reports, Data Entry, and Telegram modules (Ultrathin Monolith)"
    InstallPath = $InstallPath
    BackendPath = Join-Path $InstallPath "backend"
    FrontendPath = Join-Path $InstallPath "frontend"
    LogsPath = Join-Path $InstallPath "logs"
    TempPath = Join-Path $InstallPath "temp"
    # IMPORTANT: venv is OUTSIDE InstallPath to survive deployments!
    VenvPath = "C:\inetpub\wwwroot\roa2web-venv"
    PythonVersion = $PythonVersion
    ServicePort = $ServicePort
    IISSiteName = $IISSiteName
    IISAppName = $IISAppName
    IISAppPoolName = "ROA2WEB-AppPool"
    CreateNewSite = $CreateNewSite
}

# =============================================================================
# HELPER FUNCTIONS
# =============================================================================

function Write-Step {
    param([string]$Message)
    Write-Host "`n[*] $Message" -ForegroundColor Cyan
}

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

function Write-Error {
    param([string]$Message)
    Write-Host "    [ERROR] $Message" -ForegroundColor Red
}

function Write-Warning {
    param([string]$Message)
    Write-Host "    [WARN] $Message" -ForegroundColor Yellow
}

function Test-Administrator {
    $identity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = [Security.Principal.WindowsPrincipal]$identity
    return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

function Test-CommandExists {
    param([string]$Command)
    try {
        if (Get-Command $Command -ErrorAction Stop) {
            return $true
        }
    } catch {
        return $false
    }
}

function Install-Chocolatey {
    Write-Step "Installing Chocolatey package manager..."

    if (Test-CommandExists "choco") {
        Write-Success "Chocolatey already installed"
        return
    }

    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
        Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

        # Refresh environment
        $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")

        Write-Success "Chocolatey installed successfully"
    } catch {
        throw "Failed to install Chocolatey: $_"
    }
}

function Install-Python {
    Write-Step "Checking Python installation..."

    if ($SkipPython) {
        Write-Warning "Skipping Python installation (as requested)"
        return
    }

    # Check if Python is already installed
    try {
        $pythonCmd = Get-Command python -ErrorAction Stop
        $pythonVersionOutput = & python --version 2>&1
        if ($pythonVersionOutput -match "Python (\d+\.\d+\.\d+)") {
            $installedVersion = $matches[1]
            Write-Success "Python $installedVersion already installed at $($pythonCmd.Source)"
            return
        }
    } catch {
        Write-Warning "Python not found, will install..."
    }

    # Install Python via Chocolatey
    Write-Step "Installing Python $PythonVersion..."
    try {
        choco install python --version=$PythonVersion -y --force

        # Refresh environment
        $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")

        Write-Success "Python $PythonVersion installed successfully"
    } catch {
        throw "Failed to install Python: $_"
    }
}

function Install-NSSM {
    Write-Step "Installing NSSM (service manager)..."

    if (Test-Path "C:\nssm\nssm.exe") {
        Write-Success "NSSM already installed"
        return
    }

    try {
        choco install nssm -y
        Write-Success "NSSM installed successfully"
    } catch {
        throw "Failed to install NSSM: $_"
    }
}

function Install-IISModules {
    if ($SkipIIS) {
        Write-Warning "Skipping IIS configuration (as requested)"
        return
    }

    Write-Step "Checking IIS installation..."

    # Detect OS type (Server vs Desktop)
    $osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
    $isServer = $osInfo.ProductType -eq 3  # 1=Workstation, 2=Domain Controller, 3=Server

    # Check if IIS is installed (different cmdlets for Server vs Desktop)
    $iisInstalled = $false

    if ($isServer) {
        # Windows Server - use Get-WindowsFeature
        $iisFeature = Get-WindowsFeature -Name Web-Server -ErrorAction SilentlyContinue
        $iisInstalled = $iisFeature -and $iisFeature.InstallState -eq "Installed"

        if (-not $iisInstalled) {
            Write-Error "IIS is not installed. Please install IIS first:"
            Write-Host "    Install-WindowsFeature -Name Web-Server -IncludeManagementTools" -ForegroundColor Yellow
            throw "IIS not installed"
        }
    } else {
        # Windows Desktop (10/11) - use Get-WindowsOptionalFeature
        $iisFeature = Get-WindowsOptionalFeature -Online -FeatureName IIS-WebServer -ErrorAction SilentlyContinue
        $iisInstalled = $iisFeature -and $iisFeature.State -eq "Enabled"

        if (-not $iisInstalled) {
            Write-Error "IIS is not installed. Please install IIS first:"
            Write-Host "    Enable-WindowsOptionalFeature -Online -FeatureName IIS-WebServer -All" -ForegroundColor Yellow
            Write-Host "    Or use: Control Panel -> Programs -> Turn Windows features on/off -> Internet Information Services" -ForegroundColor Yellow
            throw "IIS not installed"
        }
    }

    Write-Success "IIS is installed ($($osInfo.Caption))"

    # Install URL Rewrite Module
    Write-Step "Installing IIS URL Rewrite Module..."
    $urlRewriteInstalled = Get-WebConfiguration -Filter "/system.webServer/rewrite" -PSPath "IIS:\" -ErrorAction SilentlyContinue

    if (-not $urlRewriteInstalled) {
        Write-Warning "URL Rewrite not found, installing..."
        try {
            $urlRewriteUrl = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_en-US.msi"
            $urlRewritePath = "$env:TEMP\rewrite_amd64.msi"

            Invoke-WebRequest -Uri $urlRewriteUrl -OutFile $urlRewritePath
            Start-Process msiexec.exe -ArgumentList "/i", $urlRewritePath, "/quiet", "/norestart" -Wait
            Remove-Item $urlRewritePath -Force

            Write-Success "URL Rewrite Module installed"
        } catch {
            Write-Error "Failed to install URL Rewrite: $_"
            Write-Warning "You can download it manually from: https://www.iis.net/downloads/microsoft/url-rewrite"
        }
    } else {
        Write-Success "URL Rewrite Module already installed"
    }

    # Install Application Request Routing (ARR)
    Write-Step "Checking Application Request Routing (ARR)..."
    try {
        choco install iis-arr -y
        Write-Success "ARR installed successfully"
    } catch {
        Write-Warning "Could not install ARR via Chocolatey. Download manually from: https://www.iis.net/downloads/microsoft/application-request-routing"
    }
}

function New-DirectoryStructure {
    Write-Step "Creating directory structure..."

    $directories = @(
        $Config.InstallPath,
        $Config.BackendPath,
        $Config.FrontendPath,
        $Config.LogsPath,
        $Config.TempPath,
        (Join-Path $Config.BackendPath "logs"),
        (Join-Path $Config.BackendPath "temp")
    )

    foreach ($dir in $directories) {
        if (-not (Test-Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force | Out-Null
            Write-Success "Created: $dir"
        } else {
            Write-Success "Already exists: $dir"
        }
    }

    # Set permissions (IIS user needs read access)
    try {
        $acl = Get-Acl $Config.InstallPath
        $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule("IIS_IUSRS", "ReadAndExecute", "ContainerInherit,ObjectInherit", "None", "Allow")
        $acl.SetAccessRule($accessRule)
        Set-Acl -Path $Config.InstallPath -AclObject $acl
        Write-Success "Permissions set for IIS_IUSRS"
    } catch {
        Write-Warning "Could not set permissions: $_"
    }
}

function Install-PythonDependencies {
    Write-Step "Setting up Python virtual environment..."

    $requirementsPath = Join-Path $Config.BackendPath "requirements.txt"
    $venvPath = $Config.VenvPath
    $venvPython = Join-Path $venvPath "Scripts\python.exe"
    $venvPip = Join-Path $venvPath "Scripts\pip.exe"

    # Create venv if it doesn't exist
    if (-not (Test-Path $venvPython)) {
        Write-Step "Creating virtual environment at $venvPath..."
        try {
            & python -m venv $venvPath
            Write-Success "Virtual environment created"
        } catch {
            throw "Failed to create virtual environment: $_"
        }
    } else {
        Write-Success "Virtual environment already exists"
    }

    # Upgrade pip in venv
    Write-Step "Upgrading pip in virtual environment..."
    try {
        & $venvPython -m pip install --upgrade pip
        Write-Success "Pip upgraded"
    } catch {
        Write-Warning "Could not upgrade pip: $_"
    }

    # Install dependencies
    if (-not (Test-Path $requirementsPath)) {
        Write-Warning "requirements.txt not found at $requirementsPath"
        Write-Warning "Please copy backend files first, then run this script again"
        return
    }

    Write-Step "Installing Python dependencies in virtual environment..."
    try {
        & $venvPip install -r $requirementsPath
        Write-Success "Python dependencies installed successfully in venv"
    } catch {
        throw "Failed to install Python dependencies: $_"
    }
}

function New-WindowsService {
    Write-Step "Creating Windows Service for backend..."

    # Check if service already exists using nssm (more reliable than Get-Service)
    # Temporarily disable error action to check service status
    $oldErrorAction = $ErrorActionPreference
    $ErrorActionPreference = "SilentlyContinue"

    $nssmOutput = & nssm status $Config.ServiceName 2>&1
    $serviceExists = $LASTEXITCODE -eq 0

    $ErrorActionPreference = $oldErrorAction

    if ($serviceExists) {
        Write-Warning "Service already exists, stopping and removing..."

        # Check service status
        $status = & nssm status $Config.ServiceName 2>&1

        # Only try to stop if service is running
        if ($status -match "SERVICE_RUNNING") {
            Write-Step "Stopping running service..."
            & nssm stop $Config.ServiceName 2>&1 | Out-Null
            Start-Sleep -Seconds 2
        } else {
            Write-Step "Service is not running (status: $status)"
        }

        # Force remove service
        & nssm remove $Config.ServiceName confirm 2>&1 | Out-Null
        Start-Sleep -Seconds 2
        Write-Success "Existing service removed"
    }

    # Get Python path from venv
    $venvPython = Join-Path $Config.VenvPath "Scripts\python.exe"

    if (-not (Test-Path $venvPython)) {
        throw "Virtual environment Python not found at $venvPython. Run Install-PythonDependencies first."
    }

    $uvicornModule = "uvicorn"
    $appModule = "main:app"

    # NSSM service creation
    try {
        # Install service using venv Python
        # NOTE: Using --workers 1 because Telegram bot requires single instance (polling conflict)
        & nssm install $Config.ServiceName $venvPython "-m" $uvicornModule $appModule "--host" "127.0.0.1" "--port" $Config.ServicePort.ToString() "--workers" "1"

        # Set service configuration
        & nssm set $Config.ServiceName DisplayName $Config.ServiceDisplayName
        & nssm set $Config.ServiceName Description $Config.ServiceDescription
        & nssm set $Config.ServiceName Start SERVICE_AUTO_START
        & nssm set $Config.ServiceName AppDirectory $Config.BackendPath

        # Set environment variables (PYTHONPATH for shared modules)
        # Point to the installation root AND backend/ so both shared/ and app/ modules can be imported
        $pythonPathRoot = $Config.InstallPath
        $pythonPathBackend = $Config.BackendPath
        & nssm set $Config.ServiceName AppEnvironmentExtra "PYTHONPATH=$pythonPathRoot;$pythonPathBackend"

        # Set logging
        $stdoutLog = Join-Path $Config.LogsPath "backend-stdout.log"
        $stderrLog = Join-Path $Config.LogsPath "backend-stderr.log"
        & nssm set $Config.ServiceName AppStdout $stdoutLog
        & nssm set $Config.ServiceName AppStderr $stderrLog
        & nssm set $Config.ServiceName AppStdoutCreationDisposition 4
        & nssm set $Config.ServiceName AppStderrCreationDisposition 4

        # Set restart policy
        & nssm set $Config.ServiceName AppExit Default Restart
        & nssm set $Config.ServiceName AppRestartDelay 5000

        Write-Success "Windows Service created successfully"
    } catch {
        throw "Failed to create Windows Service: $_"
    }
}

function Initialize-IISWebsite {
    if ($SkipIIS) {
        Write-Warning "Skipping IIS website configuration (as requested)"
        return
    }

    Write-Step "Configuring IIS application..."

    Import-Module WebAdministration -ErrorAction Stop

    # Remove existing app pool if present
    if (Test-Path "IIS:\AppPools\$($Config.IISAppPoolName)") {
        Write-Warning "Removing existing app pool..."
        Remove-WebAppPool -Name $Config.IISAppPoolName -ErrorAction SilentlyContinue
    }

    # Create Application Pool
    Write-Step "Creating IIS Application Pool..."
    New-WebAppPool -Name $Config.IISAppPoolName -Force | Out-Null
    Set-ItemProperty -Path "IIS:\AppPools\$($Config.IISAppPoolName)" -Name "managedRuntimeVersion" -Value ""
    Write-Success "Application Pool created: $($Config.IISAppPoolName)"

    if ($CreateNewSite) {
        # Create new website (old behavior)
        Write-Step "Creating new IIS Website..."

        # Stop default website if running
        try {
            Stop-Website -Name "Default Web Site" -ErrorAction SilentlyContinue
            Write-Success "Stopped Default Web Site"
        } catch {
            Write-Warning "Could not stop Default Web Site: $_"
        }

        # Remove existing site if present
        if (Get-Website -Name $Config.IISSiteName -ErrorAction SilentlyContinue) {
            Write-Warning "Removing existing website..."
            Remove-Website -Name $Config.IISSiteName -ErrorAction SilentlyContinue
        }

        New-Website -Name $Config.IISSiteName `
            -PhysicalPath $Config.FrontendPath `
            -ApplicationPool $Config.IISAppPoolName `
            -Port 80 `
            -Force | Out-Null

        Write-Success "Website created: $($Config.IISSiteName)"

        # Start website
        Start-Website -Name $Config.IISSiteName
        Write-Success "Website started: $($Config.IISSiteName)"
    } else {
        # Create application under existing site (default behavior)
        Write-Step "Creating IIS Application under '$($Config.IISSiteName)'..."

        # Verify parent site exists
        $parentSite = Get-Website -Name $Config.IISSiteName -ErrorAction SilentlyContinue
        if (-not $parentSite) {
            throw "Parent website '$($Config.IISSiteName)' does not exist. Use -CreateNewSite to create a new site."
        }

        # Remove existing application if present
        $existingApp = Get-WebApplication -Name $Config.IISAppName -Site $Config.IISSiteName -ErrorAction SilentlyContinue
        if ($existingApp) {
            Write-Warning "Removing existing application..."
            Remove-WebApplication -Name $Config.IISAppName -Site $Config.IISSiteName -ErrorAction SilentlyContinue
        }

        # Create application
        New-WebApplication -Name $Config.IISAppName `
            -Site $Config.IISSiteName `
            -PhysicalPath $Config.FrontendPath `
            -ApplicationPool $Config.IISAppPoolName `
            -Force | Out-Null

        Write-Success "Application created: /$($Config.IISAppName) under $($Config.IISSiteName)"
    }

    # Copy web.config to frontend path
    $webConfigSource = Join-Path $PSScriptRoot "..\config\web.config"
    $webConfigDest = Join-Path $Config.FrontendPath "web.config"

    if (Test-Path $webConfigSource) {
        Copy-Item -Path $webConfigSource -Destination $webConfigDest -Force
        Write-Success "web.config copied to frontend path"
    } else {
        Write-Warning "web.config not found at $webConfigSource"
    }
}

function Start-Services {
    Write-Step "Starting services..."

    # Start backend service
    try {
        Start-Service -Name $Config.ServiceName
        Start-Sleep -Seconds 3

        $service = Get-Service -Name $Config.ServiceName
        if ($service.Status -eq "Running") {
            Write-Success "Backend service started successfully"
        } else {
            Write-Error "Backend service failed to start (Status: $($service.Status))"
        }
    } catch {
        Write-Error "Failed to start backend service: $_"
    }

    # Test backend health
    Write-Step "Testing backend health..."
    Start-Sleep -Seconds 5

    try {
        $response = Invoke-WebRequest -Uri "http://localhost:$($Config.ServicePort)/health" -UseBasicParsing -TimeoutSec 10
        if ($response.StatusCode -eq 200) {
            Write-Success "Backend health check passed"
        }
    } catch {
        Write-Warning "Backend health check failed (may need time to start): $_"
    }
}

function Show-Summary {
    Write-Host "`n" + ("=" * 80) -ForegroundColor Cyan
    Write-Host "  ROA2WEB INSTALLATION COMPLETED" -ForegroundColor Green
    Write-Host ("=" * 80) -ForegroundColor Cyan

    Write-Host "`nInstallation Details:" -ForegroundColor Yellow
    Write-Host "  Install Path:      $($Config.InstallPath)"
    Write-Host "  Backend Path:      $($Config.BackendPath)"
    Write-Host "  Virtual Env:       $($Config.VenvPath)"
    Write-Host "  Frontend Path:     $($Config.FrontendPath)"
    Write-Host "  Service Name:      $($Config.ServiceName)"
    Write-Host "  Service Port:      $($Config.ServicePort)"
    Write-Host "  IIS Site:          $($Config.IISSiteName)"

    Write-Host "`nAccess Points:" -ForegroundColor Yellow
    if ($Config.CreateNewSite) {
        Write-Host "  Web Application:   http://localhost"
    } else {
        Write-Host "  Web Application:   http://localhost/$($Config.IISAppName)"
    }
    Write-Host "  API Backend:       http://localhost:$($Config.ServicePort)"
    Write-Host "  API Docs:          http://localhost:$($Config.ServicePort)/docs"
    Write-Host "  Health Check:      http://localhost:$($Config.ServicePort)/health"

    Write-Host "`nNext Steps:" -ForegroundColor Yellow
    Write-Host "  1. Copy backend files to: $($Config.BackendPath)"
    Write-Host "  2. Copy frontend files to: $($Config.FrontendPath)"
    Write-Host "  3. Configure .env file at: $($Config.BackendPath)\.env"
    Write-Host ""
    Write-Host "  IMPORTANT - Module Control Flags in .env:" -ForegroundColor Cyan
    Write-Host "    MODULE_REPORTS_ENABLED=true       # Enable/disable Reports module"
    Write-Host "    MODULE_DATA_ENTRY_ENABLED=true    # Enable/disable Data Entry module"
    Write-Host "    MODULE_TELEGRAM_ENABLED=true      # Enable/disable Telegram bot module"
    Write-Host ""
    Write-Host "  4. Start service: Start-Service $($Config.ServiceName)"

    Write-Host "`nManagement Commands:" -ForegroundColor Yellow
    Write-Host "  Start Service:     Start-Service $($Config.ServiceName)"
    Write-Host "  Stop Service:      Stop-Service $($Config.ServiceName)"
    Write-Host "  Restart Service:   Restart-Service $($Config.ServiceName)"
    Write-Host "  View Logs:         Get-Content $($Config.LogsPath)\backend-stdout.log -Tail 50"
    Write-Host "  Check Status:      Get-Service $($Config.ServiceName)"

    Write-Host "`nArchitecture:" -ForegroundColor Yellow
    Write-Host "  ULTRATHIN MONOLITH - Single Windows service with multiple modules"
    Write-Host "  All modules share Oracle pool, auth, and cache"
    Write-Host "  Telegram bot runs as background task (not separate service)"

    Write-Host "`n" + ("=" * 80) -ForegroundColor Cyan
}

# =============================================================================
# MAIN INSTALLATION FLOW
# =============================================================================

function Main {
    Write-Host @"

    ====================================================================
     ROA2WEB - Windows Server Installation Script
     Modern ERP Reports Application with FastAPI + Vue.js + IIS
    ====================================================================

"@ -ForegroundColor Cyan

    # Check prerequisites
    Write-Step "Checking prerequisites..."

    if (-not (Test-Administrator)) {
        Write-Error "This script must be run as Administrator"
        Write-Host "    Right-click PowerShell and select 'Run as Administrator'" -ForegroundColor Yellow
        exit 1
    }
    Write-Success "Running as Administrator"

    try {
        # Installation steps
        Install-Chocolatey
        Install-Python
        Install-NSSM
        Install-IISModules
        New-DirectoryStructure
        Install-PythonDependencies
        New-WindowsService
        Initialize-IISWebsite
        Start-Services
        Show-Summary

        Write-Host "`nInstallation completed successfully!" -ForegroundColor Green

    } catch {
        Write-Host "`n[FATAL ERROR] Installation failed: $_" -ForegroundColor Red
        Write-Host $_.ScriptStackTrace -ForegroundColor Red
        exit 1
    }
}

# Run main installation
Main
