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


expected_version="$(cat /usr/share/ssl-nexus/VERSION 2>/dev/null || printf '1.11.5~checkpoint14')"
pending_file=/var/lib/ssl-nexus/.package-upgrade-pending
upgrade_dir=""
if [[ -s "$pending_file" ]]; then
  upgrade_dir=$(cat "$pending_file")
fi

rollback_upgrade() {
  local reason="$1"
  echo "SSL Nexus upgrade activation failed: $reason" >&2
  if [[ -z "$upgrade_dir" || ! -d "$upgrade_dir" ]]; then
    echo "No pre-upgrade snapshot is available; leaving the failed package installed for inspection." >&2
    return 1
  fi
  echo "Rolling back to the pre-upgrade checkpoint at $upgrade_dir" >&2
  systemctl stop ssl-nexus.service ssl-nexus-vendor-acl.path >/dev/null 2>&1 || true
  if [[ -f "$upgrade_dir/state.tar.gz" ]]; then
    /usr/bin/ssl-nexus-admin restore "$upgrade_dir/state.tar.gz" >/dev/null 2>&1 || {
      echo "State rollback failed; snapshot retained at $upgrade_dir" >&2
      return 1
    }
  fi
  if [[ -f "$upgrade_dir/runtime.tar.gz" ]]; then
    tar -C / -xzf "$upgrade_dir/runtime.tar.gz"
  fi
  systemctl daemon-reload >/dev/null 2>&1 || true
  nginx -t >/dev/null 2>&1 || true
  local was_active=no
  if [[ -f "$upgrade_dir/manifest.env" ]]; then
    # shellcheck disable=SC1090
    . "$upgrade_dir/manifest.env"
    was_active="${WAS_ACTIVE:-no}"
  fi
  if [[ "$was_active" == yes ]]; then
    systemctl restart ssl-nexus.service >/dev/null 2>&1 || true
    systemctl restart ssl-nexus-vendor-acl.path >/dev/null 2>&1 || true
  fi
  rm -f "$pending_file"
  echo "Previous SSL Nexus runtime and state restored. Snapshot retained at: $upgrade_dir" >&2
  return 0
}

# Current schema baseline. There are no legacy customer schemas to migrate yet;
# this marker exists so future upgrades have a controlled migration boundary.
supported_state_version=1
state_version_file=/var/lib/ssl-nexus/state-version
if [[ -s "$state_version_file" ]]; then
  current_state_version=$(tr -dc '0-9' < "$state_version_file")
  [[ -n "$current_state_version" ]] || current_state_version=0
  if (( current_state_version > supported_state_version )); then
    rollback_upgrade "state schema $current_state_version is newer than this package supports ($supported_state_version)" || true
    exit 1
  fi
fi

getent group ssl-nexus >/dev/null || groupadd --system ssl-nexus
getent passwd ssl-nexus >/dev/null || useradd --system --gid ssl-nexus --home-dir /var/lib/ssl-nexus --shell /usr/sbin/nologin ssl-nexus

# Testing/source installs before the SSL Nexus rename may still own port 8080.
# Stop them before starting the packaged service, otherwise an old process can
# satisfy the health check while the new service fails to bind.
for legacy_unit in cert-platform.service cert-platform-vendor-acl.path cert-platform-vendor-acl.service; do
  systemctl disable --now "$legacy_unit" >/dev/null 2>&1 || true
done
rm -f /etc/nginx/conf.d/cert-platform.conf

# Source/test installs place units in /etc/systemd/system, which overrides the
# package-owned copies under /usr/lib/systemd/system. Refresh any such copies so
# the package cannot keep launching a stale binary after an upgrade.
for unit in ssl-nexus.service ssl-nexus-vendor-acl.service ssl-nexus-vendor-acl.path; do
  if [[ -f "/etc/systemd/system/$unit" && -f "/usr/lib/systemd/system/$unit" ]]; then
    install -m 0644 "/usr/lib/systemd/system/$unit" "/etc/systemd/system/$unit"
  fi
done
install -d -m 0750 -o root -g ssl-nexus /etc/ssl-nexus
install -d -m 0700 -o ssl-nexus -g ssl-nexus /etc/ssl-nexus/secrets /var/lib/ssl-nexus /var/lib/ssl-nexus/certificates /var/lib/ssl-nexus/ansible
install -d -m 0770 -o root -g ssl-nexus /etc/ssl-nexus/plugins

install -d -m 0700 -o ssl-nexus -g ssl-nexus /etc/ssl-nexus/secrets/ansible
ssh_key=/etc/ssl-nexus/secrets/ansible/id_ed25519
if [[ ! -s "$ssh_key" || ! -s "${ssh_key}.pub" ]]; then
  rm -f "$ssh_key" "${ssh_key}.pub"
  ssh-keygen -q -t ed25519 -N '' -C 'ssl-nexus-automation' -f "$ssh_key"
fi
chown ssl-nexus:ssl-nexus "$ssh_key" "${ssh_key}.pub"
chmod 0600 "$ssh_key"; chmod 0644 "${ssh_key}.pub"

for secret in windows-pfx-password targets.key; do
  path="/etc/ssl-nexus/secrets/$secret"
  if [[ ! -s "$path" ]]; then
    if [[ "$secret" == targets.key ]]; then openssl rand 32 > "$path"; else openssl rand -base64 32 > "$path"; fi
  fi
  chown ssl-nexus:ssl-nexus "$path"; chmod 0600 "$path"
done

if [[ ! -f /var/lib/ssl-nexus/ansible/inventory.ini ]]; then printf '# Managed exclusively by SSL Nexus.\n' > /var/lib/ssl-nexus/ansible/inventory.ini; fi
[[ -f /var/lib/ssl-nexus/ansible/known_hosts ]] || install -m 0600 -o ssl-nexus -g ssl-nexus /dev/null /var/lib/ssl-nexus/ansible/known_hosts
chown ssl-nexus:ssl-nexus /var/lib/ssl-nexus/ansible/inventory.ini; chmod 0600 /var/lib/ssl-nexus/ansible/inventory.ini
[[ -f /var/lib/ssl-nexus/vendor-acl.desired ]] || install -m 0600 -o ssl-nexus -g ssl-nexus /dev/null /var/lib/ssl-nexus/vendor-acl.desired
if [[ ! -f /etc/nginx/ssl-nexus-vendor-acl.conf ]]; then printf 'deny all;\n' > /etc/nginx/ssl-nexus-vendor-acl.conf; fi; chmod 0644 /etc/nginx/ssl-nexus-vendor-acl.conf

if [[ ! -f /etc/ssl-nexus/config.json ]]; then install -m 0640 -o root -g ssl-nexus /usr/share/ssl-nexus/config.example.json /etc/ssl-nexus/config.json; fi
export SSL_NEXUS_PACKAGE_VERSION="$expected_version"
python3 - <<'PY'
import json, os, urllib.request
p='/etc/ssl-nexus/config.json'
with open(p) as f:d=json.load(f)
url=d.get('license',{}).get('server_url') or 'https://api.sslnexus.com'
if url.startswith('https://') and not d.get('license',{}).get('enabled'):
    try:
        req=urllib.request.Request(url.rstrip('/')+'/v1/public-key',headers={'Accept':'application/json','User-Agent':'SSL-Nexus-Package/' + os.environ.get('SSL_NEXUS_PACKAGE_VERSION','unknown')})
        with urllib.request.urlopen(req,timeout=15) as response: key=json.load(response)['public_key']
        d['license']['public_key']=key;d['license']['enabled']=True
    except Exception as exc:
        print('SSL Nexus licensing authority not reachable; Free tier remains available:',exc)
with open(p+'.tmp','w') as f:json.dump(d,f,indent=2);f.write('\n')
os.replace(p+'.tmp',p)
PY
chown ssl-nexus:ssl-nexus /etc/ssl-nexus/config.json; chmod 0600 /etc/ssl-nexus/config.json

# Production package activation is deterministic: never reach out to Galaxy or PyPI here.
# Distro/enterprise-managed Ansible collections and pywinrm are inspected by preflight.

configured=$(python3 - <<'PY'
import json
try:
    with open('/etc/ssl-nexus/config.json') as f:c=json.load(f)
    p=c.get('vendor_portal',{}).get('state_path','/var/lib/ssl-nexus/vendor-state.json')
    with open(p) as f:s=json.load(f)
    print('yes' if any(i.get('role')=='organisation_admin' and i.get('password_hash') for i in s.get('identities',[])) else 'no')
except Exception: print('no')
PY
)
bootstrap=/etc/ssl-nexus/bootstrap.env
if [[ "$configured" == yes ]]; then
  rm -f "$bootstrap"
else
  regenerate=yes
  if [[ -s "$bootstrap" ]]; then
    # Keep an existing unexpired link across package repair/reinstall.
    expires=$(awk -F= '$1=="SSL_NEXUS_BOOTSTRAP_EXPIRES"{print substr($0,index($0,"=")+1)}' "$bootstrap" || true)
    if [[ -n "$expires" ]] && python3 - "$expires" <<'PY'
import sys,datetime
try:
 e=datetime.datetime.fromisoformat(sys.argv[1].replace('Z','+00:00'));sys.exit(0 if e>datetime.datetime.now(datetime.timezone.utc) else 1)
except Exception:sys.exit(1)
PY
    then regenerate=no; fi
  fi
  if [[ "$regenerate" == yes ]]; then
    token=$(openssl rand -hex 32)
    expires=$(python3 - <<'PY'
import datetime
print((datetime.datetime.now(datetime.timezone.utc)+datetime.timedelta(minutes=30)).isoformat(timespec='seconds').replace('+00:00','Z'))
PY
)
    printf 'SSL_NEXUS_BOOTSTRAP_TOKEN=%s\nSSL_NEXUS_BOOTSTRAP_EXPIRES=%s\n' "$token" "$expires" > "$bootstrap"
  fi
  chown root:ssl-nexus "$bootstrap"; chmod 0640 "$bootstrap"
fi

ip=$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++)if($i=="src"){print $(i+1);exit}}')
[[ -n "$ip" ]] || ip=$(hostname -I 2>/dev/null | awk '{print $1}')
[[ -n "$ip" ]] || ip=127.0.0.1
nginx_conf=/etc/nginx/conf.d/ssl-nexus.conf
preserved_nginx=/etc/ssl-nexus/nginx.conf.preserved
if [[ ! -f "$nginx_conf" ]]; then
  if [[ -s "$preserved_nginx" ]]; then
    install -m 0644 "$preserved_nginx" "$nginx_conf"
  else
    sed "s/__DOMAIN__/${ip}/g" /usr/share/ssl-nexus/client.nginx.conf > "$nginx_conf"
    chmod 0644 "$nginx_conf"
  fi
fi
if ! nginx -t >/dev/null 2>&1; then
  if [[ -s "$preserved_nginx" && "$nginx_conf" != "$preserved_nginx" ]]; then
    rm -f "$nginx_conf"
  fi
  rollback_upgrade "nginx configuration validation failed" || true
  exit 1
fi
systemctl daemon-reload
systemctl enable --now nginx ssl-nexus.service ssl-nexus-vendor-acl.path
systemctl restart ssl-nexus.service
healthy=no
for _ in {1..30}; do
  if curl -fsS http://127.0.0.1:8080/healthz >/dev/null 2>&1 && \
     curl -fsS http://127.0.0.1:8080/api/version 2>/dev/null | python3 -c 'import json,sys,os; sys.exit(0 if json.load(sys.stdin).get("version")==os.environ["SSL_NEXUS_PACKAGE_VERSION"] else 1)'; then
    healthy=yes
    break
  fi
  sleep 1
done
if [[ "$healthy" != yes ]]; then
  systemctl status ssl-nexus.service --no-pager >&2 || true
  rollback_upgrade "packaged service $expected_version did not become healthy" || true
  exit 1
fi
if ! /usr/bin/ssl-nexus-admin preflight >/var/lib/ssl-nexus/last-preflight.txt 2>&1; then
  cat /var/lib/ssl-nexus/last-preflight.txt >&2 || true
  rollback_upgrade "production preflight failed after package activation" || true
  exit 1
fi
chown ssl-nexus:ssl-nexus /var/lib/ssl-nexus/last-preflight.txt
chmod 0600 /var/lib/ssl-nexus/last-preflight.txt
/usr/libexec/ssl-nexus/sync-vendor-acl >/dev/null 2>&1 || { rollback_upgrade "vendor ACL synchronisation failed" || true; exit 1; }
systemctl restart ssl-nexus-vendor-acl.path >/dev/null 2>&1 || true
printf '%s\n' "$supported_state_version" > "$state_version_file"
chown ssl-nexus:ssl-nexus "$state_version_file"; chmod 0600 "$state_version_file"
printf '%s\n' "$expected_version" > /var/lib/ssl-nexus/package-version
chown ssl-nexus:ssl-nexus /var/lib/ssl-nexus/package-version; chmod 0600 /var/lib/ssl-nexus/package-version
rm -f "$pending_file"

printf '\nSSL Nexus installed.\n'
if [[ "$configured" != yes && -s "$bootstrap" ]]; then
  token=$(awk -F= '$1=="SSL_NEXUS_BOOTSTRAP_TOKEN"{print substr($0,index($0,"=")+1)}' "$bootstrap")
  expires=$(awk -F= '$1=="SSL_NEXUS_BOOTSTRAP_EXPIRES"{print substr($0,index($0,"=")+1)}' "$bootstrap")
  printf 'Open this short-lived setup URL to create the first administrator:\n\n  http://%s/setup/%s\n\nSetup link expires: %s\n' "$ip" "$token" "$expires"
else
  printf 'Open SSL Nexus:\n\n  http://%s/admin/\n' "$ip"
fi
printf '\n'
