#!/usr/bin/env bash
# =============================================================================
# onx-quota-apply — Apply XFS user quota to /home
#
# Purpose:
#   Sets soft and hard block quotas (and inode quotas) for a hosting account
#   using setquota. Hard limit is soft+10% to provide a grace buffer.
#
# Input (stdin JSON):
#   {
#     "username": "onx_xxxx",
#     "disk_mb":  2048,         -- soft disk limit in MiB
#     "inodes":   100000        -- soft inode limit (files)
#   }
#
# Output (stdout JSON):
#   {"username":..., "soft_mb":..., "hard_mb":..., "inodes_soft":..., "inodes_hard":..., "applied":true}
#
# Exit codes: 0=ok 1=invalid-input 2=preflight-fail 3=exec-fail 4=rolled-back 5=rollback-failed
#
# Sudoers entry needed:
#   apache ALL=(root) NOPASSWD: /usr/local/onoxsoft/bin/onx-quota-apply
#   Defaults!/usr/local/onoxsoft/bin/onx-quota-apply !requiretty
#   Defaults!/usr/local/onoxsoft/bin/onx-quota-apply log_output, log_input
#
# Deployed to: /usr/local/onoxsoft/bin/onx-quota-apply
# =============================================================================

set -euo pipefail

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

# ── Dependencies ──────────────────────────────────────────────────────────────
command -v jq       >/dev/null 2>&1 || { printf '{"error":"jq required"}\n' >&2; exit 2; }
command -v setquota >/dev/null 2>&1 || { printf '{"error":"setquota required"}\n' >&2; exit 2; }
require_root

# ── Read & parse stdin ────────────────────────────────────────────────────────
INPUT=$(cat)
onx_require_json "${INPUT}"

USERNAME=$(onx_json_get "${INPUT}" "username")
DISK_MB=$(onx_json_get  "${INPUT}" "disk_mb"  "2048")
INODES=$(onx_json_get   "${INPUT}" "inodes"   "100000")

# ── Input validation ──────────────────────────────────────────────────────────
onx_validate_username "${USERNAME}"
[[ "${DISK_MB}" =~ ^[0-9]+$ ]] || onx_die 1 "disk_mb must be a positive integer"
[[ "${INODES}"  =~ ^[0-9]+$ ]] || onx_die 1 "inodes must be a positive integer"
(( DISK_MB > 0 )) || onx_die 1 "disk_mb must be greater than 0"
(( INODES  > 0 )) || onx_die 1 "inodes must be greater than 0"

# ── Preflight ─────────────────────────────────────────────────────────────────
id "${USERNAME}" &>/dev/null || onx_die 2 "Linux user does not exist: ${USERNAME}"
mountpoint -q /home           || onx_die 2 "/home is not a mount point (XFS quota requires a separate mount)"

# ── Calculate quota values ────────────────────────────────────────────────────
# setquota uses 1 KiB blocks as the unit
SOFT_KB=$(( DISK_MB * 1024 ))
HARD_KB=$(( SOFT_KB * 110 / 100 ))          # 10% grace buffer
INODES_SOFT=${INODES}
INODES_HARD=$(( INODES * 110 / 100 ))

SOFT_MB=${DISK_MB}
HARD_MB=$(( HARD_KB / 1024 ))

# ── Apply quota ───────────────────────────────────────────────────────────────
setquota -u "${USERNAME}" \
    "${SOFT_KB}" "${HARD_KB}" \
    "${INODES_SOFT}" "${INODES_HARD}" \
    /home || onx_die 3 "setquota failed for ${USERNAME}"

onx_log "quota applied: ${USERNAME} soft=${SOFT_MB}MB hard=${HARD_MB}MB inodes_soft=${INODES_SOFT} inodes_hard=${INODES_HARD}"

# ── Output ────────────────────────────────────────────────────────────────────
onx_json_out \
    "username"    "${USERNAME}" \
    "soft_mb"     "${SOFT_MB}" \
    "hard_mb"     "${HARD_MB}" \
    "inodes_soft" "${INODES_SOFT}" \
    "inodes_hard" "${INODES_HARD}" \
    "applied"     "true"
