#!/usr/bin/env bash

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

ensure_redis_account() {
    if ! getent group redis >/dev/null 2>&1; then run groupadd --system redis; fi
    if ! id redis >/dev/null 2>&1; then run useradd --system --gid redis --home-dir /nonexistent --shell /sbin/nologin redis; fi
}

build_redis_component() {
    local version=$1 archive=$2
    local prefix="/opt/redis/$version"
    if [[ -x "$prefix/bin/redis-server" ]] && "$prefix/bin/redis-server" --version | grep -Fq "v=$version"; then return; fi
    backup_file "$prefix"
    run rm -rf "$BUILD_ROOT/$version"
    extract_archive "$(asset_path "$archive")" "$BUILD_ROOT/$version"
    run_shell "cd '$BUILD_ROOT/$version/redis-$version' && make -j\$(nproc) && make test && make install PREFIX='$prefix'"
}

stage_redis_templates() {
    ensure_dir /etc/redis 0750 root redis
    ensure_dir "$TEMPLATE_ROOT" 0750 root root
    run rsync -a --delete "$ROLE_ROOT/templates/" "$TEMPLATE_ROOT/"
    for unit in redis5 redis7 sentinel5 sentinel7; do
        install_file "$ROLE_ROOT/templates/systemd/$unit.service" "/etc/systemd/system/$unit.service" 0644 root root
    done
    run systemctl daemon-reload
    stop_disable_units "$UNITS_MANIFEST"
}

role_install() {
    if [[ "${ZHCT_STATIC_VALIDATE:-0}" == "1" ]]; then
        log 'STATIC: redis install plan loaded'
        return
    fi
    install_offline_rpms
    ensure_dir "$BUILD_ROOT" 0750 root root
    ensure_redis_account
    build_redis_component 5.0.14 redis-5.0.14.tar.gz
    build_redis_component 7.2.14 redis-7.2.14.tar.gz
    for path in /data/redis5 /data/redis7 /var/log/redis5 /var/log/redis7 /var/lib/redis-sentinel5 /var/lib/redis-sentinel7 /var/log/redis-sentinel5 /var/log/redis-sentinel7; do
        ensure_dir "$path" 0750 redis redis
    done
    stage_redis_templates
}

role_verify() {
    if [[ "${ZHCT_STATIC_VALIDATE:-0}" == "1" ]]; then
        log 'STATIC: redis role verification contract loaded'
        return
    fi
    /opt/redis/5.0.14/bin/redis-server --version | grep -Fq 'v=5.0.14'
    /opt/redis/7.2.14/bin/redis-server --version | grep -Fq 'v=7.2.14'
    for path in /data/redis5 /data/redis7 /var/lib/redis-sentinel5 /var/lib/redis-sentinel7; do
        if find "$path" -mindepth 1 -print -quit | grep -q .; then
            die "template contains Redis or Sentinel state: $path"
        fi
    done
    verify_template_units_inactive "$UNITS_MANIFEST"
}

role_seal() {
    for path in /data/redis5 /data/redis7 /var/lib/redis-sentinel5 /var/lib/redis-sentinel7; do
        if find "$path" -mindepth 1 -print -quit | grep -q .; then
            die "refuse to seal template with runtime state: $path"
        fi
    done
    run rm -f /etc/zhct/node.env
    run rm -rf /etc/zhct/secrets
    run rm -f /etc/redis/redis5.conf /etc/redis/redis7.conf /etc/orchestrator.conf.json
    run rm -rf /var/lib/orchestrator/.raft /var/lib/orchestrator/raft /var/lib/orchestrator/orchestrator.db
    run find /var/log/redis5 /var/log/redis7 /var/log/redis-sentinel5 /var/log/redis-sentinel7 -type f -delete
}

role_post_clone() {
    local node_template="$TEMPLATE_ROOT/nodes/$NODE_KEY"
    require_dir "$node_template"
    ensure_dir /etc/redis 0750 root redis
    ensure_dir /var/lib/redis-sentinel5 0750 redis redis
    ensure_dir /var/lib/redis-sentinel7 0750 redis redis
    render_template "$node_template/redis5.conf" /etc/redis/redis5.conf 0640 root redis
    render_template "$node_template/redis7.conf" /etc/redis/redis7.conf 0640 root redis
    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
    render_template "$node_template/orchestrator.conf.json" /etc/orchestrator.conf.json 0600 root root
    run systemctl daemon-reload
    stop_disable_units "$UNITS_MANIFEST"
}

role_activate() {
    if [[ "$DRY_RUN" == "1" ]]; then
        log 'DRY-RUN: would inject Redis secrets, reject unresolved placeholders and activate node policy'
        return
    fi
    require_command python3
    materialize_secret /etc/redis/redis5.conf __REDIS5_PASSWORD__ /etc/zhct/secrets/redis5.password
    materialize_secret /etc/redis/redis7.conf __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
    for config in /etc/redis/redis5.conf /etc/redis/redis7.conf /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"
}
