#!/bin/bash
# SPDX-Version: 3.0
# SPDX-CreationInfo: 2025-05-05; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.live.builder.git
# SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
# SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-FileType: SOURCE
# SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
# SPDX-PackageName: CISS.debian.live.builder
# SPDX-Security-Contact: security@coresecret.eu

guard_sourcing || return "${ERR_GUARD_SRCE}"

#######################################
# Print Error Message for Trap on 'ERR' in ${ERROR_LOG}
# Globals:
#   BASHOPTS
#   EPOCHREALTIME
#   ERRCMMD
#   ERRCODE
#   ERRFUNC
#   ERRLINE
#   ERRSCRT
#   EUID
#   LOG_DEBUG
#   LOG_ERROR
#   LOG_VAR
#   SECONDS
#   SHELLOPTS
#   UID
#   VAR_ARG_SANITIZED
#   VAR_EARLY_DEBUG
#   VAR_GIT_REL
#   VAR_PARAM_COUNT
#   VAR_PARAM_STRNG
#   VAR_SYSTEM
#   VAR_VERSION
#   VAR_VER_BASH
#   VAR_VER_DS
#   VAR_VER_LB
# Arguments:
#   None
#######################################
print_file_err() {
  {
    printf "❌ Trap on 'ERR'          : CISS.debian.live.builder Script failed. \n"
    printf "❌ Git Commit             : %s \n" "${VAR_GIT_REL}"
    printf "❌ Version                : %s \n" "${VAR_VERSION}"
    printf "❌ Epoch                  : %s \n" "${EPOCHREALTIME}"
    printf "❌ Bash                   : %s \n" "${VAR_VER_BASH}"
    printf "❌ Live-Build             : %s \n" "${VAR_VER_LB}"
    printf "❌ Debootstrap            : %s \n" "${VAR_VER_DS}"
    printf "❌ UID                    : %s \n" "${UID}"
    printf "❌ EUID                   : %s \n" "${EUID}"
    printf "❌ Hostsystem             : %s \n" "${VAR_SYSTEM}"
    printf "❌ Error                  : %s \n" "${ERRCODE}"
    printf "❌ Line                   : %s \n" "${ERRLINE}"
    printf "❌ Script                 : %s \n" "${ERRSCRT}"
    printf "❌ Function               : %s \n" "${ERRFUNC}"
    printf "❌ Command                : %s \n" "${ERRCMMD}"
    printf "❌ Script Runtime         : %s \n" "${SECONDS}"
    printf "❌ Arguments Counter      : %s \n" "${VAR_PARAM_COUNT}"
    printf "❌ Arguments Original     : %s \n" "${VAR_PARAM_STRNG}"
    printf "❌ Arguments Sanitized    : %s \n" "${VAR_ARG_SANITIZED}"
    printf "❌ Bashopts               : %s \n" "${BASHOPTS}"
    printf "❌ Shellopts              : %s \n" "${SHELLOPTS}"

    if "${VAR_EARLY_DEBUG}"; then

      printf "❌ Vars Dump saved at     : %s \n" "${LOG_VAR}"
      printf "❌ Debug Log saved at     : %s \n" "${LOG_DEBUG}"
      printf "❌ batcat --pager='less -r' %s \n" "${LOG_DEBUG}"

    fi

    printf "\n"
  } >> "${LOG_ERROR}"
}
### Prevents accidental 'unset -f'.
# shellcheck disable=SC2034
readonly -f print_file_err

#######################################
# Print Error Message for Trap on 'ERR' on Terminal.
# Globals:
#   ERRCMMD
#   ERRCODE
#   ERRFUNC
#   ERRLINE
#   ERRSCRT
#   LOG_DEBUG
#   LOG_ERROR
#   LOG_VAR
#   SECONDS
#   VAR_ARG_SANITIZED
#   VAR_EARLY_DEBUG
#   VAR_GIT_REL
#   VAR_PARAM_COUNT
#   VAR_PARAM_STRNG
#   VAR_SYSTEM
#   VAR_VERSION
#   VAR_VER_BASH
#   VAR_VER_DS
#   VAR_VER_LB
# Arguments:
#   None
#######################################
print_scr_err() {
  printf "\e[91m❌ Trap on 'ERR'          : CISS.debian.live.builder Script failed. \e[0m\n" >&2
  printf "\e[91m❌ Git Commit             : %s \e[0m\n" "${VAR_GIT_REL}" >&2
  printf "\e[91m❌ Version                : %s \e[0m\n" "${VAR_VERSION}" >&2
  printf "\e[91m❌ Epoch                  : %s \e[0m\n" "${EPOCHREALTIME}" >&2
  printf "\e[91m❌ Bash                   : %s \e[0m\n" "${VAR_VER_BASH}" >&2
  printf "\e[91m❌ Live-Build             : %s \e[0m\n" "${VAR_VER_LB}" >&2
  printf "\e[91m❌ Debootstrap            : %s \e[0m\n" "${VAR_VER_DS}" >&2
  printf "\e[91m❌ UID                    : %s \e[0m\n" "${UID}" >&2
  printf "\e[91m❌ EUID                   : %s \e[0m\n" "${EUID}" >&2
  printf "\e[91m❌ Hostsystem             : %s \e[0m\n" "${VAR_SYSTEM}" >&2
  printf "\e[91m❌ Error                  : %s \e[0m\n" "${ERRCODE}" >&2
  printf "\e[91m❌ Line                   : %s \e[0m\n" "${ERRLINE}" >&2
  printf "\e[91m❌ Script                 : %s \e[0m\n" "${ERRSCRT}" >&2
  printf "\e[91m❌ Function               : %s \e[0m\n" "${ERRFUNC}" >&2
  printf "\e[91m❌ Command                : %s \e[0m\n" "${ERRCMMD}" >&2
  printf "\e[91m❌ Script Runtime         : %s \e[0m\n" "${SECONDS}" >&2
  printf "\e[91m❌ Arguments Counter      : %s \e[0m\n" "${VAR_PARAM_COUNT}" >&2
  printf "\e[91m❌ Arguments Original     : %s \e[0m\n" "${VAR_PARAM_STRNG}" >&2
  printf "\e[91m❌ Arguments Sanitized    : %s \e[0m\n" "${VAR_ARG_SANITIZED}" >&2
  printf "\e[91m❌ Bashopts               : %s \e[0m\n" "${BASHOPTS}" >&2
  printf "\e[91m❌ Shellopts              : %s \e[0m\n" "${SHELLOPTS}" >&2
  printf "\e[91m❌ Error Log saved at     : %s \e[0m\n" "${LOG_ERROR}" >&2
  printf "\e[91m❌ batcat --pager='less -r' %s \e[0m\n" "${LOG_ERROR}" >&2

  if "${VAR_EARLY_DEBUG}"; then

    printf "\e[91m❌ Vars Dump saved at     : %s \e[0m\n" "${LOG_VAR}" >&2
    printf "\e[91m❌ Debug Log saved at     : %s \e[0m\n" "${LOG_DEBUG}" >&2
    printf "\e[91m❌ batcat --pager='less -r' %s \e[0m\n" "${LOG_DEBUG}" >&2

  fi

  print_stacktrace
  printf "%b" "${NL}"
}
### Prevents accidental 'unset -f'.
# shellcheck disable=SC2034
readonly -f print_scr_err

#######################################
# Trap function to be called on 'ERR'.
# Globals:
#   ERRCMMD
#   ERRCODE
#   ERRFUNC
#   ERRLINE
#   ERRSCRT
#   ERRTRAP
#   VAR_EARLY_DEBUG
#   VAR_HANDLER_AUTOBUILD
# Arguments:
#   1: $?
#   2: ${BASH_SOURCE[0]}
#   3: ${LINENO}
#   4: ${FUNCNAME[0]:-main}
#   5: ${BASH_COMMAND}
#######################################
trap_on_err() {
  trap - DEBUG ERR INT TERM

  declare -gx ERRCODE="$1"
  declare -gx ERRSCRT="$2"
  declare -gx ERRLINE="$3"
  declare -gx ERRFUNC="$4"
  declare -gx ERRCMMD="$5"
  # shellcheck disable=SC2034
  declare -gx ERRTRAP="true"

  if "${VAR_EARLY_DEBUG}"; then dump_user_vars; fi

  clean_up "${ERRCODE}"

  if ! "${VAR_HANDLER_AUTOBUILD}"; then clean_screen; fi

  print_file_err

  print_scr_err
}
### Prevents accidental 'unset -f'.
# shellcheck disable=SC2034
readonly -f trap_on_err

#######################################
# Gather all user-defined variables (name and value)
# Globals:
#   LOG_VAR
#   VAR_DUMP_VARS_INITIAL
#   VAR_VERSION
# Arguments:
#   None
#######################################
dump_user_vars() {
  ### Capture the final snapshot of all variables (excluding '^(BASH|_).*')
  # shellcheck disable=SC2155
  declare dump_vars_final=$(mktemp)
  set +x
  {
    declare var
    # shellcheck disable=SC2312
    while IFS= read -r var; do
      declare -p "${var}" 2>/dev/null
    done < <(compgen -v | grep -Ev '^(BASH|_).*')
  } | sort >| "${dump_vars_final}"
  set -x

  {
    printf "✅ CISS.debian.live.builder Config Variable Dump. \n"
    printf "✅ Version             : %s \n" "${VAR_VERSION}"
    printf "\n"
    printf "===== Initial VAR Environment ===== \n"
  } >> "${LOG_VAR}"

  comm -23 "${VAR_DUMP_VARS_INITIAL}" "${dump_vars_final}" >> "${LOG_VAR}"  || true

  {
    printf "\n"
    printf "===== Final VAR Environment ===== \n"
  } >> "${LOG_VAR}"

  comm -13 "${VAR_DUMP_VARS_INITIAL}" "${dump_vars_final}" >> "${LOG_VAR}" || true
  rm "${VAR_DUMP_VARS_INITIAL}" "${dump_vars_final}"
}
### Prevents accidental 'unset -f'.
# shellcheck disable=SC2034
readonly -f dump_user_vars

#######################################
# Print function() stacktrace.
# Globals:
#   BASH_LINENO
#   BASH_SOURCE
#   FUNCNAME
#   LINENO
#   LOG_ERROR
#   NL
#   RED
#   RES
# Arguments:
#   None
#######################################
print_stacktrace() {
  declare -i i=0

  printf "%b❌ %b%b" "${RED}" "${RES}" "${NL}"
  printf "❌ %b" "${NL}" >> "${LOG_ERROR}"

  printf "%b❌ Raw Stacktrace         : %b%b" "${RED}" "${RES}" "${NL}"
  printf "❌ Raw Stacktrace         : %b" "${NL}" >> "${LOG_ERROR}"

  for ((i=0; i<${#FUNCNAME[@]}-1; i++)); do

    if (( i == 0 )); then

      printf "%b❌   ➥ %s() at: [%s:%s] %b%b" "${RED}" "${FUNCNAME[i]}" "${BASH_SOURCE[i]}" "${LINENO:-?}" "${RES}" "${NL}"
      printf "❌   ➥ %s() at: [%s:%s] %b" "${FUNCNAME[i]}" "${BASH_SOURCE[i]}" "${LINENO:-?}" "${NL}" >> "${LOG_ERROR}"

    else

      printf "%b❌   ➥ %s() at: [%s:%s] %b%b" "${RED}" "${FUNCNAME[i]}" "${BASH_SOURCE[i]}" "${BASH_LINENO[i-1]:-?}" "${RES}" "${NL}"
      printf "❌   ➥ %s() at: [%s:%s] %b" "${FUNCNAME[i]}" "${BASH_SOURCE[i]}" "${BASH_LINENO[i-1]:-?}" "${NL}" >> "${LOG_ERROR}"

    fi

  done

  printf "%b" "${NL}"
}
### Prevents accidental 'unset -f'.
# shellcheck disable=SC2034
readonly -f print_stacktrace
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
