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

APP_DIR="/app"
DATA_ROOT="${EPICRISIS_DATA_ROOT:-/data}"
RUNTIME_ROOT="${EPICRISIS_RUNTIME_DIR:-${DATA_ROOT}/runtime}"
LOG_ROOT="${EPICRISIS_LOG_DIR:-${RUNTIME_ROOT}/logs}"
MONGO_DATA_DIR="${MONGO_DATA_DIR:-${DATA_ROOT}/mongodb}"
REDIS_DATA_DIR="${REDIS_DATA_DIR:-${DATA_ROOT}/redis}"
MONGO_APP_DATABASE="${MONGO_APP_DATABASE:-${DB_NAME:-Epicrisis}}"
MONGO_APP_USERNAME="${MONGO_APP_USERNAME:-epicrisis_app}"
MONGO_APP_PASSWORD="${MONGO_APP_PASSWORD:-}"
MONGO_APP_FORCE_RESET="${MONGO_APP_FORCE_RESET:-0}"
APP_HOST="${APP_HOST:-0.0.0.0}"
APP_PORT="${APP_PORT:-7000}"
CELERY_LOG_LEVEL="${CELERY_LOG_LEVEL:-INFO}"
CELERY_QUEUES="${CELERY_QUEUES:-batch_jobs,individual_uploads}"
CELERY_CONCURRENCY="${CELERY_CONCURRENCY:-2}"
EPICRISIS_AUTO_MIGRATE="${EPICRISIS_AUTO_MIGRATE:-1}"
EPICRISIS_AUTO_BOOTSTRAP_ADMIN="${EPICRISIS_AUTO_BOOTSTRAP_ADMIN:-1}"
EPICRISIS_AUTO_WARMUP="${EPICRISIS_AUTO_WARMUP:-1}"
EPICRISIS_WARMUP_RESOURCES="${EPICRISIS_WARMUP_RESOURCES:-cie10,cups,soat}"

if [[ -z "${MONGO_APP_PASSWORD}" ]]; then
    echo "MONGO_APP_PASSWORD es obligatorio para iniciar el contenedor all-in-one." >&2
    exit 1
fi

export DB_NAME="${DB_NAME:-${MONGO_APP_DATABASE}}"
export COLLECTION_NAME="${COLLECTION_NAME:-HistoriaClinica}"
export REDIS_URL="${REDIS_URL:-redis://127.0.0.1:6379/0}"
export BATCH_DISPATCHER="${BATCH_DISPATCHER:-celery}"
export APP_HOST
export APP_PORT
export CELERY_LOG_LEVEL
export CELERY_QUEUES
export CELERY_CONCURRENCY
export MONGO_APP_DATABASE
export MONGO_APP_USERNAME
export MONGO_APP_PASSWORD
export MONGO_APP_FORCE_RESET

if [[ -z "${MONGO_URI:-}" ]]; then
    export MONGO_URI="mongodb://${MONGO_APP_USERNAME}:${MONGO_APP_PASSWORD}@127.0.0.1:27017/${DB_NAME}?authSource=${MONGO_APP_DATABASE}"
fi

if [[ -z "${AUDIT_LOG_FILE:-}" ]]; then
    export AUDIT_LOG_FILE="logs/audit.jsonl"
fi

link_persistent_dir() {
    local source_path="$1"
    local target_path="$2"

    mkdir -p "$(dirname "${source_path}")" "${target_path}"
    if [[ -L "${source_path}" ]]; then
        return
    fi

    if [[ -d "${source_path}" ]]; then
        cp -a "${source_path}/." "${target_path}/" 2>/dev/null || true
        rm -rf "${source_path}"
    elif [[ -f "${source_path}" ]]; then
        cp -a "${source_path}" "${target_path}/" 2>/dev/null || true
        rm -f "${source_path}"
    fi

    ln -s "${target_path}" "${source_path}"
}

prepare_layout() {
    mkdir -p \
        "${MONGO_DATA_DIR}" \
        "${REDIS_DATA_DIR}" \
        "${LOG_ROOT}" \
        "${RUNTIME_ROOT}/_batch_uploads" \
        "${RUNTIME_ROOT}/_batch_extracted" \
        "${RUNTIME_ROOT}/_batch_reports" \
        "${RUNTIME_ROOT}/_individual_uploads" \
        "${RUNTIME_ROOT}/faiss_principal_jerarquico" \
        "${RUNTIME_ROOT}/cups_faiss" \
        "${RUNTIME_ROOT}/soat_faiss" \
        /var/log/epicrisis \
        /var/run/epicrisis

    link_persistent_dir "${APP_DIR}/logs" "${LOG_ROOT}"
    link_persistent_dir "${APP_DIR}/_batch_uploads" "${RUNTIME_ROOT}/_batch_uploads"
    link_persistent_dir "${APP_DIR}/_batch_extracted" "${RUNTIME_ROOT}/_batch_extracted"
    link_persistent_dir "${APP_DIR}/_batch_reports" "${RUNTIME_ROOT}/_batch_reports"
    link_persistent_dir "${APP_DIR}/_individual_uploads" "${RUNTIME_ROOT}/_individual_uploads"
    link_persistent_dir "${APP_DIR}/faiss_principal_jerarquico" "${RUNTIME_ROOT}/faiss_principal_jerarquico"
    link_persistent_dir "${APP_DIR}/cups_faiss" "${RUNTIME_ROOT}/cups_faiss"
    link_persistent_dir "${APP_DIR}/soat_faiss" "${RUNTIME_ROOT}/soat_faiss"

    touch "${LOG_ROOT}/audit.jsonl"
    chown -R epicrisis:epicrisis /data /var/log/epicrisis /var/run/epicrisis
}

wait_for_mongo() {
    local retries="${1:-30}"
    local sleep_seconds="${2:-2}"
    local attempt

    for ((attempt = 1; attempt <= retries; attempt += 1)); do
        if gosu epicrisis mongosh --quiet --host 127.0.0.1 --port 27017 --eval "db.adminCommand({ ping: 1 }).ok" >/dev/null 2>&1; then
            return 0
        fi
        sleep "${sleep_seconds}"
    done

    echo "MongoDB no respondió durante la inicialización." >&2
    return 1
}

start_temp_mongo() {
    gosu epicrisis mongod \
        --bind_ip 127.0.0.1 \
        --port 27017 \
        --dbpath "${MONGO_DATA_DIR}" \
        --fork \
        --logpath /var/log/epicrisis/mongod-init.log \
        --setParameter diagnosticDataCollectionEnabled=false
}

stop_temp_mongo() {
    gosu epicrisis mongod --dbpath "${MONGO_DATA_DIR}" --shutdown || true
}

ensure_mongo_user() {
    gosu epicrisis env \
        MONGO_APP_DATABASE="${MONGO_APP_DATABASE}" \
        MONGO_APP_USERNAME="${MONGO_APP_USERNAME}" \
        MONGO_APP_PASSWORD="${MONGO_APP_PASSWORD}" \
        MONGO_APP_FORCE_RESET="${MONGO_APP_FORCE_RESET}" \
        mongosh --quiet --host 127.0.0.1 --port 27017 --eval '
            const dbName = process.env.MONGO_APP_DATABASE;
            const username = process.env.MONGO_APP_USERNAME;
            const password = process.env.MONGO_APP_PASSWORD;
            const forceReset = ["1", "true", "yes", "on"].includes((process.env.MONGO_APP_FORCE_RESET || "").toLowerCase());
            const appDb = db.getSiblingDB(dbName);
            const roles = [
              { role: "readWrite", db: dbName },
              { role: "dbAdmin", db: dbName }
            ];
            const existing = appDb.getUser(username);
            if (!existing) {
              appDb.createUser({ user: username, pwd: password, roles });
              print(`Mongo user created: ${username}`);
            } else if (forceReset) {
              appDb.updateUser(username, { pwd: password, roles });
              print(`Mongo user password updated: ${username}`);
            } else {
              print(`Mongo user already exists: ${username}`);
            }
        '
}

run_runtime_bootstrap() {
    local bootstrap_mongo_uri="mongodb://127.0.0.1:27017/${DB_NAME}"

    if [[ "${EPICRISIS_AUTO_MIGRATE}" == "1" ]]; then
        gosu epicrisis env MONGO_URI="${bootstrap_mongo_uri}" /app/.venv/bin/python -m app.migrations.run
    fi

    if [[ "${EPICRISIS_AUTO_BOOTSTRAP_ADMIN}" == "1" ]]; then
        gosu epicrisis env MONGO_URI="${bootstrap_mongo_uri}" /app/.venv/bin/python -m app.scripts.bootstrap_admin
    fi

    if [[ "${EPICRISIS_AUTO_WARMUP}" == "1" ]]; then
        local args=()
        local resource
        local resources=()
        local warmup_output
        IFS=',' read -r -a resources <<<"${EPICRISIS_WARMUP_RESOURCES}"
        for resource in "${resources[@]}"; do
            resource="$(echo "${resource}" | xargs)"
            if [[ -n "${resource}" ]]; then
                args+=(--resource "${resource}")
            fi
        done
        if [[ "${#args[@]}" -gt 0 ]]; then
            if ! warmup_output="$(
                gosu epicrisis env MONGO_URI="${bootstrap_mongo_uri}" \
                    /app/.venv/bin/python -m app.scripts.warmup_resources "${args[@]}" 2>&1
            )"; then
                printf '%s\n' "${warmup_output}" >&2
                echo "El warmup de recursos terminó con error y se cancelará el arranque." >&2
                return 1
            fi

            printf '%s\n' "${warmup_output}"
            for resource in "${resources[@]}"; do
                resource="$(echo "${resource}" | xargs)"
                if [[ -n "${resource}" ]] && ! grep -Fqx -- "${resource}: ready" <<<"${warmup_output}"; then
                    echo "El recurso solicitado '${resource}' no terminó en estado ready; se cancelará el arranque." >&2
                    return 1
                fi
            done
        fi
    fi
}

main() {
    prepare_layout
    start_temp_mongo
    trap stop_temp_mongo EXIT
    wait_for_mongo
    ensure_mongo_user
    run_runtime_bootstrap
    stop_temp_mongo
    trap - EXIT

    exec gosu epicrisis /usr/bin/supervisord -c /etc/supervisor/conf.d/epicrisis.conf
}

main "$@"
