#!/bin/bash
# img-pipeline.sh — Hardened image processing pipeline
# Run by s3rv1c3agent (php-f8m user) on 558201
# Input: /var/www/uploads/tmp/[upload_id].*
# Output: /var/www/media/[hash]/[random].[ext]
set -euo pipefail
shopt -s inherit_errexit 2>/dev/null || true
IFS=$'\n\t'

readonly TMP="/var/www/uploads/tmp"
readonly MEDIA="/var/www/media"
readonly DB_SOCK="${DB_SOCK:-/var/lib/mysql/mysql.sock}"
readonly DB_NAME="${DB_NAME:-store}"
readonly DB_CNF="${DB_CNF:-/var/www/private/db.cnf}"
readonly VAULT_KEY="${VAULT_KEY:-$(cat /dev/shm/vault.key 2>/dev/null || printf '%s' '')}"
readonly IMG_KEY="${IMG_KEY:-$(cat /dev/shm/img_key.secret 2>/dev/null || printf '%s' "${VAULT_KEY}")}"
readonly LOCK_FILE="/run/se/.img_pipeline.lock"
readonly LOG_FILE="/var/log/s3rv1c3agent/img-pipeline.log"
readonly MAX_FILE_SIZE="${MAX_FILE_SIZE:-10485760}"  # 10MB
readonly MAX_DIMENSION="${MAX_DIMENSION:-5000}"

# ── Logging ────────────────────────────────────────────────────────────────
log_pipe() {
    local lvl="${1:-INFO}" msg="${2:-}"
    printf '%s [%s] [img-pipeline] %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "${lvl}" "${msg}" >> "${LOG_FILE}" 2>/dev/null || true
}

# ── File lock ──────────────────────────────────────────────────────────────
exec 400>"${LOCK_FILE}"
if ! flock -n 400; then
    log_pipe "ERR" "Another pipeline instance is running"
    exit 1
fi

# ── Validate environment ───────────────────────────────────────────────────
if [[ ! -d "${TMP}" ]]; then
    log_pipe "ERR" "TMP directory does not exist: ${TMP}"
    exit 1
fi

if [[ ! -d "${MEDIA}" ]]; then
    mkdir -p "${MEDIA}"
    chmod 755 "${MEDIA}"
fi

if [[ -z "${IMG_KEY}" ]]; then
    log_pipe "ERR" "No image encryption key available"
    exit 1
fi

# ── Process files ──────────────────────────────────────────────────────────
shopt -s nullglob
declare -a files=("${TMP}"/*)
shopt -u nullglob

if [[ "${#files[@]}" -eq 0 ]]; then
    exit 0
fi

for f in "${files[@]}"; do
    [[ -f "${f}" ]] || continue

    # Check file size
    local fsize
    fsize="$(stat -c '%s' "${f}" 2>/dev/null || printf '%s' '0')"
    if [[ "${fsize}" -gt "${MAX_FILE_SIZE}" ]]; then
        log_pipe "WARN" "File too large: ${f} (${fsize} bytes)"
        rm -f "${f}"
        continue
    fi

    ID="$(basename "${f}" | cut -d. -f1)"
    if [[ ! "${ID}" =~ ^[a-zA-Z0-9_-]+$ ]]; then
        log_pipe "WARN" "Invalid upload ID: ${ID}"
        rm -f "${f}"
        continue
    fi

    # Magic byte validation
    MAGIC="$(xxd -l 16 -p "${f}" 2>/dev/null || printf '%s' '')"
    EXT=""
    case "${MAGIC}" in
        89504e47*) EXT="png" ;;
        ffd8ff*)   EXT="jpg" ;;
        52494646*) EXT="webp" ;;
        47494638*) EXT="gif" ;;
        *)
            log_pipe "WARN" "Unknown magic bytes for ${f}: ${MAGIC}"
            rm -f "${f}"
            continue
            ;;
    esac

    # Create output directory
    OUT_HASH="$(openssl rand -hex 16)"
    OUT="${MEDIA}/${OUT_HASH}"
    mkdir -p "${OUT}"
    chmod 755 "${OUT}"

    # Process with ImageMagick — strip all metadata
    if ! convert "${f}" -strip -set units PixelsPerInch -density 72 \
        -resize "${MAX_DIMENSION}x${MAX_DIMENSION}>" \
        "${OUT}/${ID}-full.png" 2>/dev/null; then
        log_pipe "ERR" "ImageMagick conversion failed for ${f}"
        rm -rf "${OUT}"
        rm -f "${f}"
        continue
    fi

    # Generate variants
    convert "${f}" -strip -resize '800x800>' -quality 85 "${OUT}/${ID}-lg.webp" 2>/dev/null || true
    convert "${f}" -strip -resize '400x400>' -quality 85 "${OUT}/${ID}-md.webp" 2>/dev/null || true
    convert "${f}" -strip -resize '150x150>' -quality 85 "${OUT}/${ID}-sm.webp" 2>/dev/null || true

    # Remove original
    rm -f "${f}"

    # Hash output
    HASH="$(sha256sum "${OUT}/${ID}-lg.webp" 2>/dev/null | cut -d' ' -f1)" || HASH=""

    # Generate obfuscated public URL
    PUB="/media/$(openssl rand -hex 8)/$(openssl rand -hex 8).webp"

    # Encrypt private path
    ENC="$(# SEC: Use file-based password to avoid ps aux exposure
    _tmp_pass=$(mktemp); umask 077; printf '%s' "${IMG_KEY}" > "${_tmp_pass}"
    openssl enc -aes-256-cbc -a -salt -pass "file:${_tmp_pass}" <<< "${OUT}" 2>/dev/null || printf '%s' '')"; rm -f "${_tmp_pass}"

    # Build variants JSON
    VARIANTS="$(jq -n \
        --arg full "/media/full/${ID}.png" \
        --arg lg "/media/lg/${ID}-lg.webp" \
        --arg md "/media/md/${ID}-md.webp" \
        --arg sm "/media/sm/${ID}-sm.webp" \
        '{full:$full,lg:$lg,md:$md,sm:$sm}')"

    # Insert into database
    if [[ -f "${DB_CNF}" ]]; then
        mysql --defaults-file="${DB_CNF}" -D "${DB_NAME}" -e \
            "INSERT INTO product_images (upload_id,hash,public_url,private_path_enc,variants,created_at) VALUES ('${ID}','${HASH}','${PUB}','${ENC}','${VARIANTS}',UNIX_TIMESTAMP());" \
            2>/dev/null || log_pipe "ERR" "DB insert failed for ${ID}"
    else
        log_pipe "WARN" "DB config not found, skipping DB insert"
    fi

    log_pipe "INFO" "Processed ${ID}.${EXT} -> ${PUB}"
done

flock -u 400
