using namespace System.Collections.Generic;
. "$PSScriptRoot/../../Common/Scripts/System.ps1";

$null = New-Module {
    $pathResolver = {
        param(
            [string] $User,
            [string] $Path
        )

        [string] $result = $null;

        if ($User) {
            $result = "Users/$User";
        } else {
            $result = "System";
        }

        if (-not $Path) {
            $Path = "Files";
        }

        $result = Join-Path $result $Path;
        return $result;
    };

    <#
        .SYNOPSIS
        Gets the name of the variable holding the path to the backup archive of the current machine.
    #>
    function Get-ArchiveVariableName {
        return "BACKUP_ARCHIVE";
    }

    <#
        .SYNOPSIS
        Gets the path to the backup archive of the current machine.
    #>
    function Get-ValhallaBackupArchive {
        (Get-Item "Env:\$(Get-ArchiveVariableName)").Value;
    }

    <#
        .SYNOPSIS
        Sets the path to the backup archive of the current machine.

        .PARAMETER Path
        The path to set.
    #>
    function Set-ValhallaBackupArchive {
        param(
            [string] $Path
        )

        Set-Item "Env:\$(Get-ArchiveVariableName)" $Path;
    }

    <#
        .SYNOPSIS
        Adds files to the backup archive.

        .PARAMETER User
        The user to add the files to.

        .PARAMETER Source
        The file or directory to add to the backup archive.

        .PARAMETER Path
        The path to the location to store the file or directory at.

        .PARAMETER ArgumentList
        The arguments to pass to the `7z` command.
    #>
    function Add-BackupArtifacts {
        param(
            [string] $User,
            [string] $Source,
            [string] $Path,
            [string[]] $Include,
            [string[]] $Exclude
        )

        if ($env:BACKUP_ARCHIVE) {
            [List[string]] $argumentList = @();
            $dir = New-TemporaryDirectory;
            $targetPath = & $pathResolver @PSBoundParameters;
            $fullPath = Join-Path $dir $targetPath;
            $null = New-Item -ItemType Directory -Force (Split-Path -Parent $fullPath);

            if (Test-Path -PathType Container $Source) {
                $null = New-Item -ItemType Junction $fullPath -Target $Source;
            } elseif (Test-Path -PathType Leaf $Source) {
                Copy-Item $Source $fullPath;
            }

            $options = @(
                @("i", $Include),
                @("x", $Exclude)
            );

            foreach ($option in $options) {
                $indicator = $option[0];
                $list = $option[1];

                foreach ($pattern in $list) {
                    $argumentList.Add("-$indicator!`"$(Join-Path $targetPath $pattern)`"");
                }
            }

            Start-Process `
                -NoNewWindow `
                -Wait `
                -WorkingDirectory $dir `
                -FilePath 7z `
                -ArgumentList (
                    @(
                        "a",
                        (Get-ValhallaBackupArchive),
                        "-xr!desktop.ini",
                        "-xr!thumbs.db",
                        "-xr!Thumbs.db"
                    ) + $argumentList);

            Remove-Item -Recurse -Force $dir;
        }
    }

    <#
        .SYNOPSIS
        Extracts the specified backup artifacts to the specified target path.

        .PARAMETER User
        The user to restore the files for.

        .PARAMETER Path
        The path to restore the files from.

        .PARAMETER Target
        The path to restore the files to.

        .PARAMETER ArgumentList
        The arguments to pass to `7z`.
    #>
    function Expand-BackupArtifacts {
        param(
            [string] $User,
            [string] $Path,
            [string] $Target,
            [Parameter(ValueFromRemainingArguments)]
            [string[]] $ArgumentList
        )

        if ($env:BACKUP_ARCHIVE) {
            $dir = New-TemporaryDirectory;
            $sourcePath = & $pathResolver @PSBoundParameters;
            $filePath = Join-Path $dir $sourcePath;
            7z x "-o$dir" (Get-ValhallaBackupArchive) $sourcePath @ArgumentList;

            if (Test-Path $filePath) {
                if (Test-Path -PathType Container $filePath) {
                    $null = New-Item -ItemType Directory $Target -Force;
                    $filePath = "$filePath/*";
                }

                Copy-Item -Recurse $filePath $Target -Force;
            }

            Remove-Item -Recurse -Force $dir;
        }
    }
};