#!/usr/bin/env bash
# =============================================================================
# onx-mailbox-list — Enumerate virtual mailboxes (optionally scoped per-domain)
#
# Input (stdin JSON; both fields optional):
#   {
#     "domain":   "example.com",   -- optional; restrict to this domain
#     "with_du":  true             -- optional; default true. Set false to
#                                  --   skip the per-mailbox du() call
#                                  --   (~50x faster on large servers)
#   }
#
# Output (stdout JSON):
#   {
#     "total": 42,
#     "domain": "example.com" | null,
#     "mailboxes": [
#       {
#         "email":       "...",
#         "uid":         5000,
#         "gid":         5000,
#         "home":        "/var/vmail/.../",
#         "quota_bytes": 1073741824,
#         "quota_mb":    1024,
#         "enabled":     true,
#         "disk_bytes":  53216487
#       },
#       ...
#     ]
#   }
#
# Exit codes: 0=ok 1=invalid 2=preflight 3=exec
#
# Deployed to: /usr/local/onoxsoft/bin/onx-mailbox-list
# =============================================================================

set -euo pipefail

SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
# shellcheck source=_lib/common.sh
source "${SCRIPT_DIR}/_lib/common.sh"

require_root
if [[ "${MOCK_MODE}" != "1" ]]; then
    command -v mysql >/dev/null 2>&1 || onx_die 2 "mysql client not found"
fi

onx_json_input

DOMAIN_RAW=$(onx_json_field "domain" "")
WITH_DU=$(onx_json_get_bool "${INPUT}" "with_du" "true")

# Validate domain if supplied; empty means "all domains".
if [[ -n "${DOMAIN_RAW}" ]]; then
    onx_validate_domain "${DOMAIN_RAW}"
    DOMAIN="${DOMAIN_RAW}"
    WHERE_CLAUSE="WHERE email LIKE '%@${DOMAIN}'"
    DOMAIN_JSON_FIELD="\"${DOMAIN}\""
else
    DOMAIN=""
    WHERE_CLAUSE=""
    DOMAIN_JSON_FIELD="null"
fi

# ── Query ────────────────────────────────────────────────────────────────────
# Use tab separator (mysql --batch default) and read line-by-line. We pick
# only the columns we expose to the panel — never SELECT * (schema may carry
# extra metadata we don't want leaking out).
SQL="SELECT email, uid, gid, home, quota_bytes, enabled FROM dovecot_users ${WHERE_CLAUSE} ORDER BY email;"

ROWS=$(mysql_exec "${DOVECOT_DB_NAME}" "${SQL}") || onx_die 3 "dovecot_users SELECT failed"

# ── Build mailboxes JSON array ───────────────────────────────────────────────
TOTAL=0
MAILBOX_JSON_ITEMS=()

while IFS=$'\t' read -r EMAIL UID_VAL GID_VAL HOME_DIR QUOTA_BYTES ENABLED; do
    [[ -z "${EMAIL:-}" ]] && continue
    TOTAL=$(( TOTAL + 1 ))

    # Sanity-check the home path is under /var/vmail — refuse to du anything
    # outside that tree even if the DB row is corrupt.
    case "${HOME_DIR}" in
        /var/vmail|/var/vmail/*) : ;;
        *) HOME_DIR="" ;;
    esac

    DISK_BYTES=0
    if [[ "${WITH_DU}" == "true" ]] && [[ -n "${HOME_DIR}" ]] && [[ -d "${HOME_DIR}/Maildir" ]]; then
        # `du -sb` outputs "<bytes>\t<path>" — keep just the bytes.
        DISK_BYTES=$(du -sb "${HOME_DIR}/Maildir" 2>/dev/null | awk '{print $1}')
        DISK_BYTES="${DISK_BYTES:-0}"
    fi

    QUOTA_BYTES="${QUOTA_BYTES:-0}"
    [[ "${QUOTA_BYTES}" =~ ^-?[0-9]+$ ]] || QUOTA_BYTES=0

    if [[ "${QUOTA_BYTES}" -gt 0 ]]; then
        QUOTA_MB=$(( QUOTA_BYTES / 1024 / 1024 ))
    else
        QUOTA_MB=-1
    fi

    # ENABLED comes back as "0" or "1" from MariaDB — translate to JSON bool.
    if [[ "${ENABLED}" == "1" ]]; then
        ENABLED_JSON="true"
    else
        ENABLED_JSON="false"
    fi

    # Build a single-line JSON object via jq so strings are properly escaped.
    ITEM=$(jq -nc \
        --arg email "${EMAIL}" \
        --argjson uid "${UID_VAL:-0}" \
        --argjson gid "${GID_VAL:-0}" \
        --arg home "${HOME_DIR}" \
        --argjson qb "${QUOTA_BYTES}" \
        --argjson qm "${QUOTA_MB}" \
        --argjson db "${DISK_BYTES}" \
        --argjson en "${ENABLED_JSON}" \
        '{email:$email,uid:$uid,gid:$gid,home:$home,quota_bytes:$qb,quota_mb:$qm,disk_bytes:$db,enabled:$en}')
    MAILBOX_JSON_ITEMS+=("${ITEM}")
done <<< "${ROWS}"

# Assemble final JSON via jq -s (slurp the array) so we never hand-roll commas.
if [[ ${#MAILBOX_JSON_ITEMS[@]} -gt 0 ]]; then
    MAILBOX_JSON_ARRAY=$(printf '%s\n' "${MAILBOX_JSON_ITEMS[@]}" | jq -s '.')
else
    MAILBOX_JSON_ARRAY="[]"
fi

printf '{"total":%d,"domain":%s,"mailboxes":%s}\n' \
    "${TOTAL}" \
    "${DOMAIN_JSON_FIELD}" \
    "${MAILBOX_JSON_ARRAY}"
