<#
.SYNOPSIS
    Enable HTTPS for ROA2WEB on IIS

.DESCRIPTION
    This script configures HTTPS for ROA2WEB by:
    - Creating a self-signed SSL certificate (or using existing certificate)
    - Configuring HTTPS binding on IIS site
    - Enabling HTTP to HTTPS redirect

.PARAMETER IISSiteName
    IIS Site name (default: Default Web Site)

.PARAMETER CertificateDnsName
    DNS name for certificate (default: server IP or hostname)

.PARAMETER UseExistingCert
    Use existing certificate by thumbprint

.PARAMETER CertThumbprint
    Thumbprint of existing certificate to use

.PARAMETER Port
    HTTPS port (default: 443)

.EXAMPLE
    .\Enable-HTTPS.ps1
    Create self-signed certificate and enable HTTPS

.EXAMPLE
    .\Enable-HTTPS.ps1 -IISSiteName "ROA2WEB" -CertificateDnsName "roa2web.company.com"
    Create certificate with custom DNS name

.EXAMPLE
    .\Enable-HTTPS.ps1 -UseExistingCert -CertThumbprint "ABC123..."
    Use existing certificate

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

[CmdletBinding()]
param(
    [string]$IISSiteName = "Default Web Site",
    [string]$CertificateDnsName = "",
    [switch]$UseExistingCert,
    [string]$CertThumbprint = "",
    [int]$Port = 443,
    [string]$IPAddress = "*"
)

$ErrorActionPreference = "Stop"

# =============================================================================
# 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)
}

# =============================================================================
# MAIN SCRIPT
# =============================================================================

Write-Host @"

====================================================================
 ROA2WEB - Enable HTTPS on IIS
====================================================================

"@ -ForegroundColor Cyan

# Check administrator privileges
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"

# Import required modules
Write-Step "Loading IIS module..."
Import-Module WebAdministration -ErrorAction Stop
Write-Success "IIS module loaded"

# Verify IIS site exists
Write-Step "Verifying IIS site '$IISSiteName'..."
$site = Get-Website -Name $IISSiteName -ErrorAction SilentlyContinue
if (-not $site) {
    Write-Error "IIS site '$IISSiteName' not found"
    Write-Host "`nAvailable sites:" -ForegroundColor Yellow
    Get-Website | Format-Table Name, State, PhysicalPath
    exit 1
}
Write-Success "IIS site found: $IISSiteName (State: $($site.State))"

# Get or create certificate
if ($UseExistingCert) {
    Write-Step "Using existing certificate..."

    if ([string]::IsNullOrEmpty($CertThumbprint)) {
        Write-Host "`nAvailable certificates in LocalMachine\My:" -ForegroundColor Yellow
        Get-ChildItem -Path "cert:\LocalMachine\My" |
            Select-Object Thumbprint, Subject, FriendlyName, NotAfter |
            Format-Table -AutoSize

        $CertThumbprint = Read-Host "Enter certificate thumbprint"
    }

    $cert = Get-ChildItem -Path "cert:\LocalMachine\My\$CertThumbprint" -ErrorAction SilentlyContinue
    if (-not $cert) {
        Write-Error "Certificate with thumbprint '$CertThumbprint' not found"
        exit 1
    }

    Write-Success "Certificate found: $($cert.Subject)"

} else {
    Write-Step "Creating self-signed SSL certificate..."

    # Auto-detect DNS name if not provided
    if ([string]::IsNullOrEmpty($CertificateDnsName)) {
        $serverName = $env:COMPUTERNAME
        $ipAddress = (Get-NetIPAddress -AddressFamily IPv4 |
            Where-Object {$_.IPAddress -notlike "127.*" -and $_.IPAddress -notlike "169.*"} |
            Select-Object -First 1).IPAddress

        Write-Host "    Detected hostname: $serverName" -ForegroundColor Yellow
        Write-Host "    Detected IP: $ipAddress" -ForegroundColor Yellow

        $response = Read-Host "Use hostname for certificate? (Y/n)"
        if ($response -eq "" -or $response -eq "Y" -or $response -eq "y") {
            $CertificateDnsName = $serverName
        } else {
            $CertificateDnsName = $ipAddress
        }
    }

    # Check if certificate already exists
    $existingCert = Get-ChildItem -Path "cert:\LocalMachine\My" |
        Where-Object {$_.DnsNameList -contains $CertificateDnsName} |
        Select-Object -First 1

    if ($existingCert) {
        Write-Warning "Certificate for '$CertificateDnsName' already exists"
        $response = Read-Host "Use existing certificate? (Y/n)"
        if ($response -eq "" -or $response -eq "Y" -or $response -eq "y") {
            $cert = $existingCert
            Write-Success "Using existing certificate"
        } else {
            Write-Warning "Removing existing certificate..."
            Remove-Item -Path "cert:\LocalMachine\My\$($existingCert.Thumbprint)" -Force
        }
    }

    if (-not $cert) {
        # Create new certificate
        $cert = New-SelfSignedCertificate `
            -DnsName $CertificateDnsName `
            -CertStoreLocation "cert:\LocalMachine\My" `
            -NotAfter (Get-Date).AddYears(5) `
            -FriendlyName "ROA2WEB SSL Certificate" `
            -KeyUsage DigitalSignature, KeyEncipherment `
            -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1")

        Write-Success "Certificate created successfully"
        Write-Host "    DNS Name: $CertificateDnsName" -ForegroundColor Yellow
        Write-Host "    Thumbprint: $($cert.Thumbprint)" -ForegroundColor Yellow
        Write-Host "    Valid Until: $($cert.NotAfter)" -ForegroundColor Yellow
    }
}

# Configure HTTPS binding
Write-Step "Configuring HTTPS binding..."

# Check if HTTPS binding already exists
$existingBinding = Get-WebBinding -Name $IISSiteName -Protocol "https" -Port $Port -ErrorAction SilentlyContinue

if ($existingBinding) {
    Write-Warning "HTTPS binding already exists on port $Port"
    $response = Read-Host "Remove and recreate binding? (Y/n)"
    if ($response -eq "" -or $response -eq "Y" -or $response -eq "y") {
        Remove-WebBinding -Name $IISSiteName -Protocol "https" -Port $Port -ErrorAction SilentlyContinue
        Write-Success "Existing binding removed"
    } else {
        Write-Warning "Skipping binding creation"
        $existingBinding = $null
    }
}

if (-not $existingBinding) {
    # Create HTTPS binding
    try {
        New-WebBinding -Name $IISSiteName -Protocol "https" -Port $Port -IPAddress $IPAddress
        Write-Success "HTTPS binding created on port $Port"
    } catch {
        Write-Error "Failed to create HTTPS binding: $_"
        exit 1
    }
}

# Attach certificate to binding
Write-Step "Attaching certificate to HTTPS binding..."

try {
    # Method 1: Using IIS PowerShell Provider (IIS 8+)
    Push-Location
    Set-Location IIS:\SslBindings

    # Remove existing binding if present
    $sslBinding = "${IPAddress}!${Port}"
    if ($IPAddress -eq "*") {
        $sslBinding = "0.0.0.0!${Port}"
    }

    if (Test-Path $sslBinding) {
        Remove-Item $sslBinding -Force -ErrorAction SilentlyContinue
    }

    # Create new SSL binding
    $cert | New-Item $sslBinding
    Pop-Location

    Write-Success "Certificate attached to HTTPS binding"

} catch {
    Write-Warning "Method 1 failed, trying alternative method..."

    try {
        # Method 2: Using netsh (more compatible)
        $certHash = $cert.Thumbprint
        $appId = "{4dc3e181-e14b-4a21-b022-59fc669b0914}"

        # Remove existing binding
        netsh http delete sslcert ipport=0.0.0.0:$Port 2>&1 | Out-Null

        # Add new binding
        $result = netsh http add sslcert ipport=0.0.0.0:$Port certhash=$certHash appid=$appId

        if ($LASTEXITCODE -eq 0) {
            Write-Success "Certificate attached using netsh"
        } else {
            Write-Error "Failed to attach certificate: $result"
            exit 1
        }

    } catch {
        Write-Error "Failed to attach certificate: $_"
        exit 1
    }
}

# Update web.config for HTTP to HTTPS redirect
Write-Step "Checking web.config for HTTPS redirect..."

$webConfigPath = Join-Path $site.PhysicalPath "web.config"

if (Test-Path $webConfigPath) {
    $webConfig = Get-Content $webConfigPath -Raw

    if ($webConfig -match "Force HTTPS") {
        Write-Success "HTTPS redirect rule already exists in web.config"
    } else {
        Write-Warning "HTTPS redirect rule not found in web.config"
        Write-Host "`nTo enable automatic HTTP to HTTPS redirect, add this rule to web.config:" -ForegroundColor Yellow
        Write-Host @"

<rule name="Force HTTPS" stopProcessing="true">
    <match url="(.*)" />
    <conditions>
        <add input="{HTTPS}" pattern="off" />
    </conditions>
    <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>

"@ -ForegroundColor Gray

        $response = Read-Host "`nAdd this rule automatically? (Y/n)"
        if ($response -eq "" -or $response -eq "Y" -or $response -eq "y") {
            # Backup web.config
            $backupPath = "$webConfigPath.backup-$(Get-Date -Format 'yyyyMMdd-HHmmss')"
            Copy-Item -Path $webConfigPath -Destination $backupPath
            Write-Success "web.config backed up to: $backupPath"

            # Add redirect rule
            $redirectRule = @"
                <!-- Rule: Force HTTPS (redirect HTTP to HTTPS) -->
                <rule name="Force HTTPS" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="off" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
                </rule>

"@

            $webConfig = $webConfig -replace '(<rules>)', "`$1`r`n$redirectRule"
            Set-Content -Path $webConfigPath -Value $webConfig
            Write-Success "HTTPS redirect rule added to web.config"
        }
    }
} else {
    Write-Warning "web.config not found at: $webConfigPath"
    Write-Host "    Please ensure web.config exists and contains proper rewrite rules" -ForegroundColor Yellow
}

# Test configuration
Write-Step "Testing configuration..."

# Restart IIS site to apply changes
try {
    Stop-Website -Name $IISSiteName -ErrorAction SilentlyContinue
    Start-Sleep -Seconds 2
    Start-Website -Name $IISSiteName
    Write-Success "IIS site restarted"
} catch {
    Write-Warning "Could not restart IIS site: $_"
}

# Display summary
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
Write-Host "  HTTPS CONFIGURATION COMPLETED" -ForegroundColor Green
Write-Host ("=" * 70) -ForegroundColor Cyan

Write-Host "`nConfiguration Summary:" -ForegroundColor Yellow
Write-Host "  IIS Site:          $IISSiteName"
Write-Host "  HTTPS Port:        $Port"
Write-Host "  Certificate:       $($cert.Subject)"
Write-Host "  Thumbprint:        $($cert.Thumbprint)"
Write-Host "  Valid Until:       $($cert.NotAfter)"

Write-Host "`nAccess Points:" -ForegroundColor Yellow
Write-Host "  HTTPS URL:         https://$CertificateDnsName"
if ($site.Bindings.Collection | Where-Object {$_.protocol -eq "http"}) {
    Write-Host "  HTTP URL:          http://$CertificateDnsName (will redirect to HTTPS)"
}

Write-Host "`nNext Steps:" -ForegroundColor Yellow

if ($cert.Subject -match "CN=[\d\.]+") {
    Write-Host "  1. [RECOMMENDED] Replace self-signed certificate with CA-issued certificate"
    Write-Host "     - Browsers will show security warnings for self-signed certificates"
    Write-Host "     - Use Let's Encrypt, DigiCert, or another CA for production"
}

Write-Host "  2. Test HTTPS access: https://$CertificateDnsName"
Write-Host "  3. Verify HTTP to HTTPS redirect is working"
Write-Host "  4. Check browser console for mixed content warnings"

Write-Host "`nTroubleshooting:" -ForegroundColor Yellow
Write-Host "  View IIS bindings:     Get-WebBinding -Name '$IISSiteName'"
Write-Host "  View certificates:     Get-ChildItem cert:\LocalMachine\My"
Write-Host "  Test HTTPS locally:    Invoke-WebRequest https://localhost:$Port -SkipCertificateCheck"
Write-Host "  IIS Manager:           inetmgr"

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