#!/bin/bash

# webuiRunUpdate — non-interactive LibrePortal update for the WebUI.
#
# Invoked as a task via `libreportal update apply` (see cli_update_commands.sh),
# so it runs under the task processor with stdin closed and
# LIBREPORTAL_NONINTERACTIVE=1. It must therefore never block on a prompt:
# every decision is resolved up front from config, and it bails out cleanly
# (non-zero) instead of asking a question.
#
# Flow: guard -> forced update check -> if behind, run the proven file update
# (gitPerformUpdate) -> redeploy the portal so the new WebUI is live ->
# regenerate WebUI data and refresh the out-of-date status.
webuiRunUpdate()
{
    isHeader "LibrePortal Update"

    sourceCheckFiles;

    local install_mode="${CFG_INSTALL_MODE:-git}"
    local git_updates="${CFG_GIT_UPDATES:-true}"

    if [[ "$install_mode" == "local" ]]; then
        isError "This is a local installation — updates are managed manually, nothing to pull."
        return 1
    fi
    if [[ "$git_updates" != "true" ]]; then
        isError "Updates are disabled (CFG_GIT_UPDATES). Enable them to update from the WebUI."
        return 1
    fi

    # Release mode: version-compare the channel's latest against the local VERSION
    # and, if newer, fetch + verify the new tarball and redeploy. No config backup
    # dance — lpFetchRelease replaces only the install tree; configs/logs live in
    # the separate system tree.
    if [[ "$install_mode" == "release" ]]; then
        webuiSystemUpdateCheck "force"
        local cur lat
        cur=$(tr -d ' \t\n\r' < "$script_dir/VERSION" 2>/dev/null)
        lat=$(lpReleaseLatestVersion 2>/dev/null)
        if [[ -z "$lat" ]]; then
            isError "Could not reach the release server ($(lpReleaseBaseUrl))."
            return 1
        fi
        if ! lpVersionGt "$lat" "$cur"; then
            isSuccessful "LibrePortal is already up to date (v${cur})."
            return 0
        fi
        # If the release bumps the root-owned footprint (helpers/wrapper/unit), a
        # manager-run apply can't install it — those are deliberately not
        # manager-writable. Require a root re-install, which fetches + re-bakes
        # everything atomically.
        local inst_fp rel_fp
        inst_fp=$(lpInstalledFootprintVersion 2>/dev/null)
        rel_fp=$(lpReleaseLatestFootprint 2>/dev/null)
        if [[ -n "$rel_fp" && "${rel_fp:-0}" -gt "${inst_fp:-0}" ]]; then
            isError "Update v${lat} changes system components — it must be applied as root, not from the WebUI."
            isNotice "Run on the host:  curl -fsSL $(lpReleaseBaseUrl)/install.sh | sudo bash"
            isNotice "(or, from the install tree:  sudo ${script_dir}/init.sh --unattended init ... )"
            return 1
        fi
        isNotice "Update found — v${cur} → v${lat}. Fetching the verified release..."
        lpFetchRelease "$lat" || { isError "Release fetch failed — install unchanged."; return 1; }
        isNotice "Redeploying LibrePortal with the new version..."
        dockerInstallApp "libreportal"
        WEBUI_UPDATER_FORCE=1 webuiLibrePortalUpdate
        webuiSystemUpdateCheck "force"
        isSuccessful "LibrePortal has been updated to v${lat}."
        return 0
    fi

    # Credential guard — gitReset()/gitCheckGitDetails() would otherwise prompt
    # for missing git details and hang the task forever. Fail fast with a clear
    # message instead.
    if [[ "$install_mode" == "git" ]]; then
        if [[ -z "$CFG_GIT_USER" || "$CFG_GIT_USER" == "changeme" ]]; then
            isError "Git credentials are not configured. Run the 'libreportal' command once on the host, then retry."
            return 1
        fi
        if [[ "$CFG_GIT_USER" != "empty" && ( -z "$CFG_GIT_KEY" || "$CFG_GIT_KEY" == "changeme" ) ]]; then
            isError "Git access token is not configured. Run the 'libreportal' command once on the host, then retry."
            return 1
        fi
    fi

    cd "$script_dir" || { isError "Cannot access the install directory ($script_dir)."; return 1; }
    runAsManager git config core.fileMode false

    # Force a fresh fetch + status write so the decision below (and the badge)
    # reflect reality right now, not a stale throttled snapshot.
    webuiSystemUpdateCheck "force"

    local branch behind
    branch=$(runAsManager git -C "$script_dir" rev-parse --abbrev-ref HEAD 2>/dev/null)
    [[ -z "$branch" || "$branch" == "HEAD" ]] && branch="main"
    behind=$(runAsManager git -C "$script_dir" rev-list --count "HEAD..refs/remotes/origin/$branch" 2>/dev/null)
    [[ -z "$behind" ]] && behind=0

    if [[ "$behind" -eq 0 ]]; then
        isSuccessful "LibrePortal is already up to date."
        return 0
    fi

    isNotice "Update found — $behind commit(s) behind origin/$branch. Updating now..."

    # Proven file-level update: back up configs/logs, re-clone, restore.
    gitPerformUpdate;

    # Redeploy the portal from the freshly pulled source so the new WebUI goes
    # live. This is exactly what `libreportal app install libreportal` does, so
    # it's already safe to run non-interactively. It restarts the container; the
    # task processor runs on the host, so this task survives the restart.
    isNotice "Redeploying LibrePortal with the new version..."
    dockerInstallApp "libreportal"

    # Regenerate WebUI data (new version, configs, etc.) and clear the
    # out-of-date flag.
    WEBUI_UPDATER_FORCE=1 webuiLibrePortalUpdate
    webuiSystemUpdateCheck "force"

    isSuccessful "LibrePortal has been updated."
}

checkUpdates()
{
    local param1="$1"

	sourceCheckFiles;

	# Skip Git updates if installation mode is local or Git updates are disabled
	if [[ $CFG_INSTALL_MODE == "local" ]]; then
		isNotice "Local installation detected - Git updates are disabled."
		if [[ $init_run_flag == "true" ]]; then
			startLoad;
		fi
		return
	fi

	if [[ $CFG_GIT_UPDATES == "true" ]]; then
		isHeader "Checking for Updates"

		# Ask user if they want to check for updates
		while true; do
			if [[ $CFG_GIT_UPDATES == "false" ]]; then
				isQuestion "Would you like to check for updates? (y/n): "
				read -p "" check_updates_choice
			elif [[ $CFG_GIT_UPDATES == "true" ]]; then
				check_updates_choice=y
			fi
			case $check_updates_choice in
				[yY])
					# DNS Query Test with Quad9
					isNotice "Testing internet DNS, please wait..."
					if command -v dig >/dev/null 2>&1; then
						dns_check_cmd="dig +short +time=3 +tries=1 @9.9.9.9 quad9.net"
					elif command -v getent >/dev/null 2>&1; then
						dns_check_cmd="getent hosts quad9.net"
					else
						dns_check_cmd="ping -c 1 -W 3 9.9.9.9"
					fi
					if $dns_check_cmd >/dev/null 2>&1; then
						isSuccessful "Internet DNS is working."
					else
						isError "Internet DNS is not working."
						exit 1
					fi

					cd "$script_dir" || { isError " Cannot navigate to the repository directory"; exit 1; }

					# Update Git to ignore changes in file permissions
					runAsManager git config core.fileMode false
					# Update Git with email address
					runAsManager git config --global user.name "$CFG_INSTALL_NAME"
					runAsManager git config --global user.email "noreply@${CFG_INSTALL_NAME,,}.libreportal.local"

					# Check if there are edited (modified) files
					if git status --porcelain | grep -q "^ M"; then
						isNotice "There are uncommitted changes in the repository."
						while true; do
							isQuestion "Do you want to discard these changes and update the repository? (y/n): "
							read -p "" customupdatesfound
							case $customupdatesfound in
								[yY])
									remove_changes=true
									gitCheckForUpdate;
									gitCheckConfigs;
									fixPermissionsBeforeStart "" "update";
									sourceCheckFiles;

									if [[ $init_run_flag == "true" ]]; then
										isSuccessful "Starting/Restarting LibrePortal"
										startLoad;
									fi
									
									;;
								[nN])
									isNotice "Custom changes will be kept, continuing..."
									remove_changes=false
									gitCheckForUpdate;
									gitCheckConfigs;
									fixPermissionsBeforeStart "" "update";
									sourceCheckFiles;
									
									if [[ $init_run_flag == "true" ]]; then
										startLoad;
									fi
									
									;;
								*)
									isNotice "Please provide a valid input (y or n)."
									;;
							esac
						done
					fi

					# Make sure an update happens after custom code check
					if [[ $update_done != "true" ]]; then
						gitCheckForUpdate;

						gitCheckConfigs;
						fixPermissionsBeforeStart "" "update";
						sourceCheckFiles;

						if [[ $init_run_flag == "true" ]]; then
							isSuccessful "Starting/Restarting LibrePortal"
							startLoad;
						fi
					fi
					;;
				[nN])
					echo ""
					isNotice "Skipping update check. Starting application..."
					if [[ $init_run_flag == "true" ]]; then
						startLoad;
					fi
					;;
				*)
					isNotice "Please enter y or n."
					;;
			esac
		done
	else
        if [[ $init_run_flag == "true" ]]; then
            startLoad;
        fi
	fi
}
