#!/bin/bash

## Copyright (C) 2023 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

set -x
set -o errexit
set -o nounset
set -o pipefail
set -o errtrace

true "$0: START"

run_cmd() {
  [ -n "${TESTING_MODE:-}" ] || TESTING_MODE=0
  if [ "${TESTING_MODE:-0}" -eq 1 ]; then
    set +x
    printf '%s\n' "$@"
  else
    "$@"
  fi
}

## This path to this script in the derivative-maker source code folder is help-steps/dm-build-official.
## Go to root of the source code folder.
## Only needed if one would 'cd ./help-steps' beforehand.
#run_cmd cd ..

true "INFO: 0: $0"

if [ "${CI:-}" = "true" ]; then
  true "INFO: Skipping test if folder ~/.ssh exists on CI."
elif [ "${build_dry_run:-}" = "true" ]; then
  ## '--dry-run true' is documented (see 'help-steps/parse-cmd') as
  ## "useful for debugging dm-prepare-release"; rsync is mocked
  ## (see 'help-steps/variables' '$rsync_cmd' default for dry-run),
  ## so '~/.ssh' is not used for real uploads and its absence is not
  ## an error. Coordinated with
  ## 'build-steps.d/1100_sanity-tests'
  ## 'check-redistributable-builds-requirements()'.
  true "INFO: Skipping test if folder ~/.ssh exists in dry-run mode."
else
  run_cmd test -d ~/.ssh
fi

## Optional testing of docker on CI.
if [ "${CI:-}" = "true" ]; then
  ## Minimal test only for now.
  sudo --non-interactive -- ./docker/derivative-maker-docker-setup
  ./docker/derivative-maker-docker-run --build-step 1100_sanity-tests --target raw --flavor source
fi

## architecture choice
## - If environment variable 'dist_build_target_arch' is set, honor it.
## - On CI, build ARM64 by default since it is the most recent architecture port.
## - Official builds default to Intel/AMD64 at the time of writing.
if ! [ "${dist_build_target_arch:-}" = "" ]; then
  architecture="$dist_build_target_arch"
elif [ "${CI:-}" = "true" ]; then
  architecture=arm64
  build_args+=(--remote-derivative-packages true)
  export dist_build_upgrade_build_machine=1
else
  architecture="amd64"
fi
build_args+=(--arch "$architecture")

## Ordered as follows for the following reasons:
## - 1) Build '--flavor kicksecure-lxqt' because building ISO, which is newer,
##      therefore more prone to build issues. Error out quicker is better.
## - 2) Build '--flavor whonix-gateway-lxqt' because it is required to be able to
##      run dm-prepare-release due to unified ova files.
## - 3) Build '--flavor whonix-workstation-lxqt' because it is the most
##      complex, because of downloading Tor Browser as well as when used with
##      '--target windows', because:
## - *_prepare-build-machine downloads VirtualBox-*-Win.exe
## - dm-prepare-release builds Whonix Windows Installer
## - 4) Build CLI flavors because these are the least likely to have build issues.
##
## NOTE: Fewer flavors are build on CI. If 'CI=true', 'help-steps/parse-cmd'
##       will inject 'build_dry_run="true"' (equivalent of '--dry-run true').
[ -n "${flavors_list:-}" ] || flavors_list=(
  kicksecure-lxqt
  kicksecure-cli
  whonix-gateway-lxqt
  whonix-workstation-lxqt
  whonix-gateway-cli
  whonix-workstation-cli
)

build_upload_noninteractive=true
export build_upload_noninteractive

dist_build_redistributable=true
export dist_build_redistributable

if [ "${dist_build_redistributable:-}" = "true" ]; then
  build_args+=(--repo true)
  build_args+=(--tb closed)
  ## Install package 'firmware-nonfreedom' by default.
  ## - Applicable to '--arch' 'amd64' only
  ## - Applicable to for ISO builds only.
  ## See also:
  ## https://www.kicksecure.com/wiki/Dev/nonfree
  build_args+=(--freedom false)
fi

if printf '%s\n' "$@" | grep -- "remote-derivative-packages true" &>/dev/null; then
  remote_derivative_packages=true
fi

if printf '%s\n' "${build_args[*]}" | grep -- "remote-derivative-packages true" &>/dev/null; then
  remote_derivative_packages=true
fi

if [ "${remote_derivative_packages:-}" = "true" ]; then
  ## Skip upload of debug images.
  rsync_cmd="true simulate-only"
  export rsync_cmd
fi

multi_target_args=()

case "${architecture:-}" in
  amd64)
    ## '--target virtualbox'
    ## Build VirtualBox ova. (amd64 for Windows, Linux, Mac)
    multi_target_args+=("--target" "virtualbox")
    multi_target_args+=("--target" "qcow2")
  ;;
  arm64)
    ## Build VirtualBox ova. (arm64 for Mac M1, M2 and maybe Linux.)
    #multi_target_args+=("--target" "virtualbox")
    #multi_target_args+=("--target" "qcow2")

    ## Only on arm64 for Mac M1, M2.
    ## TODO: re-enable once CI server issues have been resolved
    #multi_target_args+=("--target" "virtualbox")
    multi_target_args+=("--target" "qcow2")
  ;;
  *)
    ## '--target qcow2' might be the most universal.
    multi_target_args+=("--target" "qcow2")
  ;;
esac

## multi_target_args comment:
## Cannot mix,
## * 1) '--target iso', and,
## * 2) "${multi_target_args[@]}"
## because no ISO should be build for Whonix-Gateway, Whonix-Workstation.
## (Maybe in the future for Whonix-Host.)
## The ISO should only be built for Kicksecure-LXQt for now.

for flavor_item in "${flavors_list[@]}"; do
  ## Not yet using multi_target_args as the sanity test for Whonix-Gateway ISO would complain that the VMs
  ## have not been built yet.
  run_cmd ./build-steps.d/*_sanity-tests "${build_args[@]}" --target windows "${multi_target_args[@]}" --flavor "$flavor_item" "$@"
done

## Use both,
## * 1) '--target iso', and,
## * 2) "${multi_target_args[@]}"
## for prepare-build-machine, because additional dependencies are required for building the ISO.
run_cmd ./build-steps.d/*_prepare-build-machine "${build_args[@]}" --target iso --target windows "${multi_target_args[@]}" --flavor source "$@"

run_cmd ./build-steps.d/*_cowbuilder-setup "${build_args[@]}" --target iso --target windows "${multi_target_args[@]}" --flavor source "$@"
run_cmd ./build-steps.d/*_local-dependencies "${build_args[@]}" --target iso --target windows "${multi_target_args[@]}" --flavor source "$@"

export dist_build_raw_base_image_create=true
## '--flavor source' would lead to variable dist_build_hostname being unset.
## Therefore using '--flavor kicksecure-cli' to create a raw base image.
## '--target iso' must not be used because ISO is nowadays created using live-build, not create-raw-image.
## create-raw-image would do nothing if using '--target iso'.
run_cmd ./build-steps.d/*_create-raw-image "${build_args[@]}" "${multi_target_args[@]}" --flavor kicksecure-cli "$@"
unset dist_build_raw_base_image_create

## '--target iso' is required to download calamares from backports.
run_cmd ./build-steps.d/*_create-debian-packages "${build_args[@]}" --target iso "${multi_target_args[@]}" --flavor source "$@"

## Fast. No need to skip.
#SKIP_SCRIPTS+=" sanity-tests "

SKIP_SCRIPTS+=" prepare-build-machine "
SKIP_SCRIPTS+=" cowbuilder-setup "
## Using cached_binary_image_raw_file instead because we will set dist_build_use_cached_raw_base_image=true.
## Variable cached_binary_image_raw_file will result in create-raw-image simply making a copy of the exiting raw image.
#SKIP_SCRIPTS+=" create-raw-image "
SKIP_SCRIPTS+=" local-dependencies "
SKIP_SCRIPTS+=" create-debian-packages "
export SKIP_SCRIPTS

dist_build_use_cached_raw_base_image=true
export dist_build_use_cached_raw_base_image

## Build and dm-prepare-release.
for flavor_item in "${flavors_list[@]}"; do
  case "${flavor_item:-}" in
    kicksecure-lxqt)
      ## For now, create an ISO only for Kicksecure LXQt.
      ## Not for Kicksecure CLI.
      ## Not yet for Whonix.
      true "INFO: ISO build flavor."
      run_cmd ./derivative-maker "${build_args[@]}" --target iso --flavor "$flavor_item" "$@"
      ;;
    *)
      true "INFO: Non-ISO build flavor."
      ;;
  esac

  run_cmd ./derivative-maker "${build_args[@]}" "${multi_target_args[@]}" --flavor "$flavor_item" "$@"
done

## Same source code for all of the following:
## - desktop: LXQt versus CLI
## - target: Kicksecure versus Whonix.
## - architecture: all
run_cmd dm-prepare-release --target source --flavor "kicksecure-lxqt" "$@"
run_cmd dm-upload-images --target source --flavor "kicksecure-lxqt" "$@"
run_cmd dm-upload-images --target source --flavor "whonix-workstation-lxqt" "$@"

## TODO: Windows
# if [ "${CI:-}" = "true" ]; then
# #if [ "${architecture:-}" = "amd64" ]; then
#   ## Also build the Whonix-Windows-Installer.
#   run_cmd dm-prepare-release "${build_args[@]}" --target windows --flavor whonix-workstation-lxqt
#   run_cmd dm-upload-images "${build_args[@]}" --target windows --flavor whonix-workstation-lxqt
# fi

## Uploading.
for flavor_item in "${flavors_list[@]}"; do
  if printf '%s\n' "$flavor_item" | grep -- "gateway" &>/dev/null; then
    ## Not needed for gateway due to unified images.
    continue
  fi

  case "${flavor_item:-}" in
    kicksecure-lxqt)
      true "INFO: ISO build flavor."
      run_cmd dm-upload-images "${build_args[@]}" --target iso --flavor "$flavor_item" "$@"
      ;;
    *)
      true "INFO: Non-ISO build flavor."
      ;;
  esac

  ## Cannot use "${multi_target_args[@]}" here, because
  ## help-steps/variables variable dist_server_with_upload_location_list is does not support multiple "--target"'s.
  for ((i=0; i<${#multi_target_args[@]}; i+=2)); do
    target_arg="${multi_target_args[i]}"
    target_value="${multi_target_args[i+1]}"
    run_cmd dm-upload-images "${build_args[@]}" "$target_arg" "$target_value" --flavor "$flavor_item" "$@"
  done
done

true "$0: END"
