#!/usr/bin/env bash
#
# onx-fail2ban-banned-list — Tüm jail'lerde aktif banlı IP'leri konsolide listele.
#
# Tercih: fail2ban SQLite DB (timeofban+bantime > şu an). Yoksa fail2ban-client status.
# Output: {"bans":[{jail,ip,country_code,banned_at,expires_at,failed_attempts}],"total":N}

set -euo pipefail

readonly DB="/var/lib/fail2ban/fail2ban.sqlite3"

bans_json="[]"

# Country lookup DEVRE DIŞI — ipdeny.com country CIDR data eksik/eski
# (Türkiye'nin yaygın Türk Telekom 176.240.x bile TR.txt'de yok).
# Performans: 22sn → <2sn. Future: MMDB binary database (mmdblookup) ile %100 doğru.
ip2cc() {
    echo ""
}

# ── Strategy 1: SQLite DB (en güvenilir) ──────────────────────────────────
# NOT: bantime=0 olan kayıtlar timeofban+bantime > now check'inde "expired"
# olur. fail2ban configde bantime varsa per-row override edilir; default 0
# olabilir. Bu yüzden bantime=0 olan kayıtları SON 24sa içindeyse aktif say.
if [[ -r "$DB" ]] && command -v sqlite3 &>/dev/null; then
    tmp="$(mktemp)"
    trap 'rm -f "$tmp"' EXIT

    # Aktif banlar — bantime>0 ise (timeofban+bantime > now), bantime=0 ise son 24sa
    sqlite3 -separator '|' "$DB" \
        "SELECT jail, ip,
                datetime(timeofban,'unixepoch') AS banned_at,
                datetime(timeofban + CASE WHEN bantime > 0 THEN bantime ELSE 3600 END, 'unixepoch') AS expires_at,
                COALESCE(json_array_length(data,'\$.matches'),0) AS attempts
         FROM bans
         WHERE (bantime > 0 AND timeofban + bantime > strftime('%s','now'))
            OR (bantime = 0 AND timeofban >= strftime('%s','now','-24 hours'))
         ORDER BY timeofban DESC
         LIMIT 100" 2>/dev/null > "$tmp" || true

    bans_json="["
    first=1
    while IFS='|' read -r jail ip banned_at expires_at attempts; do
        [[ -z "$ip" ]] && continue

        cc="$(ip2cc "$ip")"

        [[ $first -eq 0 ]] && bans_json+=","
        first=0
        bans_json+=$(jq -nc \
            --arg jail "$jail" --arg ip "$ip" --arg cc "$cc" \
            --arg banned_at "$banned_at" --arg expires_at "$expires_at" \
            --argjson attempts "${attempts:-0}" \
            '{jail:$jail,ip:$ip,country_code:$cc,banned_at:$banned_at,expires_at:$expires_at,failed_attempts:$attempts}')
    done < "$tmp"
    bans_json+="]"
fi

# ── Strategy 2: fail2ban-client status fallback ───────────────────────────
if [[ "$bans_json" == "[]" ]] && command -v fail2ban-client &>/dev/null; then
    jails_raw="$(fail2ban-client status 2>/dev/null | grep "Jail list" | cut -d: -f2 || echo "")"
    bans_json="["
    first=1

    IFS=',' read -ra jails_arr <<<"$jails_raw"
    for jail in "${jails_arr[@]}"; do
        jail="$(echo "$jail" | tr -d ' \t')"
        [[ -z "$jail" ]] && continue

        # FIX: tr -d ' \t' YANLIŞ — IP'leri birleştiriyor (3.129.187.38 + 3.132.26.232 → 3.129.187.383.132.26.232)
        # fail2ban-client output format: "Banned IP list:    ip1 ip2 ip3" (whitespace separator)
        # Strip leading/trailing whitespace only, split by spaces.
        ips_raw="$(fail2ban-client status "$jail" 2>/dev/null \
            | grep "Banned IP list" | cut -d: -f2 \
            | sed -E 's/^[[:space:]]+//;s/[[:space:]]+$//' || echo "")"
        [[ -z "$ips_raw" ]] && continue

        bantime=$(fail2ban-client get "$jail" bantime 2>/dev/null || echo 3600)
        banned_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
        expires_at="$(date -u -d "+${bantime} seconds" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || echo "$banned_at")"

        # SPLIT BY WHITESPACE — IFS=',' YANLIŞ (fail2ban space-separated kullanır)
        read -ra ip_arr <<<"$ips_raw"
        for ip in "${ip_arr[@]}"; do
            ip="$(echo "$ip" | tr -d ' \t,')"  # her IP'yi temizle (artık güvenli)
            [[ -z "$ip" ]] && continue

            # v3.66: Country lookup DEVRE DIŞI (Strategy 1 ile paritesi).
            # Eski grepcidr döngüsü her IP için ~250 country .txt dosyasını tarıyordu
            # (N_ip × 250 grepcidr fork) → çalışma 2-3 dk sürüyor, panel polling
            # orphan process'leri biriktirip LOAD PATLATIYORDU. cc boş bırak.
            # İleride: mmdblookup (tek binary DB) ile O(1) doğru lookup.
            cc=""

            [[ $first -eq 0 ]] && bans_json+=","
            first=0
            bans_json+=$(jq -nc \
                --arg jail "$jail" --arg ip "$ip" --arg cc "$cc" \
                --arg banned_at "$banned_at" --arg expires_at "$expires_at" \
                '{jail:$jail,ip:$ip,country_code:$cc,banned_at:$banned_at,expires_at:$expires_at,failed_attempts:0}')
        done
    done
    bans_json+="]"
fi

total=$(echo "$bans_json" | jq 'length')

jq -nc --argjson bans "$bans_json" --argjson total "$total" \
    '{ok:true,bans:$bans,total:$total}'
