#!/bin/env fish
begin
    set -l dir (status dirname)

    set -l backupActions \
        backup backupSW prepareBackup prepareBackup backupArgs getBackupArgs restore restoreSW \
        userBackup userBackup prepareUserBackup prepareUserBackup userBackupArgs getUserBackupArgs userRestore userRestore

    set -l actions \
        install installSW \
        configure configureSW \
        userConfig userConfig \
        dependencies installSWDependencies

    set -a actions $backupActions

    for i in (seq 2 2 (count $actions))
        functions -e "$actions[$i]"
    end

    for i in (seq 1 8 (count $backupActions))
        set -l preRun $backupActions[(math $i + 3)]
        set -l function $backupActions[(math $i + 1)]
        set -l getArgs $backupActions[(math $i + 5)]
        set -l restore $backupActions[(math $i + 7)]

        for functionName in $function $restore
            function $functionName -V dir -V preRun -V getArgs -V functionName -V restore
                set -l args

                if functions -q $getArgs
                    set args ($getArgs $argv)
                end

                if [ "$functionName" = "$restore" ] || [ -n "$args" ]
                    for arg in name user
                        set -l varName "_flag_$arg"

                        begin
                            set -l backup $argv
                            argparse -i "$arg=" -- $args
                            set -l argv $backup
                        end

                        if [ -z "$$varName" ]
                            argparse -i "$arg=" -- $argv
                            set -a args "--$arg" "$$varName"
                        end
                    end

                    source "$dir/restoration.fish"

                    if [ "$functionName" != "$restore" ]
                        argparse -i "action=" -- $argv

                        if functions -q "$preRun"
                            "$preRun" $argv
                        end

                        backupFiles $args
                    else
                        restoreFiles $args
                    end
                end
            end
        end
    end

    function runPSUserAction
        argparse -i "script=" "action=" "user=" -- $argv

        if [ -z "$_flag_script" ]
            set _flag_script $argv[1]
        end

        pwsh -CommandWithArgs '& $args[0] $args[1] @{ name=$args[2]; }' "$_flag_script" "$_flag_action" "$_flag_user"
    end

    function runPSUserConfig
        runPSUserAction $argv --action ConfigureUser
    end

    function inherit -V actions -a script -d "Inherits the installer from the specified script."
        for i in (seq 1 2 (count $actions))
            set -l action $actions[$i]
            set -l functionName $actions[(math $i + 1)]
            set -l baseName $functionName"Base"

            function $baseName -V script -V action
                argparse -i "action=" -- $argv
                fish "$script" $action $argv
            end

            function $functionName -V baseName
                $baseName $argv
            end
        end
    end

    function runInstaller -V dir -a action
        argparse -i "name=" -- $argv

        if [ -z "$_flag_name" ]
            set -l path (status stack-trace | head -n4 | tail -n1 | string replace --regex -- '^\s*called on line \d+ of file (.*)$' '$1')
            set _flag_name (basename (dirname $path))
        end

        runInstallerAction --name "$_flag_name" $argv
    end

    function runInstallerAction -V dir -V actions
        argparse -i force "name=" "action=" -- $argv
        set -l install
        set -l name $_flag_name
        set -l action $_flag_action
        set -l args $_flag_force --name "$name"
        set -l dependencyFunction installSWDependencies
        set -l installDependencies
        source "$dir/settings.fish"

        if [ -n "$_flag_force" ]
            set force true
        else
            set force false
        end

        if functions -q "$dependencyFunction"
            set installDependencies __runSosftwareDependencyInstaller
            functions -c "$dependencyFunction" "$installDependencies"
            functions -e "$dependencyFunction"
        end

        if $force || isProgramEnabled $args
            set install true
        else
            set install false
        end

        if [ -z "$action" ]
            if [ -n "$argv[1]" ]
                set action $argv[1]
                set argv $argv[2..]
            else
                set action install
            end
        end

        for i in (seq 1 2 (count $actions))
            if [ "$action" = "$actions[$i]" ]
                set -l message
                set -l function $actions[(math $i + 1)]
                set -l preRun __preRun
                set -l postRun __postRun
                functions -e $preRun
                functions -e $postRun

                switch "$action"
                    case install
                        set message "Installing `$name`..."

                        function $postRun -V args
                            runInstallerAction $args --action configure

                            if not isConfigured || [ "$USER" != (getConfig "valhalla.setupUser.name") ]
                                runInstallerAction $args --action userConfig
                            end
                        end
                    case configure
                        set message "Configuring `$name`..."

                        function $preRun -V args
                            runInstallerAction $args --action restore
                        end
                    case userConfig userBackup userRestore
                        argparse -i "user=" -- $argv
                        set -l user "$_flag_user"

                        if [ -z "$user" ]
                            set user "$USER"
                            set -a args --user "$user"
                        end

                        if $force || isProgramEnabled $args
                            set install true
                        else
                            set install false
                        end

                        switch "$action"
                            case userConfig
                                set message "Configuring `$name` for `$user`..."

                                function $preRun -V args
                                    runInstallerAction $args --action userRestore
                                end
                            case userBackup
                                set message "Backing up `$name` for `$user`..."
                            case userRestore
                                set message "Restoring `$name` for `$user`..."
                        end
                end

                if functions -q $preRun
                    $preRun
                end

                if functions -q "$function" && $install
                    if [ -n "$message" ]
                        echo $message
                    end

                    "$function" $args $argv
                end

                if functions -q $postRun
                    $postRun
                end
            end
        end

        if [ -n "$installDependencies" ]
            "$installDependencies" --action "$action" $args $argv
            functions -c "$installDependencies" "$dependencyFunction"
            functions -e "$installDependencies"
        end
    end
end