#!/usr/bin/env bash

role_preflight() {
    if [[ "${ZHCT_STATIC_VALIDATE:-0}" != "1" ]]; then
        require_command gcc
        require_command make
        require_command sha256sum
    fi
}

ensure_edge_accounts() {
    for account in www haproxy redis; do
        if ! getent group "$account" >/dev/null 2>&1; then run groupadd --system "$account"; fi
        if ! id "$account" >/dev/null 2>&1; then run useradd --system --gid "$account" --home-dir /nonexistent --shell /sbin/nologin "$account"; fi
    done
    ensure_dir /var/log/nginx 0750 www www
    ensure_dir /var/log/haproxy 0750 haproxy haproxy
    ensure_dir /var/log/redis-sentinel5 0750 redis redis
    ensure_dir /var/log/redis-sentinel7 0750 redis redis
    ensure_dir /var/lib/redis-sentinel5 0750 redis redis
    ensure_dir /var/lib/redis-sentinel7 0750 redis redis
}

build_nginx_component() {
    local binary=/usr/local/nginx/sbin/nginx
    if [[ -x "$binary" ]] && "$binary" -v 2>&1 | grep -Fq 'nginx/1.26.3'; then
        log 'UNCHANGED: nginx 1.26.3'
        return
    fi
    backup_file /usr/local/nginx
    run rm -rf "$BUILD_ROOT/nginx"
    extract_archive "$(asset_path nginx-1.26.3.tar.gz)" "$BUILD_ROOT/nginx"
    run_shell "cd '$BUILD_ROOT/nginx/nginx-1.26.3' && ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-threads && make -j\$(nproc) && make install"
}

build_keepalived_component() {
    if command -v keepalived >/dev/null 2>&1 && keepalived --version 2>&1 | grep -Fq 'v2.3.4'; then
        log 'UNCHANGED: keepalived 2.3.4'
        return
    fi
    backup_file /usr/local/sbin/keepalived
    run rm -rf "$BUILD_ROOT/keepalived"
    extract_archive "$(asset_path keepalived-2.3.4.tar.gz)" "$BUILD_ROOT/keepalived"
    run_shell "cd '$BUILD_ROOT/keepalived/keepalived-2.3.4' && ./configure --prefix=/usr/local --sysconfdir=/etc && make -j\$(nproc) && make install"
}

build_haproxy_component() {
    if [[ -x /usr/local/haproxy/sbin/haproxy ]] && /usr/local/haproxy/sbin/haproxy -v | grep -Fq '2.8.26'; then
        log 'UNCHANGED: haproxy 2.8.26'
        return
    fi
    backup_file /usr/local/haproxy
    run rm -rf "$BUILD_ROOT/haproxy"
    extract_archive "$(asset_path haproxy-2.8.26.tar.gz)" "$BUILD_ROOT/haproxy"
    run_shell "cd '$BUILD_ROOT/haproxy/haproxy-2.8.26' && make -j\$(nproc) TARGET=linux-glibc USE_OPENSSL=1 USE_PCRE2=1 USE_SYSTEMD=1 && make install PREFIX=/usr/local/haproxy"
}

build_sentinel_runtime() {
    local version=$1 archive=$2
    local prefix="/opt/redis/$version"
    if [[ -x "$prefix/bin/redis-sentinel" && -x "$prefix/bin/redis-cli" ]]; then
        log "UNCHANGED: Redis $version Sentinel runtime"
        return
    fi
    backup_file "$prefix"
    run rm -rf "$BUILD_ROOT/redis-$version"
    extract_archive "$(asset_path "$archive")" "$BUILD_ROOT/redis-$version"
    run_shell "cd '$BUILD_ROOT/redis-$version/redis-$version' && make -j\$(nproc) && install -d '$prefix/bin' && install -m 0755 src/redis-sentinel src/redis-cli '$prefix/bin/'"
}

stage_nginx_templates() {
    local source="$ROLE_ROOT/templates"
    local destination="$TEMPLATE_ROOT"
    ensure_dir "$destination" 0750 root root
    run rsync -a --delete "$source/" "$destination/"
    for unit in nginx keepalived haproxy sentinel5 sentinel7; do
        install_file "$source/systemd/$unit.service" "/etc/systemd/system/$unit.service" 0644 root root
    done
    for probe in check-front-vip check-mqtt-vip check-db-proxy-vip vip-control provision-edge-secrets; do
        install_file "$source/runtime/$probe.sh" "/usr/local/sbin/$probe.sh" 0750 root root
    done
    install_file "$source/sysctl/99-zhct-edge.conf" /etc/sysctl.d/99-zhct-edge.conf 0644 root root
    run sysctl -p /etc/sysctl.d/99-zhct-edge.conf
    run systemctl daemon-reload
    stop_disable_units "$UNITS_MANIFEST"
}

role_install() {
    install_offline_rpms
    ensure_dir "$BUILD_ROOT" 0750 root root
    ensure_edge_accounts
    build_nginx_component
    build_keepalived_component
    build_haproxy_component
    build_sentinel_runtime 5.0.14 redis-5.0.14.tar.gz
    build_sentinel_runtime 7.2.14 redis-7.2.14.tar.gz
    stage_nginx_templates
}

role_verify() {
    if [[ "${ZHCT_STATIC_VALIDATE:-0}" == "1" ]]; then
        log 'STATIC: nginx role verification contract loaded'
        return
    fi
    /usr/local/nginx/sbin/nginx -v 2>&1 | grep -Fq 'nginx/1.26.3'
    keepalived --version 2>&1 | grep -Fq 'v2.3.4'
    /usr/local/haproxy/sbin/haproxy -v | grep -Fq '2.8.26'
    /opt/redis/5.0.14/bin/redis-sentinel --version | grep -Fq 'v=5.0.14'
    /opt/redis/7.2.14/bin/redis-sentinel --version | grep -Fq 'v=7.2.14'
    verify_template_units_inactive "$UNITS_MANIFEST"
}

role_seal() {
    run rm -f /etc/zhct/node.env
    run rm -rf /etc/zhct/secrets
    run rm -f /etc/keepalived/keepalived.conf /etc/haproxy/haproxy.cfg /etc/orchestrator.conf.json
    run rm -rf /var/lib/orchestrator/.raft /var/lib/orchestrator/raft /var/lib/orchestrator/orchestrator.db
    run find /var/lib/redis-sentinel5 /var/lib/redis-sentinel7 -mindepth 1 -delete
    run find /var/log/zhct -type f -delete
}

role_post_clone() {
    local node_template="$TEMPLATE_ROOT/nodes/$NODE_KEY"
    require_dir "$node_template"
    render_template "$TEMPLATE_ROOT/nginx/nginx.conf" /usr/local/nginx/conf/nginx.conf 0644 root root
    render_template "$TEMPLATE_ROOT/nginx/front.conf" /usr/local/nginx/conf/conf.d/front.conf 0644 root root
    install_file "$TEMPLATE_ROOT/nginx/file-primary-routes.conf" /usr/local/nginx/conf/conf.d/file-primary-routes.conf 0644 root root
    render_template "$TEMPLATE_ROOT/haproxy/haproxy.cfg" /etc/haproxy/haproxy.cfg 0640 root root
    render_template "$node_template/keepalived.conf" /etc/keepalived/keepalived.conf 0600 root root
    render_template "$node_template/orchestrator.conf.json" /etc/orchestrator.conf.json 0600 root root
    render_template "$node_template/sentinel5.conf" /var/lib/redis-sentinel5/sentinel.conf 0600 redis redis
    render_template "$node_template/sentinel7.conf" /var/lib/redis-sentinel7/sentinel.conf 0600 redis redis
    run systemctl daemon-reload
    stop_disable_units "$UNITS_MANIFEST"
}

role_activate() {
    if [[ "$DRY_RUN" == "1" ]]; then
        log 'DRY-RUN: would inject edge secrets and validate configs; Keepalived remains disabled until Q-251'
        return
    fi
    require_command python3
    if [[ -r /etc/zhct/secrets/vrrp.auth ]] && [[ $(tr -d '\r\n' </etc/zhct/secrets/vrrp.auth | wc -c) -gt 8 ]]; then
        die 'Keepalived VRRP auth secret must be at most 8 characters'
    fi
    materialize_secret /etc/keepalived/keepalived.conf __VRRP_AUTH_PASS__ /etc/zhct/secrets/vrrp.auth
    materialize_secret /etc/haproxy/haproxy.cfg __REDIS5_PASSWORD__ /etc/zhct/secrets/redis5.password
    materialize_secret /etc/haproxy/haproxy.cfg __REDIS7_PASSWORD__ /etc/zhct/secrets/redis7.password
    materialize_secret /var/lib/redis-sentinel5/sentinel.conf __REDIS5_PASSWORD__ /etc/zhct/secrets/redis5.password
    materialize_secret /var/lib/redis-sentinel7/sentinel.conf __REDIS7_PASSWORD__ /etc/zhct/secrets/redis7.password
    materialize_secret /etc/orchestrator.conf.json __ORCHESTRATOR_TOPOLOGY_PASSWORD__ /etc/zhct/secrets/orchestrator-topology.password
    /usr/local/nginx/sbin/nginx -t
    /usr/local/haproxy/sbin/haproxy -c -f /etc/haproxy/haproxy.cfg
    keepalived --config-test --use-file=/etc/keepalived/keepalived.conf
    for config in /etc/keepalived/keepalived.conf /etc/haproxy/haproxy.cfg /var/lib/redis-sentinel5/sentinel.conf /var/lib/redis-sentinel7/sentinel.conf /etc/orchestrator.conf.json; do
        grep -Eq '__[A-Z0-9_]+__' "$config" && die "secret placeholder has not been injected: $config"
    done
    python3 -m json.tool /etc/orchestrator.conf.json >/dev/null
}

role_rollback() {
    stop_disable_units "$UNITS_MANIFEST"
}
