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

APP_SOURCE=${APP_SOURCE:-/opt/app}
APP_TARGET=${APP_TARGET:-/var/www/html}
APP_USER=${APP_USER:-www-data}
APP_GROUP=${APP_GROUP:-www-data}
SKIP_CODE_SYNC=${SKIP_CODE_SYNC:-0}
DB_WAIT_TIMEOUT=${DB_WAIT_TIMEOUT:-60}
REDIS_WAIT_TIMEOUT=${REDIS_WAIT_TIMEOUT:-60}

sync_code() {
    if [[ "$SKIP_CODE_SYNC" == "1" ]]; then
        return
    fi

    if [[ ! -d "$APP_TARGET" ]]; then
        mkdir -p "$APP_TARGET"
    fi

    rsync -a --delete --omit-dir-times --no-perms --no-owner --no-group \
        --exclude="storage/**" \
        --exclude="storage/logs" \
        --exclude="storage/framework/sessions" \
        "$APP_SOURCE"/ "$APP_TARGET"/ || true

    chown -R "$APP_USER:$APP_GROUP" "$APP_TARGET"
}

ensure_helper_scripts() {
    if compgen -G "$APP_TARGET/scripts/*.sh" > /dev/null; then
        chmod +x "$APP_TARGET"/scripts/*.sh || true
    fi
}

prepare_storage() {
    cd "$APP_TARGET"

    if [[ ! -h public/storage ]]; then
        php artisan storage:link >/dev/null 2>&1 || true
    fi

    if [[ -n "${PENDING_MIGRATIONS:-}" ]]; then
        php artisan migrate --force >/dev/null 2>&1 || true
    fi
}
refresh_config_cache() {
    cd "$APP_TARGET"

    php artisan config:clear >/dev/null 2>&1 || true
    php artisan config:cache >/dev/null 2>&1 || true
    php artisan route:clear >/dev/null 2>&1 || true
    php artisan view:clear >/dev/null 2>&1 || true
}

ensure_help_cache() {
    cd "$APP_TARGET"

    if [[ "${HELP_SYNC_ON_BOOT:-auto}" == "0" ]]; then
        return
    fi

    if [[ "${HELP_SYNC_ON_BOOT:-auto}" == "1" ]]; then
        php artisan help:sync >/dev/null 2>&1 || true
        return
    fi

    if ! compgen -G "$APP_TARGET/storage/app/help/*/*/articles.json" > /dev/null; then
        php artisan help:sync >/dev/null 2>&1 || true
    fi
}

wait_for_service() {
    local name="$1" host="$2" port="$3" timeout="$4"
    local start
    start=$(date +%s)

    echo "[entrypoint] Waiting for ${name} at ${host}:${port} (timeout ${timeout}s)..."

    while true; do
        if exec 3<>"/dev/tcp/${host}/${port}" 2>/dev/null; then
            exec 3>&- 3<&-
            echo "[entrypoint] ${name} is available."
            break
        fi

        if (( $(date +%s) - start >= timeout )); then
            echo "[entrypoint] Timeout while waiting for ${name}." >&2
            exit 1
        fi

        sleep 2
    done
}

wait_for_dependencies() {
    local should_wait_db="false"

    case "${DB_CONNECTION:-sqlite}" in
        mysql|mariadb)
            should_wait_db="true"
            DB_HOST=${DB_HOST:-mysql}
            DB_PORT=${DB_PORT:-3306}
            ;;
        pgsql)
            should_wait_db="true"
            DB_HOST=${DB_HOST:-postgres}
            DB_PORT=${DB_PORT:-5432}
            ;;
    esac

    if [[ "${WAIT_FOR_DB:-$should_wait_db}" == "true" && "$should_wait_db" == "true" ]]; then
        wait_for_service "database" "$DB_HOST" "$DB_PORT" "$DB_WAIT_TIMEOUT"
    fi

    local should_wait_redis="false"
    if [[ "${QUEUE_CONNECTION:-}" == redis* ]]; then
        should_wait_redis="true"
    fi
    if [[ "${CACHE_DRIVER:-}" == redis ]]; then
        should_wait_redis="true"
    fi
    if [[ "${SESSION_DRIVER:-}" == redis ]]; then
        should_wait_redis="true"
    fi
    if [[ "${FORCE_WAIT_FOR_REDIS:-false}" == "true" ]]; then
        should_wait_redis="true"
    fi

    if [[ "${WAIT_FOR_REDIS:-$should_wait_redis}" == "true" && "$should_wait_redis" == "true" ]]; then
        wait_for_service "redis" "${REDIS_HOST:-redis}" "${REDIS_PORT:-6379}" "$REDIS_WAIT_TIMEOUT"
    fi
}

sync_code
ensure_helper_scripts
prepare_storage
refresh_config_cache
wait_for_dependencies
ensure_help_cache

cd "$APP_TARGET"
exec "$@"
