[CmdletBinding()]
param(
    [string]$SiteName = "Default Web Site",
    [string]$AppName = "ehfleet_webservice",
    [string]$AppPoolName = "ehfleet_webservice",
    [int]$Port = 8080,
    [string]$HostName = "",
    [string]$PhysicalPath = "C:\inetpub\wwwroot\ehfleet_webservice",
    [Parameter(Mandatory = $true)]
    [string]$PackagePath,
    [Parameter(Mandatory = $true)]
    [string]$SqlServer,
    [Parameter(Mandatory = $true)]
    [string]$Database,
    [string]$SqlUser,
    [string]$SqlPassword,
    [switch]$UseWindowsAuth
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

function Assert-Administrator {
    $identity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object Security.Principal.WindowsPrincipal($identity)
    if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        throw "Run this script from an elevated PowerShell session."
    }
}

function Enable-WindowsFeatureIfMissing {
    param([string[]]$Names)

    foreach ($name in $Names) {
        $feature = Get-WindowsOptionalFeature -Online -FeatureName $name -ErrorAction SilentlyContinue
        if ($feature -and $feature.State -ne "Enabled") {
            Enable-WindowsOptionalFeature -Online -FeatureName $name -All -NoRestart | Out-Null
        }
    }
}

function Get-MSDeployPath {
    $candidates = @(
        "$env:ProgramFiles\IIS\Microsoft Web Deploy V3\msdeploy.exe",
        "${env:ProgramFiles(x86)}\IIS\Microsoft Web Deploy V3\msdeploy.exe"
    )

    return $candidates | Where-Object { Test-Path $_ } | Select-Object -First 1
}

function Install-MSDeployIfMissing {
    $msdeploy = Get-MSDeployPath
    if ($msdeploy) {
        return $msdeploy
    }

    $winget = Get-Command winget.exe -ErrorAction SilentlyContinue
    if ($winget) {
        winget install --id Microsoft.WebDeploy --source winget --accept-package-agreements --accept-source-agreements
        $msdeploy = Get-MSDeployPath
        if ($msdeploy) {
            return $msdeploy
        }
    }

    throw "Microsoft Web Deploy was not found and could not be installed automatically. Install Web Deploy 3.6, then rerun this script."
}

function New-EHFleetConnectionString {
    if ($UseWindowsAuth) {
        return "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=$Database;Data Source=$SqlServer"
    }

    if ([string]::IsNullOrWhiteSpace($SqlUser) -or [string]::IsNullOrWhiteSpace($SqlPassword)) {
        throw "SqlUser and SqlPassword are required unless -UseWindowsAuth is specified."
    }

    return "Provider=SQLOLEDB.1;Persist Security Info=False;User ID=$SqlUser;Password=$SqlPassword;Initial Catalog=$Database;Data Source=$SqlServer"
}

function Ensure-IISApplication {
    Import-Module WebAdministration

    if (-not (Test-Path $PhysicalPath)) {
        New-Item -ItemType Directory -Force -Path $PhysicalPath | Out-Null
    }

    if (-not (Test-Path "IIS:\AppPools\$AppPoolName")) {
        New-WebAppPool -Name $AppPoolName | Out-Null
    }

    Set-ItemProperty "IIS:\AppPools\$AppPoolName" -Name managedRuntimeVersion -Value "v4.0"
    Set-ItemProperty "IIS:\AppPools\$AppPoolName" -Name managedPipelineMode -Value "Integrated"

    if (-not (Test-Path "IIS:\Sites\$SiteName")) {
        New-Website -Name $SiteName -Port $Port -HostHeader $HostName -PhysicalPath "C:\inetpub\wwwroot" -ApplicationPool $AppPoolName | Out-Null
    }

    $binding = Get-WebBinding -Name $SiteName -Protocol "http" | Where-Object {
        $_.bindingInformation -eq "*:${Port}:${HostName}"
    }
    if (-not $binding) {
        New-WebBinding -Name $SiteName -Protocol "http" -Port $Port -HostHeader $HostName | Out-Null
    }

    $appPath = "IIS:\Sites\$SiteName\$AppName"
    if (-not (Test-Path $appPath)) {
        New-WebApplication -Site $SiteName -Name $AppName -PhysicalPath $PhysicalPath -ApplicationPool $AppPoolName | Out-Null
    }
    else {
        Set-ItemProperty $appPath -Name physicalPath -Value $PhysicalPath
        Set-ItemProperty $appPath -Name applicationPool -Value $AppPoolName
    }

    $identity = "IIS AppPool\$AppPoolName"
    & icacls $PhysicalPath /grant "${identity}:(OI)(CI)(RX,M)" /T | Out-Null
}

function Invoke-MSDeployPackage {
    param(
        [string]$MSDeployExe,
        [string]$ConnectionString
    )

    if (-not (Test-Path $PackagePath)) {
        throw "PackagePath not found: $PackagePath"
    }

    $iisAppPath = "$SiteName/$AppName"
    & $MSDeployExe `
        "-verb:sync" `
        "-source:package='$PackagePath'" `
        "-dest:auto" `
        "-setParam:name='IIS Web Application Name',value='$iisAppPath'" `
        "-setParam:name='EHFleetConnectionString-Web.config Connection String',value='$ConnectionString'"
}

function Test-Webservice {
    $hostPart = if ([string]::IsNullOrWhiteSpace($HostName)) { "localhost" } else { $HostName }
    $url = "http://${hostPart}:$Port/$AppName/WorkshopItems.asmx"
    $response = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 30
    if ($response.StatusCode -lt 200 -or $response.StatusCode -ge 400) {
        throw "Smoke test failed for $url with HTTP $($response.StatusCode)."
    }

    Write-Host "Smoke test successful: $url"
}

Assert-Administrator

Enable-WindowsFeatureIfMissing -Names @(
    "IIS-WebServerRole",
    "IIS-WebServer",
    "IIS-CommonHttpFeatures",
    "IIS-DefaultDocument",
    "IIS-DirectoryBrowsing",
    "IIS-StaticContent",
    "IIS-ASPNET45",
    "IIS-NetFxExtensibility45",
    "IIS-ISAPIExtensions",
    "IIS-ISAPIFilter",
    "IIS-ManagementConsole",
    "IIS-ManagementService"
)

$msdeploy = Install-MSDeployIfMissing
$connectionString = New-EHFleetConnectionString
Ensure-IISApplication
Invoke-MSDeployPackage -MSDeployExe $msdeploy -ConnectionString $connectionString
Test-Webservice

Write-Host "EHFleet webservice installation completed."
