#!/bin/bash

dockerSwitcherSwap()
{
    local flag="$1"
    local run_switcher="false"

    dockerSwitcherSetSocketPermissions;

    # Select preexisting docker_type
    if [ -f "$docker_dir/$db_file" ]; then
        local docker_type=$(runInstallOp sqlite3 "$docker_dir/$db_file" 'SELECT content FROM options WHERE option = "docker_type";')
        # Insert into DB if something doesnt exist
        if [[ $docker_type == "" ]]; then
            databaseOptionInsert "docker_type" $CFG_DOCKER_INSTALL_TYPE;
            local docker_type=$(runInstallOp sqlite3 "$docker_dir/$db_file" 'SELECT content FROM options WHERE option = "docker_type";')
        fi
    else
        :
    fi

    # Check if docker install type is different
    if [[ $CFG_DOCKER_INSTALL_TYPE != $docker_type ]]; then
        isHeader "Docker Root/Rootless Switcher"

        # Switching modes re-maps container UIDs (rootless shifts them by the
        # subuid base), so a stateful app's on-disk data won't line up in the
        # new mode and a chown can't carry it. LibrePortal's control plane is
        # reconciled automatically (reconcileDockerOwnership); third-party app
        # data is carried by an automatic backup-before / restore-after when a
        # backup location is enabled.
        isNotice "Switching Docker mode re-maps container ownership."
        if [[ -n "$(resticEnabledLocations)" ]]; then
            isNotice "Stateful apps will be backed up now and restored automatically after the switch."
        else
            isNotice "No backup location enabled — back up stateful apps by hand BEFORE switching and restore AFTER."
        fi

        if [[ $CFG_DOCKER_INSTALL_TYPE == "rooted" ]]; then
            if [[ $flag != "cli" ]]; then
                isNotice "The current Docker Setup Type is currently : ${RED}$docker_type${NC}"
                echo ""
                while true; do
                    isQuestion "Would you like to switch to Rooted Docker? (y/n): "
                    echo ""
                    read -p "" switch_rooted_choice
                    if [[ -n "$switch_rooted_choice" ]]; then
                        break
                    fi
                    isNotice "Please provide a valid input."
                done
            else 
                switch_rooted_choice="y"
            fi
            if [[ "$switch_rooted_choice" == [yY] ]]; then
                isNotice "Switching to the Rooted Docker now..."
                # Back up every app under the old (still-running) mode first; a
                # failure aborts the switch before anything changes.
                if ! switchMigrateBackupApps "$docker_type"; then
                    return 1
                fi
                # Looking at the Rootless Install
                if [[ $docker_rootless_found == "true" ]]; then
                    dockerComposeDownAllApps rootless;
                    dockerServiceStop rootless;
                fi
                if [[ $rootless_docker_failed_stop != "true" ]]; then
                    # Looking for Root install
                    if [[ $docker_root_found == "false" ]]; then
                        installDocker;
                    fi
                    dockerServiceStart rooted;
                    dockerSwitcherUpdateContainersToDockerType "$docker_type";
                    reconcileDockerOwnership "$CFG_DOCKER_INSTALL_TYPE";
                    dockerStartAllApps;
                    databaseOptionInsert "docker_type" $CFG_DOCKER_INSTALL_TYPE;
                    switchMigrateRestoreApps;
                    installLibrePortalWebUITaskService;
                fi
            fi
        fi

        if [[ $CFG_DOCKER_INSTALL_TYPE == "rootless" ]]; then
            if [[ $flag != "cli" ]]; then
                isNotice "The current Docker Setup Type is currently : ${RED}$docker_type${NC}"
                echo ""
                while true; do
                    isQuestion "Would you like to switch to Rootless Docker? (y/n): "
                    echo ""
                    read -p "" switch_rootless_choice
                    if [[ -n "$switch_rootless_choice" ]]; then
                        break
                    fi
                    isNotice "Please provide a valid input."
                done
            else 
                switch_rootless_choice="y"
            fi
            if [[ "$switch_rootless_choice" == [yY] ]]; then
                isNotice "Switching to the Rootless Docker now..."
                # Back up every app under the old (still-running) mode first; a
                # failure aborts the switch before anything changes.
                if ! switchMigrateBackupApps "$docker_type"; then
                    return 1
                fi
                # Looking at the Rooted Install
                if [[ $docker_rooted_found == "true" ]]; then
                    dockerComposeDownAllApps rooted;
                    dockerServiceStop rooted;
                fi
                dockerServiceStart rootless;
                dockerSwitcherUpdateContainersToDockerType "$docker_type";
                reconcileDockerOwnership "$CFG_DOCKER_INSTALL_TYPE";
                dockerStartAllApps;
                databaseOptionInsert "docker_type" $CFG_DOCKER_INSTALL_TYPE;
                switchMigrateRestoreApps;
                installLibrePortalWebUITaskService;
            fi
        fi
    elif [[ $flag == "cli" ]]; then
        isSuccessful "Docker type is already setup for "$CFG_DOCKER_INSTALL_TYPE" no changes needed..."
    fi
}

# Apps captured by switchMigrateBackupApps, consumed by switchMigrateRestoreApps.
# Both run inside the same dockerSwitcherSwap call, on either side of the daemon
# switch.
switch_migrated_apps=()

# Back up every installed app (except LibrePortal's own control plane, which the
# reconcile already carries) under the OLD, still-running mode so it can be
# restored under the new mode afterwards. backupAppStart talks to the daemon via
# CFG_DOCKER_INSTALL_TYPE, which the switcher has already advanced to the target
# mode, so force it (and the resolved install user) back to old_mode for the
# duration, then hand it back. Returns non-zero if any backup fails so the
# caller can abort the switch with nothing changed.
switchMigrateBackupApps()
{
    local old_mode="$1"

    switch_migrated_apps=()

    if [[ -z "$(resticEnabledLocations)" ]]; then
        isNotice "No backup location enabled — skipping automatic data migration."
        return 0
    fi

    local saved_type="$CFG_DOCKER_INSTALL_TYPE"
    CFG_DOCKER_INSTALL_TYPE="$old_mode"
    resolveDockerInstallUser

    # Enumerate under the OLD mode — containers/ is still owned by its container
    # user here, so runFileOp (now resolved to that user) can list it (the
    # manager can't list the 751 dockerinstall-owned dir under rootless).
    local subdirectories=($(runFileOp find "$containers_dir" -mindepth 1 -maxdepth 1 -type d))

    local failed=()
    local dir app_name
    for dir in "${subdirectories[@]}"; do
        app_name=$(basename "$dir")
        [[ "$app_name" == "libreportal" ]] && continue
        if backupAppStart "$app_name"; then
            switch_migrated_apps+=("$app_name")
        else
            failed+=("$app_name")
        fi
    done

    CFG_DOCKER_INSTALL_TYPE="$saved_type"
    resolveDockerInstallUser

    if [[ ${#failed[@]} -gt 0 ]]; then
        isError "Pre-switch backup failed for: ${failed[*]}"
        isNotice "Aborting the switch — nothing changed, apps remain on $old_mode."
        return 1
    fi

    isSuccessful "Backed up ${#switch_migrated_apps[@]} app(s) before switching."
    return 0
}

# Restore each app captured by switchMigrateBackupApps under the NEW mode (new
# daemon up, CFG_DOCKER_INSTALL_TYPE already the target). restoreAppStart wipes
# and re-lays each tree and re-owns it to the new mode's install user — the UID
# remap a chown can't do. Best-effort: a failed app is reported and the rest
# continue, since the daemon has already switched.
switchMigrateRestoreApps()
{
    [[ ${#switch_migrated_apps[@]} -eq 0 ]] && return 0

    resolveDockerInstallUser

    local failed=()
    local app_name
    for app_name in "${switch_migrated_apps[@]}"; do
        if ! restoreAppStart "$app_name" "latest"; then
            failed+=("$app_name")
        fi
    done

    if [[ ${#failed[@]} -gt 0 ]]; then
        isError "Post-switch restore failed for: ${failed[*]}"
        isNotice "The switch finished, but these apps need a manual restore: ${failed[*]}"
        return 1
    fi

    isSuccessful "Restored ${#switch_migrated_apps[@]} app(s) into $CFG_DOCKER_INSTALL_TYPE."
    return 0
}
