param(
    [string]$BaseUrl = 'http://localhost:5099',
    [string]$AdminUsername = $env:Admin__Username,
    [string]$AdminPassword = $env:Admin__Password
)

$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.Net.Http

if ([string]::IsNullOrWhiteSpace($AdminUsername) -or [string]::IsNullOrWhiteSpace($AdminPassword)) {
    throw 'Admin__Username and Admin__Password must be provided.'
}

$stamp = Get-Date -Format 'yyyyMMddHHmmss'
$actorUsername = "adminsmoke$stamp"
$targetUsername = "adminpeer$stamp"
$password = 'Demo123!'
$attachmentName = "admin-attachment-$stamp.txt"
$actorPhone = "+7911$stamp"
$targetPhone = "+7922$stamp"

$actorSession = Invoke-RestMethod `
    -Uri "$BaseUrl/api/auth/register" `
    -Method Post `
    -ContentType 'application/json' `
    -Body (@{
        username = $actorUsername
        displayName = 'Admin Smoke Actor'
        password = $password
        phoneNumber = $actorPhone
    } | ConvertTo-Json)

$targetSession = Invoke-RestMethod `
    -Uri "$BaseUrl/api/auth/register" `
    -Method Post `
    -ContentType 'application/json' `
    -Body (@{
        username = $targetUsername
        displayName = 'Admin Smoke Peer'
        password = $password
        phoneNumber = $targetPhone
    } | ConvertTo-Json)

$actorHeaders = @{
    Authorization = "Bearer $($actorSession.accessToken)"
}

$targetUser = Invoke-RestMethod `
    -Uri "$BaseUrl/api/users/search?q=$targetUsername" `
    -Headers $actorHeaders `
    -Method Get | Select-Object -First 1

$chat = Invoke-RestMethod `
    -Uri "$BaseUrl/api/chats/direct" `
    -Headers $actorHeaders `
    -Method Post `
    -ContentType 'application/json' `
    -Body (@{
        userId = $targetUser.id
    } | ConvertTo-Json)

$tempFile = Join-Path $env:TEMP $attachmentName
"admin attachment smoke $stamp" | Set-Content -Path $tempFile -NoNewline

$handler = New-Object System.Net.Http.HttpClientHandler
$client = New-Object System.Net.Http.HttpClient($handler)
$client.BaseAddress = [Uri]::new("$BaseUrl/")
$client.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue('Bearer', $actorSession.accessToken)
$form = New-Object System.Net.Http.MultipartFormDataContent
$form.Add((New-Object System.Net.Http.StringContent('admin smoke attachment')), 'text')
$fileStream = [System.IO.File]::OpenRead($tempFile)
$fileContent = New-Object System.Net.Http.StreamContent($fileStream)
$fileContent.Headers.ContentType = New-Object System.Net.Http.Headers.MediaTypeHeaderValue('text/plain')
$form.Add($fileContent, 'file', [System.IO.Path]::GetFileName($tempFile))
$uploadResponse = $client.PostAsync("api/chats/$($chat.id)/attachments", $form).GetAwaiter().GetResult()
$uploadPayload = $uploadResponse.Content.ReadAsStringAsync().GetAwaiter().GetResult()
$fileStream.Dispose()
$form.Dispose()
$client.Dispose()
$handler.Dispose()

if (-not $uploadResponse.IsSuccessStatusCode) {
    throw $uploadPayload
}

$uploadedMessage = $uploadPayload | ConvertFrom-Json
$attachment = $uploadedMessage.attachments[0]

$adminSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession
Invoke-RestMethod `
    -Uri "$BaseUrl/admin/api/session/login" `
    -WebSession $adminSession `
    -Method Post `
    -ContentType 'application/json' `
    -Body (@{
        username = $AdminUsername
        password = $AdminPassword
    } | ConvertTo-Json) | Out-Null

$status = Invoke-RestMethod `
    -Uri "$BaseUrl/admin/api/status" `
    -WebSession $adminSession `
    -Method Get

$usersBeforeDeleteResponse = Invoke-RestMethod `
    -Uri "$BaseUrl/admin/api/users?q=adminsmoke$stamp" `
    -WebSession $adminSession `
    -Method Get
[object[]]$usersBeforeDelete = if ($null -eq $usersBeforeDeleteResponse) { @() } else { @($usersBeforeDeleteResponse) }

$chatsBeforeDeleteResponse = Invoke-RestMethod `
    -Uri "$BaseUrl/admin/api/chats?q=adminsmoke$stamp" `
    -WebSession $adminSession `
    -Method Get
[object[]]$chatsBeforeDelete = if ($null -eq $chatsBeforeDeleteResponse) { @() } else { @($chatsBeforeDeleteResponse) }

$attachmentsBeforeDeleteResponse = Invoke-RestMethod `
    -Uri "$BaseUrl/admin/api/attachments?q=$attachmentName" `
    -WebSession $adminSession `
    -Method Get
[object[]]$attachmentsBeforeDelete = if ($null -eq $attachmentsBeforeDeleteResponse) { @() } else { @($attachmentsBeforeDeleteResponse) }

$downloadPath = Join-Path $env:TEMP "admin-download-$stamp.txt"
Invoke-WebRequest `
    -Uri "$BaseUrl/admin/api/attachments/$($attachment.id)/content" `
    -WebSession $adminSession `
    -OutFile $downloadPath | Out-Null

Invoke-RestMethod `
    -Uri "$BaseUrl/admin/api/users/$($actorSession.user.id)/block" `
    -WebSession $adminSession `
    -Method Post | Out-Null

$blockedStatusCode = 0
try {
    Invoke-WebRequest `
        -Uri "$BaseUrl/api/auth/login" `
        -Method Post `
        -ContentType 'application/json' `
        -Body (@{
            username = $actorUsername
            password = $password
        } | ConvertTo-Json) | Out-Null
}
catch {
    $blockedStatusCode = [int]$_.Exception.Response.StatusCode
}

Invoke-RestMethod `
    -Uri "$BaseUrl/admin/api/users/$($actorSession.user.id)/unblock" `
    -WebSession $adminSession `
    -Method Post | Out-Null

$actorSessionAfterUnblock = Invoke-RestMethod `
    -Uri "$BaseUrl/api/auth/login" `
    -Method Post `
    -ContentType 'application/json' `
    -Body (@{
        username = $actorUsername
        password = $password
    } | ConvertTo-Json)

$actorHeadersAfterUnblock = @{
    Authorization = "Bearer $($actorSessionAfterUnblock.accessToken)"
}

Invoke-RestMethod `
    -Uri "$BaseUrl/admin/api/chats/$($chat.id)" `
    -WebSession $adminSession `
    -Method Delete | Out-Null

$chatDeleted = $false
try {
    Invoke-RestMethod `
        -Uri "$BaseUrl/api/chats/$($chat.id)" `
        -Headers $actorHeadersAfterUnblock `
        -Method Get | Out-Null
}
catch {
    $chatDeleted = [int]$_.Exception.Response.StatusCode -eq 404
}

Invoke-RestMethod `
    -Uri "$BaseUrl/admin/api/users/$($actorSession.user.id)" `
    -WebSession $adminSession `
    -Method Delete | Out-Null

Invoke-RestMethod `
    -Uri "$BaseUrl/admin/api/users/$($targetSession.user.id)" `
    -WebSession $adminSession `
    -Method Delete | Out-Null

$usersAfterDeleteResponse = Invoke-RestMethod `
    -Uri "$BaseUrl/admin/api/users?q=adminsmoke$stamp" `
    -WebSession $adminSession `
    -Method Get
[object[]]$usersAfterDelete = if ($null -eq $usersAfterDeleteResponse) { @() } else { @($usersAfterDeleteResponse) }

Invoke-RestMethod `
    -Uri "$BaseUrl/admin/api/session/logout" `
    -WebSession $adminSession `
    -Method Post | Out-Null

$logoutBlocked = $false
try {
    Invoke-WebRequest `
        -Uri "$BaseUrl/admin/api/status" `
        -WebSession $adminSession `
        -Method Get | Out-Null
}
catch {
    $logoutBlocked = [int]$_.Exception.Response.StatusCode -eq 401
}

[pscustomobject]@{
    ActorUsername        = $actorUsername
    TargetUsername       = $targetUsername
    TotalUsers           = $status.totalUsers
    DatabaseReachable    = $status.databaseReachable
    UsersBeforeCount     = $usersBeforeDelete.Count
    ChatsBeforeCount     = $chatsBeforeDelete.Count
    AttachmentsBeforeCount = $attachmentsBeforeDelete.Count
    UsersListed          = $usersBeforeDelete.Count -ge 1
    ChatsListed          = $chatsBeforeDelete.Count -ge 1
    AttachmentsListed    = $attachmentsBeforeDelete.Count -ge 1
    AttachmentDownloaded = (Get-Item $downloadPath).Length -gt 0
    BlockedLoginStatus   = $blockedStatusCode
    ChatDeleted          = $chatDeleted
    UsersDeleted         = $usersAfterDelete.Count -eq 0
    AdminLogoutBlocked   = $logoutBlocked
}
