#!/usr/bin/env bash
set -Eeuo pipefail

archive="${1:?offline archive is required}"
output="${2:?output installer path is required}"
host_runtime_dir="${3:-}"

[[ -f "${archive}" ]] || { printf 'archive not found: %s\n' "${archive}" >&2; exit 1; }
[[ "${output}" == /* ]] || { printf 'output must be an absolute path\n' >&2; exit 1; }

stage_dir="$(mktemp -d "${TMPDIR:-/tmp}/foodsafe-run.XXXXXX")"
trap 'rm -rf -- "${stage_dir}"' EXIT
payload_dir="${stage_dir}/payload"
mkdir -p "${payload_dir}"
cp "${archive}" "${payload_dir}/"

archive_name="$(basename "${archive}")"
if command -v sha256sum >/dev/null 2>&1; then
  (cd "${payload_dir}" && sha256sum "${archive_name}" >"${archive_name}.sha256")
else
  (cd "${payload_dir}" && shasum -a 256 "${archive_name}" >"${archive_name}.sha256")
fi

if [[ -n "${host_runtime_dir}" ]]; then
  [[ -x "${host_runtime_dir}/install.sh" ]] || {
    printf 'host runtime must contain executable install.sh\n' >&2
    exit 1
  }
  cp -R "${host_runtime_dir}" "${payload_dir}/host-runtime"
fi

header="${stage_dir}/header.sh"
apply_header() {
  cat >"${header}" <<'HEADER'
#!/usr/bin/env bash
set -Eeuo pipefail

die() { printf '[FAIL] %s\n' "$1" >&2; exit 1; }
info() { printf '[foodsafe] %s\n' "$1"; }

[[ "${1:-}" == 'install' ]] || die 'usage: installer.run install --server-ip <ip> [--profile core|mqtt]'
shift
server_ip=''
profile='core'
while [[ $# -gt 0 ]]; do
  case "$1" in
    --server-ip) server_ip="${2:-}"; shift 2 ;;
    --profile) profile="${2:-}"; shift 2 ;;
    *) die "unknown argument: $1" ;;
  esac
done
[[ "${server_ip}" =~ ^[A-Za-z0-9.-]+$ ]] || die 'invalid server ip or host'
[[ "${profile}" == 'core' || "${profile}" == 'mqtt' ]] || die 'invalid profile'
if [[ "${profile}" == 'mqtt' ]]; then
  die 'MQTT profile is not present in this installer; use a target adapter that bundles Mosquitto'
fi
[[ "$(id -u)" == '0' ]] || die 'run this installer with sudo or as root'
[[ "$(uname -m)" == 'x86_64' ]] || die "linux/amd64 required, current architecture: $(uname -m)"

payload_line="$(awk '/^__FOODSAFE_PAYLOAD_BELOW__$/ { print NR + 1; exit }' "$0")"
[[ -n "${payload_line}" ]] || die 'installer payload marker is missing'
temp_dir="$(mktemp -d /tmp/foodsafe-install.XXXXXX)"
trap 'rm -rf -- "${temp_dir}"' EXIT
tail -n +"${payload_line}" "$0" | tar -xzf - -C "${temp_dir}"
payload_dir="${temp_dir}/payload"
archive="$(find "${payload_dir}" -maxdepth 1 -type f -name 'foodsafe-offline-*-linux-amd64.tar.gz' -print -quit)"
[[ -n "${archive}" ]] || die 'offline archive is missing from installer'
(cd "${payload_dir}" && sha256sum -c "$(basename "${archive}").sha256")

if ! command -v docker >/dev/null 2>&1; then
  if [[ -x "${payload_dir}/host-runtime/install.sh" ]]; then
    info 'Docker is missing; installing the bundled validated host runtime'
    bash "${payload_dir}/host-runtime/install.sh"
  else
    die 'Docker is missing and this installer has no validated openEuler host runtime bundle'
  fi
fi

systemctl enable --now docker
docker info >/dev/null 2>&1 || die 'Docker daemon is unavailable'
docker compose version >/dev/null 2>&1 || die 'Docker Compose V2 is required'

base_dir='/workspace/wwwroot/food_safety'
mkdir -p "${base_dir}/packages" "${base_dir}/releases" "${base_dir}/config" \
  "${base_dir}/data/uploads" "${base_dir}/data/aibox" "${base_dir}/backups"
bundle_name="$(tar -tzf "${archive}" | sed -n '1{s#/.*##;p;q;}')"
[[ "${bundle_name}" =~ ^foodsafe-offline-[A-Za-z0-9._-]+-linux-amd64$ ]] || die 'unexpected bundle name'
release_dir="${base_dir}/releases/${bundle_name}"

if [[ ! -d "${release_dir}" ]]; then
  tar -xzf "${archive}" -C "${base_dir}/releases"
fi
[[ -f "${release_dir}/compose.yaml" ]] || die 'compose.yaml is missing after extraction'

if [[ ! -L "${release_dir}/data" ]]; then
  rmdir "${release_dir}/data/uploads" "${release_dir}/data/aibox" "${release_dir}/data" 2>/dev/null \
    || die 'release data directory is not empty; refusing to replace it'
  ln -s "${base_dir}/data" "${release_dir}/data"
fi

env_file="${base_dir}/config/.env"
if [[ ! -f "${env_file}" ]]; then
  cp "${release_dir}/.env.example" "${env_file}"
  replace_env() {
    local key="$1" value="$2" temp
    temp="${env_file}.tmp"
    sed "s|^${key}=.*|${key}=${value}|" "${env_file}" >"${temp}"
    mv "${temp}" "${env_file}"
  }
  replace_env MYSQL_PASSWORD "$(openssl rand -hex 24)"
  replace_env MYSQL_ROOT_PASSWORD "$(openssl rand -hex 24)"
  replace_env JWT_SECRET "$(openssl rand -hex 24)"
  replace_env AUDIT_HMAC_SECRET "$(openssl rand -hex 24)"
  replace_env REDIS_PASSWORD "$(openssl rand -hex 24)"
  chmod 600 "${env_file}"
fi

if [[ -e "${release_dir}/.env" && ! -L "${release_dir}/.env" ]]; then
  die 'release .env exists and is not a managed symlink'
fi
ln -sfn "${env_file}" "${release_dir}/.env"

info "installing ${bundle_name}"
(cd "${release_dir}" && ./install.sh)
ln -sfn "${release_dir}" "${base_dir}/current"

docker_bin="$(command -v docker)"
cat >/etc/systemd/system/foodsafe.service <<UNIT
[Unit]
Description=Food Safety Platform
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=${base_dir}/current
ExecStart=${docker_bin} compose --env-file .env -f compose.yaml up -d --pull never
ExecStop=${docker_bin} compose --env-file .env -f compose.yaml stop
TimeoutStartSec=0

[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable --now foodsafe.service
(cd "${base_dir}/current" && ./check.sh)

info 'installation completed'
printf '学校端：http://%s:4200\n监管端：http://%s:4300\n大屏：http://%s:5208\n' \
  "${server_ip}" "${server_ip}" "${server_ip}"
exit 0
__FOODSAFE_PAYLOAD_BELOW__
HEADER
}

apply_header
mkdir -p "$(dirname "${output}")"
payload_archive="${stage_dir}/payload.tar.gz"
tar -C "${stage_dir}" -czf "${payload_archive}" payload
cp "${header}" "${output}"
cat "${payload_archive}" >>"${output}"
chmod 700 "${output}"

if command -v sha256sum >/dev/null 2>&1; then
  (cd "$(dirname "${output}")" && sha256sum "$(basename "${output}")" >"$(basename "${output}").sha256")
else
  (cd "$(dirname "${output}")" && shasum -a 256 "$(basename "${output}")" >"$(basename "${output}").sha256")
fi
printf '[done] %s\n' "${output}"
