# 1. .\ParsecLogin.ps1 se spustí se startem VM, jakmile se spustí, čeká na vstup přes Pipe
# 2. Jakmile jej dostane, zkusí se s ním přihlásit
# 3. Když je přihlášení úspěšné, zapíše do souboru "200" (HTML OK)
# 4. Když je přihlášení neúspěšné, zapíše do souboru "400", "401" nebo "403" v závislosti na případu
# 5.   Počká daný čas, pokusí se získat znovu email a heslo k přihlášení a následně znovu provádí pokus o přihlášení

param(
    [Parameter(Mandatory = $true)]
    [string]$vmName,
    [Parameter(Mandatory = $true)]
    [string]$parsecEmail,
    [Parameter(Mandatory = $true)]
    [string]$vmPassword
)

Set-Location $PSScriptRoot
.("..\AOFLibrary\AOFLibrary.ps1")

$ScriptName = "LoginToParsec"
$LogFile = BeginScriptLogging -ScriptName $ScriptName

$password = ConvertTo-SecureString $vmPassword -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("Administrator", $password)

Add-Type -AssemblyName System.Security
function Decrypt-WithDPAPI {
    param ([string]$CipherText)

    $encryptedBytes = [Convert]::FromBase64String($CipherText)
    $decryptedBytes = [System.Security.Cryptography.ProtectedData]::Unprotect($encryptedBytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
    
    return [System.Text.Encoding]::UTF8.GetString($decryptedBytes)
}

$parsecPassword = Read-Host # not passed as script argument due to security reasons
$parsecPassword = Decrypt-WithDPAPI -CipherText $parsecPassword

$pattern = "^[a-zA-Z0-9](\.?[a-zA-Z0-9_\-+])*@[a-zA-Z0-9-]+(\.[a-zA-Z]{2,})+$"
if(-not [Regex]::Match($parsecEmail, $pattern).Success -or -not $parsecPassword)
{
    Write-Log -Message "INVALID_PARSEC_CREDENTIALS" -Level WARN -Log $LogFile
    Stop-Transcript
    exit
}

function Attempt-ParsecLogin(
    [string]$vmName,
    [System.Management.Automation.PSCredential]$cred,
    [string]$parsecEmail,
    [string]$parsecPassword
) {
    try {
        $content = Invoke-Command -VMName $vmName -Credential $cred -ArgumentList $parsecEmail, $parsecPassword -ScriptBlock {
            param($parsecEmail, $parsecPassword)
    
            if(Test-Path ($env:ProgramData + "\Parsec\user.bin"))
            {
                return "USER_ALREADY_LOGGED_IN"
            }
    
            $credentialPipeName = "aofg_parsec_credentials"
            $credentialPipeClient = New-Object System.IO.Pipes.NamedPipeClientStream '.', $credentialPipeName, 'Out'
            $credentialPipeClient.Connect()
            $writer = New-Object System.IO.StreamWriter $credentialPipeClient
            $writer.WriteLine($parsecEmail)
            $writer.WriteLine($parsecPassword)
            $writer.Close()
            $credentialPipeClient.Close()
    
            $resultPipe = "aofg_parsec_login_output"
            $resultPipeClient = New-Object System.IO.Pipes.NamedPipeClientStream '.', $resultPipe, 'In'
            $resultPipeClient.Connect()
            $reader = New-Object System.IO.StreamReader $resultPipeClient
            $content = $reader.ReadLine()
            $reader.Close()
            $resultPipeClient.Close()
    
            if(Test-Path ($env:ProgramData + "\Parsec\user.bin"))
            {
                $content = "200"
            }
    
            return $content
        } -ErrorAction Stop
    }
    catch {
        HandleScriptExecutionError -Message "Unable to fill in login information: $($PSItem.Exception.message)" -Log $LogFile
    }

    return $content
}

<#
INVALID_PARSEC_CREDENTIALS ADDITIONAL_CONFIRMATION_REQUIRED UNKNOWN_ERROR
#>


$maxAttempts = 2
$success = $false
for ($attempt = 0; $attempt -lt $maxAttempts; $attempt++)
{
    $content = Attempt-ParsecLogin -vmName $vmName -cred $cred -parsecEmail $parsecEmail -parsecPassword $parsecPassword
    if($content -eq "200")
    {
        Write-Log -Message "SUCCESS" -Level INFO -Log $LogFile
        $success = $true
        break
    }
    elseif($content -eq "403")
    {
        Write-Log -Message "ADDITIONAL_CONFIRMATION_REQUIRED" -Level WARN -Log $LogFile
        $success = $true
        break
    }
    elseif($content -eq "400" -or $content -eq "401")
    {
        Write-Log -Message "INVALID_PARSEC_CREDENTIALS" -Level WARN -Log $LogFile
        $success = $true
        break
    }
    elseif($content -eq "USER_ALREADY_LOGGED_IN")
    {
        Write-Log -Message "SUCCESS" -Level INFO -Log $LogFile
        $success = $true
        break
    }
    else
    {
        Write-Log -Message $content -Level WARN -Log $LogFile
        if ($attempt -lt $maxAttempts - 1)
        {
            Stop-VM -VMName $vmName
            Start-VM -VMName $vmName
            Wait-ForVMReady -VMName $vmName -MaxRetries 6 -SleepSeconds 2
            Start-Sleep -Seconds 2
        }
    }
}

if (-not $success)
{
    Write-Log -Message $content -LEVEL ERROR -Log $LogFile
}

Write-ScriptSuccess -Log $LogFile
