#!/usr/bin/env bash

set -Eeuo pipefail

EXPECTED_HOSTNAME="sqjcnginx01"
EXPECTED_IPV4="10.2.203.102"
EXPECTED_OS="openEuler release 24.03 (LTS-SP1)"
BUNDLE_ROOT="/opt/zhct-deploy"
PACKAGE_ROOT="${BUNDLE_ROOT}/packages"
RPM_ROOT="${PACKAGE_ROOT}/rpms"
STAGE="${PACKAGE_ROOT}/rpms.q040-stage"
EVIDENCE_DIR="/var/backups/zhct-q040/20260722T203557+0800"

ROOT_PACKAGES=(
  autoconf
  automake
  bash
  bzip2
  coreutils
  curl
  diffutils
  file
  findutils
  gawk
  gcc
  gcc-c++
  gettext
  grep
  gzip
  iproute
  iputils
  libmnl-devel
  libnfnetlink-devel
  libnftnl-devel
  libnl3-devel
  libtool
  make
  openssl-devel
  pcre2-devel
  pkgconf-pkg-config
  procps-ng
  python3
  rsync
  sed
  shadow-utils
  systemd
  systemd-devel
  tar
  unzip
  which
  zlib-devel
)

ORCHESTRATOR_RPMS=(
  "${PACKAGE_ROOT}/percona-orchestrator-3.2.6-22.el8.x86_64.rpm"
  "${PACKAGE_ROOT}/percona-orchestrator-cli-3.2.6-22.el8.x86_64.rpm"
  "${PACKAGE_ROOT}/percona-orchestrator-client-3.2.6-22.el8.x86_64.rpm"
)

ORCHESTRATOR_SHA256=(
  "0067ddf9845f31a2f150bbc5714e131676e7c05a87802c8aa3dbc3a0835d0ac2"
  "9814b2f688d3841baa8b99acf52a09eb8046d4b71fc4b19a3fff586dacbade40"
  "d7b4875ec035c3885c88351cd264fcc3f64f1b84780e0682c534d5771831e88a"
)

die() {
  printf 'ERROR: %s\n' "$*" >&2
  exit 1
}

die "superseded: the 303-RPM full closure was rejected; use q040-rebuild-minimal-rpm-closure.sh"

[[ "${EUID}" -eq 0 ]] || die "must run as root"
[[ "$(hostname -s)" == "${EXPECTED_HOSTNAME}" ]] || die "hostname mismatch"
[[ "$(tr -d '\r' </etc/openEuler-release)" == "${EXPECTED_OS}" ]] || die "OS mismatch"
ip -o -4 addr show scope global | awk '{print $4}' | cut -d/ -f1 | \
  grep -Fxq "${EXPECTED_IPV4}" || die "expected IPv4 is not configured"

command -v dnf >/dev/null || die "dnf not found"
dnf download --help >/dev/null 2>&1 || die "dnf download plugin not available"
[[ -d "${BUNDLE_ROOT}" ]] || die "bundle root not found"
[[ -d "${EVIDENCE_DIR}" ]] || die "Q040 evidence directory not found"
[[ ! -e "${RPM_ROOT}" ]] || die "RPM closure already exists: ${RPM_ROOT}"
for rpm_file in "${ORCHESTRATOR_RPMS[@]}"; do
  [[ -f "${rpm_file}" ]] || die "Orchestrator RPM missing: ${rpm_file}"
done

umask 077
resume_mode=0
if [[ -e "${STAGE}" ]]; then
  [[ -d "${STAGE}" ]] || die "RPM stage is not a directory: ${STAGE}"
  [[ -s "${EVIDENCE_DIR}/dnf-download-closure.log" ]] || die "resume download log is missing"
  [[ -s "${EVIDENCE_DIR}/dnf-download-orchestrator-dependencies.log" ]] || \
    die "resume Orchestrator dependency log is missing"
  grep -Fq '(298/298)' "${EVIDENCE_DIR}/dnf-download-closure.log" || \
    die "openEuler closure download did not reach its recorded final item"
  grep -Fq 'Complete!' "${EVIDENCE_DIR}/dnf-download-orchestrator-dependencies.log" || \
    die "Orchestrator dependency download did not complete"
  resume_mode=1
else
  install -d -m 0750 "${STAGE}"

  dnf -v repolist --all >"${EVIDENCE_DIR}/dnf-repolist-before-closure.txt" 2>&1
  find /etc/yum.repos.d -maxdepth 2 -type f -print0 | sort -z | \
    xargs -0 -r sha256sum >"${EVIDENCE_DIR}/yum-repo-files.sha256"
  grep -RHE '^[[:space:]]*(\[|name=|baseurl=|metalink=|mirrorlist=|enabled=|gpgcheck=|repo_gpgcheck=|gpgkey=)' \
    /etc/yum.repos.d >"${EVIDENCE_DIR}/yum-repo-effective-lines.txt" || true

  dnf -y --refresh download \
    --resolve \
    --alldeps \
    --archlist=x86_64,noarch \
    --destdir="${STAGE}" \
    "${ROOT_PACKAGES[@]}" \
    >"${EVIDENCE_DIR}/dnf-download-closure.log" 2>&1

  dnf repoquery \
    --requires \
    --resolve \
    --recursive \
    --archlist=x86_64,noarch \
    --qf '%{name}\t%{epoch}:%{version}-%{release}\t%{arch}\t%{repoid}\t%{downloadsize}' \
    "${ROOT_PACKAGES[@]}" \
    | sort -u >"${EVIDENCE_DIR}/dnf-closure-repository.tsv"

  dnf -y install \
    --downloadonly \
    --downloaddir="${STAGE}" \
    --setopt=install_weak_deps=False \
    --setopt=localpkg_gpgcheck=False \
    "${ORCHESTRATOR_RPMS[@]}" \
    >"${EVIDENCE_DIR}/dnf-download-orchestrator-dependencies.log" 2>&1
fi

# These are openEuler repository RPMs only. Percona RPMs use the separately
# recorded Percona keyring verification and are copied after this trust check.
find "${STAGE}" -maxdepth 1 -type f -name '*.rpm' -print0 | sort -z | \
  xargs -0 -r rpm -K >"${EVIDENCE_DIR}/openeuler-rpm-signatures.txt" 2>&1 || true
[[ -s "${EVIDENCE_DIR}/openeuler-rpm-signatures.txt" ]] || die "no openEuler RPM was downloaded"
if grep -Eiq 'BAD|NOT OK|NOKEY|NOTTRUSTED' "${EVIDENCE_DIR}/openeuler-rpm-signatures.txt"; then
  die "one or more closure RPM signatures are not trusted"
fi

[[ -s "${EVIDENCE_DIR}/orchestrator-rpm-signature-verified.txt" ]] || \
  die "Percona RPM signature evidence is missing"
percona_signature_evidence="${EVIDENCE_DIR}/orchestrator-rpm-signature-verified.txt"
[[ $(grep -Eci '8507efa5:[[:space:]]+OK' "${percona_signature_evidence}") -eq 3 ]] || \
  die "expected three Percona RPM signatures from key 8507efa5"
if grep -Eiq 'BAD|NOT OK|NOKEY|NOTTRUSTED' "${percona_signature_evidence}"; then
  die "Percona RPM signature verification did not pass"
fi
for index in "${!ORCHESTRATOR_RPMS[@]}"; do
  rpm_file=${ORCHESTRATOR_RPMS[$index]}
  actual=$(sha256sum "${rpm_file}" | awk '{print $1}')
  [[ "${actual}" == "${ORCHESTRATOR_SHA256[$index]}" ]] || \
    die "Orchestrator RPM SHA256 mismatch: ${rpm_file}"
  cp -p "${rpm_file}" "${STAGE}/"
done

find "${STAGE}" -maxdepth 1 -type f -name '*.rpm' -print0 | sort -z | \
  xargs -0 -r rpm -qp --qf '%{NAME}\t%{EPOCHNUM}:%{VERSION}-%{RELEASE}\t%{ARCH}\t%{SIZE}\t%{VENDOR}\n' \
  | sort -u >"${EVIDENCE_DIR}/openeuler-rpm-nevra.tsv"

find "${STAGE}" -maxdepth 1 -type f -name '*.rpm' -print0 | sort -z | \
  xargs -0 sha256sum >"${EVIDENCE_DIR}/openeuler-rpm-sha256.txt"

find /var/cache/dnf -type f -path '*/repodata/repomd.xml' -print0 | sort -z | \
  xargs -0 -r sha256sum >"${EVIDENCE_DIR}/dnf-repomd-sha256.txt"

{
  printf 'captured_at=%s\n' "$(date --iso-8601=seconds)"
  printf 'os=%s\n' "${EXPECTED_OS}"
  printf 'arch=x86_64\n'
  printf 'root_packages='
  printf '%s,' "${ROOT_PACKAGES[@]}"
  printf '\n'
  printf 'rpm_count=%s\n' "$(find "${STAGE}" -maxdepth 1 -type f -name '*.rpm' | wc -l)"
  printf 'rpm_bytes=%s\n' "$(du -sb "${STAGE}" | awk '{print $1}')"
  printf 'signature_check=PASS\n'
  printf 'resume_mode=%s\n' "${resume_mode}"
  printf 'install_execution=NOT_PERFORMED\n'
} >"${EVIDENCE_DIR}/rpm-closure-result.env"

chmod 0600 "${EVIDENCE_DIR}"/dnf-repolist-before-closure.txt \
  "${EVIDENCE_DIR}"/dnf-download-closure.log \
  "${EVIDENCE_DIR}"/dnf-closure-repository.tsv \
  "${EVIDENCE_DIR}"/dnf-download-orchestrator-dependencies.log \
  "${EVIDENCE_DIR}"/yum-repo-files.sha256 \
  "${EVIDENCE_DIR}"/yum-repo-effective-lines.txt \
  "${EVIDENCE_DIR}"/openeuler-rpm-signatures.txt \
  "${EVIDENCE_DIR}"/openeuler-rpm-nevra.tsv \
  "${EVIDENCE_DIR}"/openeuler-rpm-sha256.txt \
  "${EVIDENCE_DIR}"/dnf-repomd-sha256.txt \
  "${EVIDENCE_DIR}"/rpm-closure-result.env

mv "${STAGE}" "${RPM_ROOT}"
chmod -R go-rwx "${RPM_ROOT}"

printf 'Q040_RPM_CLOSURE_OK\n'
cat "${EVIDENCE_DIR}/rpm-closure-result.env"
