#!/usr/bin/env bash

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

ensure_app_accounts() {
    if ! getent group www >/dev/null 2>&1; then run groupadd --system www; fi
    if ! id www >/dev/null 2>&1; then run useradd --system --gid www --home-dir /nonexistent --shell /sbin/nologin www; fi
    ensure_dir /workspace/wwwroot 0750 www www
    ensure_dir /workspace/wwwroot/log 0750 www www
    ensure_dir /var/log/supervisor 0750 www www
    ensure_dir /var/log/nginx 0750 www www
    ensure_dir /run/lock/zhct 0750 www www
}

build_app_nginx() {
    if [[ -x /usr/local/nginx/sbin/nginx ]] && /usr/local/nginx/sbin/nginx -v 2>&1 | grep -Fq 'nginx/1.26.3'; then 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"
}

prepare_lnmp_patches() {
    local lnmp_root="$BUILD_ROOT/lnmp"
    [[ -d "$lnmp_root/src/patch" ]] && return
    run rm -rf "$lnmp_root"
    extract_archive "$(asset_path lnmp2.2-from-git-20260706.tar.gz)" "$lnmp_root"
}

build_php73() {
    if [[ -x /usr/local/php7.3/bin/php ]] && /usr/local/php7.3/bin/php -v | grep -Fq 'PHP 7.3.33'; then return; fi
    backup_file /usr/local/php7.3
    prepare_lnmp_patches
    run rm -rf "$BUILD_ROOT/php73"
    extract_archive "$(asset_path php-7.3.33.tar.bz2)" "$BUILD_ROOT/php73"
    run_shell "cd '$BUILD_ROOT/php73/php-7.3.33' && patch -N -p1 < '$BUILD_ROOT/lnmp/src/patch/php-7.3-openssl3.0.patch' && ./configure --prefix=/usr/local/php7.3 --with-config-file-path=/usr/local/php7.3/etc --enable-fpm --with-fpm-user=www --with-fpm-group=www --with-fpm-systemd --enable-mbstring --enable-bcmath --enable-opcache --enable-sockets --enable-pcntl --enable-intl --with-curl --with-openssl --with-zlib --with-zip --with-pdo-mysql=mysqlnd --with-mysqli=mysqlnd --with-gd --with-jpeg-dir --with-png-dir --with-freetype-dir && make -j\$(nproc) && make install"
}

build_php74() {
    if [[ -x /usr/local/php7.4/bin/php ]] && /usr/local/php7.4/bin/php -v | grep -Fq 'PHP 7.4.33'; then return; fi
    backup_file /usr/local/php7.4
    prepare_lnmp_patches
    run rm -rf "$BUILD_ROOT/php74"
    extract_archive "$(asset_path php-7.4.33.tar.bz2)" "$BUILD_ROOT/php74"
    run_shell "cd '$BUILD_ROOT/php74/php-7.4.33' && patch -N -p1 < '$BUILD_ROOT/lnmp/src/patch/php-7.4-openssl3.0.patch' && ./configure --prefix=/usr/local/php7.4 --with-config-file-path=/usr/local/php7.4/etc --enable-fpm --with-fpm-user=www --with-fpm-group=www --with-fpm-systemd --enable-mbstring --enable-bcmath --enable-opcache --enable-sockets --enable-pcntl --enable-intl --with-curl --with-openssl --with-zlib --with-zip --with-pdo-mysql=mysqlnd --with-mysqli=mysqlnd --enable-gd --with-jpeg --with-freetype && make -j\$(nproc) && make install"
}

build_libmosquitto() {
    if ldconfig -p | grep -Fq libmosquitto.so.1; then return; fi
    backup_file /usr/local/lib/libmosquitto.so.1
    run rm -rf "$BUILD_ROOT/mosquitto"
    extract_archive "$(asset_path mosquitto-1.6.15.tar.gz)" "$BUILD_ROOT/mosquitto"
    run_shell "cd '$BUILD_ROOT/mosquitto/mosquitto-1.6.15' && make -j\$(nproc) WITH_BROKER=no WITH_APPS=yes WITH_DOCS=no WITH_WEBSOCKETS=no && make install WITH_BROKER=no WITH_APPS=yes WITH_DOCS=no WITH_WEBSOCKETS=no && ldconfig"
}

build_redis_cli() {
    local prefix=/opt/redis-client/5.0.14
    [[ -x "$prefix/bin/redis-cli" ]] && return
    backup_file "$prefix"
    run rm -rf "$BUILD_ROOT/redis-cli"
    extract_archive "$(asset_path redis-5.0.14.tar.gz)" "$BUILD_ROOT/redis-cli"
    ensure_dir "$prefix/bin" 0755 root root
    run_shell "cd '$BUILD_ROOT/redis-cli/redis-5.0.14' && make -j\$(nproc) redis-cli && install -m 0755 src/redis-cli '$prefix/bin/redis-cli'"
}

build_php_extension() {
    local php_prefix=$1 extension=$2 archive=$3 expected_so=$4
    if [[ "$DRY_RUN" != "1" ]] && \
        "$php_prefix/bin/php" -m | grep -Fxiq "$extension"; then
        return
    fi
    local key
    key=$(basename "$php_prefix")
    run rm -rf "$BUILD_ROOT/$key-$extension"
    extract_archive "$(asset_path "$archive")" "$BUILD_ROOT/$key-$extension"
    local source_dir
    if [[ "$DRY_RUN" == "1" ]]; then
        local archive_root
        archive_root=$(tar -tf "$(asset_path "$archive")" | awk -F/ 'NF && !seen {print $1; seen=1}')
        require_value archive_root "$archive_root"
        source_dir="$BUILD_ROOT/$key-$extension/$archive_root"
    else
        source_dir=$(find "$BUILD_ROOT/$key-$extension" -mindepth 1 -maxdepth 1 -type d | head -n 1)
    fi
    require_value source_dir "$source_dir"
    local configure_flags
    case "$extension" in
        redis) configure_flags='--disable-redis-igbinary --disable-redis-lzf --disable-redis-zstd' ;;
        mosquitto) configure_flags='--with-mosquitto=/usr/local' ;;
        *) die "unsupported PHP extension: $extension" ;;
    esac
    run_shell "cd '$source_dir' && '$php_prefix/bin/phpize' && ./configure --with-php-config='$php_prefix/bin/php-config' $configure_flags && make -j\$(nproc) && make install"
    [[ "$DRY_RUN" == "1" ]] || "$php_prefix/bin/php" -d "extension=$expected_so" -m | grep -Fxiq "$extension"
}

install_supervisor() {
    if command -v supervisord >/dev/null 2>&1 && supervisord --version | grep -Fq '4.3.0'; then return; fi
    run python3 -m pip install --no-index --no-deps --require-hashes --find-links "$BUNDLE_ROOT/packages" -r "$ROLE_ROOT/templates/python/requirements-supervisor.txt"
}

install_mysql56_clients() {
    local prefix=/opt/mysql-client/5.6.51
    [[ -x "$prefix/bin/mysqldump" ]] && return
    backup_file "$prefix"
    run rm -rf "$BUILD_ROOT/mysql-client"
    extract_archive "$(asset_path mysql-5.6.51-linux-glibc2.12-x86_64.tar.gz)" "$BUILD_ROOT/mysql-client"
    ensure_dir "$prefix/bin" 0755 root root
    ensure_dir "$prefix/lib" 0755 root root
    ensure_dir "$prefix/share/charsets" 0755 root root
    run_shell "install -m 0755 '$BUILD_ROOT/mysql-client/mysql-5.6.51-linux-glibc2.12-x86_64/bin/'{mysql,mysqldump,mysqladmin} '$prefix/bin/' && rsync -a '$BUILD_ROOT/mysql-client/mysql-5.6.51-linux-glibc2.12-x86_64/lib/' '$prefix/lib/' && rsync -a '$BUILD_ROOT/mysql-client/mysql-5.6.51-linux-glibc2.12-x86_64/share/charsets/' '$prefix/share/charsets/'"
}

stage_app_templates() {
    ensure_dir "$TEMPLATE_ROOT" 0750 root root
    run rsync -a --delete "$ROLE_ROOT/templates/" "$TEMPLATE_ROOT/"
    ensure_dir /usr/local/nginx/conf/conf.d 0755 root root
    install_file "$ROLE_ROOT/templates/nginx/nginx.conf" /usr/local/nginx/conf/nginx.conf 0644 root root
    install_file "$ROLE_ROOT/templates/nginx/app.conf" /usr/local/nginx/conf/conf.d/app.conf 0644 root root
    install_file "$ROLE_ROOT/templates/php/php73.ini" /usr/local/php7.3/etc/php.ini 0644 root root
    install_file "$ROLE_ROOT/templates/php/php74.ini" /usr/local/php7.4/etc/php.ini 0644 root root
    install_file "$ROLE_ROOT/templates/php/php-fpm73.conf" /usr/local/php7.3/etc/php-fpm.conf 0644 root root
    install_file "$ROLE_ROOT/templates/php/php-fpm74.conf" /usr/local/php7.4/etc/php-fpm.conf 0644 root root
    install_file "$ROLE_ROOT/templates/supervisor/supervisord.conf" /etc/supervisord.conf 0644 root root
    for unit in nginx php-fpm73 php-fpm74 supervisor; do
        install_file "$ROLE_ROOT/templates/systemd/$unit.service" "/etc/systemd/system/$unit.service" 0644 root root
    done
    install_file "$ROLE_ROOT/templates/runtime/redis-runtime-check.sh" /usr/local/sbin/redis-runtime-check.sh 0750 root root
    install_file "$ROLE_ROOT/templates/runtime/mqtt-runtime-check.sh" /usr/local/sbin/mqtt-runtime-check.sh 0750 root root
    install_file "$ROLE_ROOT/templates/runtime/singleton-state-check.sh" /usr/local/sbin/singleton-state-check.sh 0750 root root
    install_file "$ROLE_ROOT/templates/runtime/app-runtime-control.sh" /usr/local/sbin/app-runtime-control.sh 0750 root root
    install_file "$ROLE_ROOT/templates/runtime/mysql-backup-wrapper.sh" /usr/local/sbin/mysql-backup-wrapper.sh 0750 root root
    install_file "$ROLE_ROOT/templates/runtime/apply-file-role-policy.sh" /usr/local/sbin/apply-file-role-policy.sh 0750 root root
    ensure_dir /opt/zhct-release/scripts 0750 root root
    install_file "$ROLE_ROOT/templates/release/release-packages.sha256" /opt/zhct-release/release-packages.sha256 0640 root root
    install_file "$ROLE_ROOT/templates/release/README.md" /opt/zhct-release/README.md 0640 root root
    for script in release-common deploy_zhct_sanquan deploy_aizhct_sanquan deploy_ai_store_sanquan; do
        install_file "$ROLE_ROOT/templates/release/scripts/$script.sh" "/opt/zhct-release/scripts/$script.sh" 0750 root root
    done
    run systemctl daemon-reload
    stop_disable_units "$UNITS_MANIFEST"
}

role_install() {
    if [[ "${ZHCT_STATIC_VALIDATE:-0}" == "1" ]]; then
        log 'STATIC: app install plan loaded'
        return
    fi
    install_offline_rpms
    ensure_dir "$BUILD_ROOT" 0750 root root
    ensure_app_accounts
    build_app_nginx
    build_php73
    build_php74
    build_libmosquitto
    build_redis_cli
    build_php_extension /usr/local/php7.3 redis redis-5.3.5.tgz redis.so
    build_php_extension /usr/local/php7.4 redis redis-5.3.5.tgz redis.so
    build_php_extension /usr/local/php7.3 mosquitto Mosquitto-0.4.0.tgz mosquitto.so
    build_php_extension /usr/local/php7.4 mosquitto Mosquitto-0.4.0.tgz mosquitto.so
    install_supervisor
    install_mysql56_clients
    stage_app_templates
}

role_verify() {
    if [[ "${ZHCT_STATIC_VALIDATE:-0}" == "1" ]]; then
        log 'STATIC: app role verification contract loaded'
        return
    fi
    /usr/local/nginx/sbin/nginx -v 2>&1 | grep -Fq 'nginx/1.26.3'
    /usr/local/php7.3/bin/php -v | grep -Fq 'PHP 7.3.33'
    /usr/local/php7.4/bin/php -v | grep -Fq 'PHP 7.4.33'
    /usr/local/nginx/sbin/nginx -t
    /usr/local/php7.3/sbin/php-fpm -tt --fpm-config /usr/local/php7.3/etc/php-fpm.conf
    /usr/local/php7.4/sbin/php-fpm -tt --fpm-config /usr/local/php7.4/etc/php-fpm.conf
    for php in /usr/local/php7.3/bin/php /usr/local/php7.4/bin/php; do
        "$php" -m | grep -Fxiq redis
        "$php" -m | grep -Fxiq mosquitto
    done
    supervisord --version | grep -Fq '4.3.0'
    [[ -x /opt/mysql-client/5.6.51/bin/mysqldump ]]
    /opt/redis-client/5.0.14/bin/redis-cli --version | grep -Fq '5.0.14'
    mosquitto_pub --help 2>&1 | grep -Fq 'mosquitto_pub version 1.6.15'
    mosquitto_sub --help 2>&1 | grep -Fq 'mosquitto_sub version 1.6.15'
    verify_template_units_inactive "$UNITS_MANIFEST"
}

role_seal() {
    run rm -f /etc/zhct/node.env /etc/cron.d/zhct-sanquan
    run rm -rf /etc/zhct/secrets
    run find /var/run/supervisor /var/lib/supervisor -mindepth 1 -delete
    run find /var/log/supervisor /workspace/wwwroot/log -type f -delete
    run find /workspace/wwwroot -type d -name runtime -prune -exec rm -rf {} +
}

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/app.conf" /usr/local/nginx/conf/conf.d/app.conf 0644 root root
    install_file "$TEMPLATE_ROOT/php/php73.ini" /usr/local/php7.3/etc/php.ini 0644 root root
    install_file "$TEMPLATE_ROOT/php/php74.ini" /usr/local/php7.4/etc/php.ini 0644 root root
    install_file "$TEMPLATE_ROOT/php/php-fpm73.conf" /usr/local/php7.3/etc/php-fpm.conf 0644 root root
    install_file "$TEMPLATE_ROOT/php/php-fpm74.conf" /usr/local/php7.4/etc/php-fpm.conf 0644 root root
    install_file "$node_template/supervisor.conf" /etc/supervisor/conf.d/sanquan.conf 0640 root root
    install_file "$node_template/crontab" /etc/cron.d/zhct-sanquan 0644 root root
    local file_policy=/usr/local/sbin/apply-file-role-policy.sh
    [[ "${ZHCT_STATIC_VALIDATE:-0}" == "1" ]] && file_policy="$ROLE_ROOT/templates/runtime/apply-file-role-policy.sh"
    if [[ "$DRY_RUN" == "1" ]]; then
        "$file_policy" --node "$NODE_KEY" --dry-run
    else
        "$file_policy" --node "$NODE_KEY"
    fi
    run systemctl daemon-reload
    stop_disable_units "$UNITS_MANIFEST"
}

role_activate() {
    if [[ "$DRY_RUN" == "1" ]]; then
        log 'DRY-RUN: would validate Nginx, dual PHP-FPM and singleton policy; Supervisor/crond remain disabled until Q-263'
        return
    fi
    /usr/local/nginx/sbin/nginx -t
    /usr/local/php7.3/sbin/php-fpm -tt --fpm-config /usr/local/php7.3/etc/php-fpm.conf
    /usr/local/php7.4/sbin/php-fpm -tt --fpm-config /usr/local/php7.4/etc/php-fpm.conf
    /usr/local/sbin/singleton-state-check.sh --node "$NODE_KEY" --config /etc/supervisor/conf.d/sanquan.conf --cron /etc/cron.d/zhct-sanquan
}

role_rollback() {
    stop_disable_units "$UNITS_MANIFEST"
}
