#!/usr/bin/env bash
# =============================================================================
# onx-pdns-zone-create — PowerDNS zone + full record set provisioning (atomic)
# v87 Agent 4
# =============================================================================
#
# Üretimde tespit edilen sorun: bisaglik.com / leafport.com.tr gibi
# domain'ler için zone hiç oluşturulmamış (DomainAdded event listener pre-v84
# çağrılmıyordu) → intodns "did not respond". onx-zone-add sadece SOA + NS
# basıyor; bu script üst seviye atomic "tam zone" oluşturur:
#
#   - SOA              (1)
#   - NS (×2)          (2)  ns1, ns2
#   - A apex (@)       (1)
#   - A www            (1)
#   - MX mail.<dom>    (1) priority 10
#   - CNAME webmail    (1)
#   - CNAME mail       (1)
#   - CNAME autoconfig (1)
#   - CNAME autodiscover (1)
#   ────────────────
#   Toplam: 11 record
#
# Idempotent — re-run aynı zone için INSERT IGNORE + ON DUPLICATE KEY UPDATE
# pattern'leriyle duplicate üretmez. Domain zaten varsa serial bump'lar.
#
# Stdin JSON (gerekli/opsiyonel):
#   {
#     "domain":     "bisaglik.com",          // REQUIRED
#     "account":    "onx_bisaglik",          // OPSIYONEL (log/audit için)
#     "server_ip":  "149.102.145.172",       // REQUIRED (A/MX hedef)
#     "ns1":        "ns3.onoxsoft.com.tr",   // default: ns3.onoxsoft.com.tr
#     "ns2":        "ns4.onoxsoft.com.tr",   // default: ns4.onoxsoft.com.tr
#     "ttl":        14400,                   // default: 14400
#     "kind":       "Native"                 // default: Native (Master|Slave|Native)
#   }
#
# Stdout JSON:
#   {
#     "ok": true,
#     "domain": "bisaglik.com",
#     "domain_id": 42,
#     "kind": "Native",
#     "serial": "2026052701",
#     "created_records": ["SOA","NS×2","A (@)","A (www)","MX","CNAME×4"],
#     "record_count": 11,
#     "notified": true
#   }
#
# Exit codes:
#   0 = ok
#   1 = invalid input
#   2 = preflight fail (PDNS DB unreachable, no creds)
#   3 = execution fail (DB insert hatası)
# =============================================================================

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_lib/common.sh
source "${SCRIPT_DIR}/_lib/common.sh"

require_root
require_cmd mysql
require_cmd jq
onx_json_input

# ─── Input parse + validate ──────────────────────────────────────────────────
DOMAIN="$(onx_json_field domain)"
ACCOUNT="$(onx_json_field account '')"
SERVER_IP="$(onx_json_field server_ip)"
NS1="$(onx_json_field ns1 'ns3.onoxsoft.com.tr')"
NS2="$(onx_json_field ns2 'ns4.onoxsoft.com.tr')"
TTL="$(onx_json_field ttl '14400')"
KIND="$(onx_json_field kind 'Native')"

[[ -z "$DOMAIN" ]]    && onx_die 1 "domain zorunlu"
[[ -z "$SERVER_IP" ]] && onx_die 1 "server_ip zorunlu"
onx_validate_domain "$DOMAIN"
[[ "$KIND" =~ ^(Native|Master|Slave)$ ]] || onx_die 1 "Geçersiz kind: '${KIND}' (Native|Master|Slave)"
[[ "$TTL" =~ ^[0-9]+$ ]] || onx_die 1 "Geçersiz ttl: '${TTL}'"
# IP basit validation — IPv4 only (server_ip)
[[ "$SERVER_IP" =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]] || onx_die 1 "Geçersiz server_ip (IPv4 bekleniyor): '${SERVER_IP}'"

DOMAIN_LOWER="${DOMAIN,,}"
# SOA serial: YYYYMMDDnn (saniyenin %99'u, intra-day re-create için bump)
SERIAL="$(date +%Y%m%d)$(printf '%02d' "$(($(date +%S) % 99))")"
SOA_EMAIL="hostmaster.${DOMAIN_LOWER}"
SOA_CONTENT="${NS1} ${SOA_EMAIL} ${SERIAL} 7200 3600 1209600 3600"

onx_log "pdns-zone-create: domain=${DOMAIN_LOWER} account=${ACCOUNT} server_ip=${SERVER_IP} kind=${KIND}"

# ─── Preflight: PDNS DB erişimi ──────────────────────────────────────────────
# mysql_exec_stdin DB family auto-detect ile pdns creds kullanır.
# Test bağlantı:
PING_RESULT="$(mysql_exec "${ONX_PDNS_DB}" "SELECT 1;" 2>&1)"
if ! echo "$PING_RESULT" | grep -q '^1$'; then
    onx_die 2 "PowerDNS DB erişilemiyor (db=${ONX_PDNS_DB} host=${ONX_PDNS_DB_HOST}): ${PING_RESULT}"
fi

# domains tablosu var mı?
TBL_CHK="$(mysql_exec "${ONX_PDNS_DB}" "SHOW TABLES LIKE 'domains';" 2>&1 | tail -1)"
[[ "$TBL_CHK" == "domains" ]] || onx_die 2 "PowerDNS schema bozuk: 'domains' tablosu yok (db=${ONX_PDNS_DB})"

# ─── 1) Zone (domains) upsert ────────────────────────────────────────────────
# Eski zone varsa ID'sini al, yoksa insert.
DOMAIN_ID="$(mysql_exec "${ONX_PDNS_DB}" \
    "SELECT id FROM domains WHERE name='${DOMAIN_LOWER}' LIMIT 1;" 2>/dev/null | tail -1)"

if [[ -z "$DOMAIN_ID" || ! "$DOMAIN_ID" =~ ^[0-9]+$ ]]; then
    # Yeni zone — INSERT
    mysql_exec "${ONX_PDNS_DB}" \
        "INSERT INTO domains (name, type) VALUES ('${DOMAIN_LOWER}', '${KIND}');" \
        || onx_die 3 "domains INSERT başarısız: ${DOMAIN_LOWER}"

    DOMAIN_ID="$(mysql_exec "${ONX_PDNS_DB}" \
        "SELECT id FROM domains WHERE name='${DOMAIN_LOWER}' LIMIT 1;" 2>/dev/null | tail -1)"

    [[ -z "$DOMAIN_ID" || ! "$DOMAIN_ID" =~ ^[0-9]+$ ]] && \
        onx_die 3 "domain_id alınamadı (INSERT sonrası): ${DOMAIN_LOWER}"

    ZONE_CREATED=true
    onx_log "pdns-zone-create: yeni domain inserted id=${DOMAIN_ID}"
else
    ZONE_CREATED=false
    onx_log "pdns-zone-create: domain mevcut id=${DOMAIN_ID} (idempotent re-run)"
fi

# ─── 2) Records — atomic batch ───────────────────────────────────────────────
# 11 record'u tek transaction'da yaz. ON DUPLICATE KEY UPDATE ile re-run
# duplicate üretmez (records.unique_index = domain_id+name+type+content).
#
# NOT: PowerDNS schema'sında records tablosu için PRIMARY (id) AUTO_INCREMENT
# + unique index olarak (domain_id, name, type, md5sum(content)) kullanılır.
# Çoğu install'da ek olarak idx 'rec_name_index' (name+type) bulunur. Hard
# unique key olmayabilir → ON DUPLICATE KEY çalışmazsa DELETE-then-INSERT'a düş.
#
# Strateji: idempotent için ÖNCE bu domain'in TÜM autoritative record'larını
# temizle (SOA hariç tut — serial bump için ayrı UPDATE), SONRA yeniden insert.
# Bu, schema farklılıklarına dayanıklı.

# Eski non-SOA record'ları sil (zone'a aitse). DNSSEC kayıtları (DNSKEY/RRSIG)
# pdnsutil tarafından yönetilir — disabled veya başka key/auth alanları olabilir.
# Sadece bu script'in inject ettiği "core" record'ları temizle.
DELETE_SQL=$(cat <<DSQL
DELETE FROM records
WHERE domain_id=${DOMAIN_ID}
  AND type IN ('NS','A','AAAA','MX','CNAME','TXT')
  AND name IN (
    '${DOMAIN_LOWER}',
    'www.${DOMAIN_LOWER}',
    'mail.${DOMAIN_LOWER}',
    'webmail.${DOMAIN_LOWER}',
    'autoconfig.${DOMAIN_LOWER}',
    'autodiscover.${DOMAIN_LOWER}'
  );
DSQL
)
mysql_exec_stdin "${ONX_PDNS_DB}" <<< "$DELETE_SQL" 2>/dev/null || true

# Insert 11 core record. SOA SADECE zone yeniyse — varsa UPDATE ile serial bump.
# NOT: Heredoc terminator UPPERCASE_TAG yerine `INS` kullanırsak `INSERT` ile
# karışmasın diye 5+ char unique tag (`PDNS_REC_BATCH`). Bash heredoc word-prefix
# match yapıyor — `INS` `INSERT`'in başlangıcına denk geliyordu.
INSERT_SQL=$(cat <<'PDNS_REC_BATCH'
INSERT INTO records (domain_id, name, type, content, ttl, prio, disabled, auth)
VALUES
  -- NS records (x2)
  (__DID__, '__DOM__', 'NS', '__NS1__', __TTL__, 0, 0, 1),
  (__DID__, '__DOM__', 'NS', '__NS2__', __TTL__, 0, 0, 1),
  -- A apex
  (__DID__, '__DOM__', 'A', '__IP__', __TTL__, 0, 0, 1),
  -- A www
  (__DID__, 'www.__DOM__', 'A', '__IP__', __TTL__, 0, 0, 1),
  -- A mail (CNAME yasak çünkü MX hedefi — RFC 2181)
  (__DID__, 'mail.__DOM__', 'A', '__IP__', __TTL__, 0, 0, 1),
  -- MX → mail.<domain> prio 10
  (__DID__, '__DOM__', 'MX', 'mail.__DOM__', __TTL__, 10, 0, 1),
  -- CNAME webmail/autoconfig/autodiscover → apex
  (__DID__, 'webmail.__DOM__',      'CNAME', '__DOM__', __TTL__, 0, 0, 1),
  (__DID__, 'autoconfig.__DOM__',   'CNAME', '__DOM__', __TTL__, 0, 0, 1),
  (__DID__, 'autodiscover.__DOM__', 'CNAME', '__DOM__', __TTL__, 0, 0, 1);
PDNS_REC_BATCH
)
# Placeholder substitute — single-quote heredoc'ta expansion yasak, sed ile inject.
INSERT_SQL="${INSERT_SQL//__DID__/${DOMAIN_ID}}"
INSERT_SQL="${INSERT_SQL//__DOM__/${DOMAIN_LOWER}}"
INSERT_SQL="${INSERT_SQL//__IP__/${SERVER_IP}}"
INSERT_SQL="${INSERT_SQL//__NS1__/${NS1}}"
INSERT_SQL="${INSERT_SQL//__NS2__/${NS2}}"
INSERT_SQL="${INSERT_SQL//__TTL__/${TTL}}"

mysql_exec_stdin "${ONX_PDNS_DB}" <<< "$INSERT_SQL" \
    || onx_die 3 "records INSERT başarısız: ${DOMAIN_LOWER}"

# ─── 3) SOA upsert + serial bump ─────────────────────────────────────────────
SOA_EXISTS="$(mysql_exec "${ONX_PDNS_DB}" \
    "SELECT id FROM records WHERE domain_id=${DOMAIN_ID} AND type='SOA' LIMIT 1;" 2>/dev/null | tail -1)"

if [[ -z "$SOA_EXISTS" || ! "$SOA_EXISTS" =~ ^[0-9]+$ ]]; then
    # SOA yok — yarat
    mysql_exec_stdin "${ONX_PDNS_DB}" <<SOA
INSERT INTO records (domain_id, name, type, content, ttl, prio, disabled, auth)
VALUES (${DOMAIN_ID}, '${DOMAIN_LOWER}', 'SOA', '${SOA_CONTENT}', 3600, 0, 0, 1);
SOA
    [[ $? -ne 0 ]] && onx_die 3 "SOA INSERT başarısız"
else
    # SOA var — sadece content (serial dahil) güncelle. Mevcut primary_ns ve
    # admin_email'i KORU (admin değiştirmiş olabilir), sadece serial parçayı
    # bump et. Reuse pattern: onx-record-upsert v85.x reconstruct logic.
    SOA_CURRENT="$(mysql_exec "${ONX_PDNS_DB}" \
        "SELECT content FROM records WHERE id=${SOA_EXISTS};" 2>/dev/null | tail -1)"
    if [[ -n "$SOA_CURRENT" ]]; then
        EXIST_NS="$(echo "$SOA_CURRENT"    | awk '{print $1}')"
        EXIST_ADMIN="$(echo "$SOA_CURRENT" | awk '{print $2}')"
        [[ -z "$EXIST_NS" ]]    && EXIST_NS="$NS1"
        [[ -z "$EXIST_ADMIN" ]] && EXIST_ADMIN="$SOA_EMAIL"
        NEW_SOA="${EXIST_NS} ${EXIST_ADMIN} ${SERIAL} 7200 3600 1209600 3600"
    else
        NEW_SOA="$SOA_CONTENT"
    fi
    mysql_exec "${ONX_PDNS_DB}" \
        "UPDATE records SET content='${NEW_SOA}', ttl=3600, disabled=0 WHERE id=${SOA_EXISTS};" \
        || onx_die 3 "SOA UPDATE başarısız"
fi

# ─── 4) domains.notified_serial sync (PDNS Master/Slave için) ────────────────
# Native mode'da bu kullanılmaz ama Master mode için kritik (slave notify).
mysql_exec "${ONX_PDNS_DB}" \
    "UPDATE domains SET notified_serial=${SERIAL}, last_check=UNIX_TIMESTAMP() WHERE id=${DOMAIN_ID};" \
    2>/dev/null || true

# ─── 5) PDNS notify slaves (Master mode için; Native'de no-op) ───────────────
NOTIFIED=false
if command -v pdns_control >/dev/null 2>&1; then
    if pdns_control notify "${DOMAIN_LOWER}" >/dev/null 2>&1; then
        NOTIFIED=true
    fi
fi

# ─── 6) Output ───────────────────────────────────────────────────────────────
RECORD_COUNT="$(mysql_exec "${ONX_PDNS_DB}" \
    "SELECT COUNT(*) FROM records WHERE domain_id=${DOMAIN_ID};" 2>/dev/null | tail -1)"
RECORD_COUNT="${RECORD_COUNT:-0}"

jq -nc \
    --arg dom "${DOMAIN_LOWER}" \
    --arg kind "${KIND}" \
    --arg ser "${SERIAL}" \
    --argjson did "${DOMAIN_ID}" \
    --argjson rc "${RECORD_COUNT}" \
    --argjson zc "${ZONE_CREATED}" \
    --argjson nt "${NOTIFIED}" \
    '{
        ok: true,
        domain: $dom,
        domain_id: $did,
        kind: $kind,
        serial: $ser,
        zone_created: $zc,
        record_count: $rc,
        notified: $nt,
        created_records: ["SOA","NS×2","A (@)","A (www)","A (mail)","MX","CNAME×3 (webmail/autoconfig/autodiscover)"]
    }'

exit 0
