[CmdletBinding()]
param(
    [string]$BaseUrl = 'http://127.0.0.1/CCW',
    [string]$Username = 'admin',
    [string]$Password = 'admin123',
    [switch]$SkipPhpLint,
    [switch]$KeepTestData,
    [switch]$CheckDuplicateSubmit = $true
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

$repoRoot = Split-Path -Path $PSScriptRoot -Parent
$smokeSuitePath = Join-Path $PSScriptRoot 'smoke_system_suite.ps1'
$activePhpRoots = @('config', 'includes', 'pages', 'process')
$summary = New-Object System.Collections.Generic.List[object]

function Invoke-LoggedStep {
    param(
        [string]$Name,
        [scriptblock]$Action
    )

    Write-Output ("== {0} : start ==" -f $Name)
    $startedAt = Get-Date

    try {
        & $Action

        $duration = [math]::Round(((Get-Date) - $startedAt).TotalSeconds, 2)
        $summary.Add([pscustomobject]@{
            Step = $Name
            Status = 'passed'
            DurationSeconds = $duration
        }) | Out-Null
        Write-Output ("== {0} : passed ({1}s) ==" -f $Name, $duration)
    } catch {
        $duration = [math]::Round(((Get-Date) - $startedAt).TotalSeconds, 2)
        $summary.Add([pscustomobject]@{
            Step = $Name
            Status = 'failed'
            DurationSeconds = $duration
            Message = $_.Exception.Message
        }) | Out-Null
        Write-Output ("== {0} : failed ({1}s) ==" -f $Name, $duration)
        throw
    }
}

function Get-ActivePhpFiles {
    $files = New-Object System.Collections.Generic.List[string]

    foreach ($relativeRoot in $activePhpRoots) {
        $fullRoot = Join-Path $repoRoot $relativeRoot
        if (-not (Test-Path -LiteralPath $fullRoot)) {
            continue
        }

        $rootFiles = Get-ChildItem -Path $fullRoot -Recurse -File -Filter *.php |
            Sort-Object FullName |
            Select-Object -ExpandProperty FullName
        foreach ($file in $rootFiles) {
            $files.Add($file) | Out-Null
        }
    }

    $indexPath = Join-Path $repoRoot 'index.php'
    if (Test-Path -LiteralPath $indexPath) {
        $files.Add($indexPath) | Out-Null
    }

    return $files.ToArray()
}

Invoke-LoggedStep -Name 'php-lint' -Action {
    if ($SkipPhpLint) {
        Write-Output 'Skipping PHP lint by request.'
        return
    }

    $phpFiles = Get-ActivePhpFiles
    if ($phpFiles.Count -eq 0) {
        throw 'No active PHP files were found for linting.'
    }

    $lintedCount = 0
    foreach ($file in $phpFiles) {
        $output = & php -l $file 2>&1
        if ($LASTEXITCODE -ne 0) {
            foreach ($line in $output) {
                Write-Output ("[php-lint] {0}" -f [string]$line)
            }
            throw "PHP lint failed: $file"
        }

        $lintedCount++
    }

    Write-Output ("[php-lint] Linted {0} file(s)." -f $lintedCount)
}

Invoke-LoggedStep -Name 'smoke-system-suite' -Action {
    if (-not (Test-Path -LiteralPath $smokeSuitePath)) {
        throw "Smoke suite not found: $smokeSuitePath"
    }

    $invokeParams = @{
        BaseUrl = $BaseUrl
        Username = $Username
        Password = $Password
        CheckDuplicateSubmit = $CheckDuplicateSubmit
    }

    if ($KeepTestData) {
        $invokeParams['KeepTestData'] = $true
    }

    $output = & $smokeSuitePath @invokeParams 2>&1
    foreach ($line in $output) {
        Write-Output ("[smoke-system-suite] {0}" -f [string]$line)
    }
}

Write-Output '== pre-release-gate : summary =='
foreach ($item in $summary) {
    if ($item.PSObject.Properties.Name -contains 'Message') {
        Write-Output ("{0}: {1} ({2}s) - {3}" -f $item.Step, $item.Status, $item.DurationSeconds, $item.Message)
        continue
    }

    Write-Output ("{0}: {1} ({2}s)" -f $item.Step, $item.Status, $item.DurationSeconds)
}
