#!/bin/bash
# apply-reseller-import.sh — Aplica el JSON del reseller al tenant ya provisionado.
#
# IMPORTANTE: este archivo VIVE en VPS1 como /root/scripts/apply-reseller-import.sh
# Acá en el repo está en scripts/ para auditoría + versionado. Cuando lo modifiques,
# desplegarlo a VPS1 con:
#   scp scripts/apply-reseller-import.sh vps1-claude:/root/scripts/apply-reseller-import.sh
#   ssh vps1-claude 'chmod +x /root/scripts/apply-reseller-import.sh && bash -n /root/scripts/apply-reseller-import.sh'
#
# Postmortem del refactor: docs/bewpro2.0/sprint-q2/hestiacp-import-migration.md
#
# Refactor 2026-05-14: soporte HestiaCP (nuevo) + cross-VPS (VPS1/VPS2/VPS3) +
# auto-discovery del location del tenant via `id <user>`. Reemplaza la versión
# cPanel-only que asumía path /home/{user}/public_html/git-files/{user}/ y
# operaba sólo en VPS1.
#
# Backup del original: /root/scripts/apply-reseller-import.sh.cPanel-bak-2026-05-14
#
# Uso:
#   apply-reseller-import.sh <RECORD_ID> <CPANEL_USER> <AIRTABLE_TOKEN> <AIRTABLE_BASE_ID>
#
# Flow:
#   1. Validar que el stash JSON existe en VPS1 (bewpro22)
#   2. Resolver Slug desde Airtable → arma DOMAIN={slug}.bewpro.com
#   3. Auto-discovery: dónde vive el user? (VPS1 local / VPS2 / VPS3)
#   4. SCP + chmod del JSON al tenant (HestiaCP path)
#   5. Clear de tablas correspondientes a las secciones del JSON
#   6. Ejecutar bewpro:seed adentro del tenant via su+ssh
#   7. PATCH Airtable Import_Status = Completed | Failed
#   8. Limpiar stash si todo OK
#
# Convención HestiaCP:
#   /home/{user}/web/{domain}/public_html/git-files/  ← clone del repo cd-system
#
# Convención cPanel (legacy):
#   /home/{user}/public_html/git-files/{user}/        ← ya no se usa para nuevos tenants

set -uo pipefail

RECORD_ID="${1:-}"
CPANEL_USER="${2:-}"
AIRTABLE_TOKEN="${3:-}"
AIRTABLE_BASE_ID="${4:-}"
PROJECTS_TABLE="${5:-tblzCgJZCbbt5j13Q}"
PREFIX="[reseller-import]"

# Routing VPS — mismas constantes que process-airtable2.sh
VPS2_IP="179.43.124.219"; VPS2_PORT="5633"
VPS3_IP="179.43.120.113"; VPS3_PORT="5651"
SSH_OPTS="-o StrictHostKeyChecking=no -o ConnectTimeout=10 -o ServerAliveInterval=30"

if [[ -z "$RECORD_ID" || -z "$CPANEL_USER" || -z "$AIRTABLE_TOKEN" || -z "$AIRTABLE_BASE_ID" ]]; then
  echo "${PREFIX} ERROR: faltan args. Uso: apply-reseller-import.sh <RECORD_ID> <CPANEL_USER> <TOKEN> <BASE_ID>" >&2
  exit 2
fi

STASH_DIR="/home/bewpro22/public_html/bewpro/storage/app/reseller-imports"
STASH_FILE="${STASH_DIR}/${RECORD_ID}.json"
TENANT_DB="${CPANEL_USER}_bp"

# ── 1. Verificar que el stash existe ──────────────────────────────────
if [[ ! -f "$STASH_FILE" ]]; then
  echo "${PREFIX} ERROR: stash JSON no encontrado en ${STASH_FILE}" >&2
  curl -s -X PATCH \
    -H "Authorization: Bearer ${AIRTABLE_TOKEN}" \
    -H "Content-Type: application/json" \
    --data '{"fields":{"Import_Status":"Failed","Import_Error":"Stash JSON missing on bewpro22"},"typecast":true}' \
    "https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/${PROJECTS_TABLE}/${RECORD_ID}" \
    > /dev/null 2>&1 || true
  exit 1
fi

# ── 2. Resolver Slug desde Airtable para construir el DOMAIN del path HestiaCP ─
RECORD_DATA=$(curl -s -H "Authorization: Bearer ${AIRTABLE_TOKEN}" \
    "https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/${PROJECTS_TABLE}/${RECORD_ID}")
SLUG=$(echo "$RECORD_DATA" | python3 -c "
import sys, json
try:
    d = json.load(sys.stdin)
    print((d.get('fields', {}).get('Slug') or '').strip(), end='')
except Exception:
    pass
" 2>/dev/null)

if [[ -z "$SLUG" ]]; then
  echo "${PREFIX} ERROR: no se pudo resolver Slug del record ${RECORD_ID}" >&2
  exit 1
fi

DOMAIN="${SLUG}.bewpro.com"
# Path candidatos por panel:
#   HestiaCP (VPS3): /home/{user}/web/{domain}/public_html/git-files/{user}/
#   cPanel   (VPS2): /home/{user}/public_html/git-files/{user}/
# Se resuelve dinámicamente más abajo según existencia del dir en el server destino.
TENANT_APP_DIR_HESTIA="/home/${CPANEL_USER}/web/${DOMAIN}/public_html/git-files/${CPANEL_USER}"
TENANT_APP_DIR_CPANEL="/home/${CPANEL_USER}/public_html/git-files/${CPANEL_USER}"
TENANT_APP_DIR=""  # se setea tras detectar el VPS

# ── 3. Auto-discovery: ¿en qué VPS vive el user? ──────────────────────
# Probamos VPS1 (local) → VPS2 → VPS3. El primero que responda con `id` OK
# es donde está provisionado el tenant.
LOCATION=""
if id "$CPANEL_USER" &>/dev/null; then
  LOCATION="local"
elif ssh -p "$VPS2_PORT" $SSH_OPTS root@"$VPS2_IP" "id ${CPANEL_USER}" &>/dev/null; then
  LOCATION="vps2"
elif ssh -p "$VPS3_PORT" $SSH_OPTS root@"$VPS3_IP" "id ${CPANEL_USER}" &>/dev/null; then
  LOCATION="vps3"
fi

if [[ -z "$LOCATION" ]]; then
  echo "${PREFIX} ERROR: user ${CPANEL_USER} no encontrado en VPS1/VPS2/VPS3" >&2
  curl -s -X PATCH \
    -H "Authorization: Bearer ${AIRTABLE_TOKEN}" \
    -H "Content-Type: application/json" \
    --data "{\"fields\":{\"Import_Status\":\"Failed\",\"Import_Error\":\"User ${CPANEL_USER} not found on VPS1/VPS2/VPS3\"},\"typecast\":true}" \
    "https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/${PROJECTS_TABLE}/${RECORD_ID}" \
    > /dev/null 2>&1 || true
  exit 1
fi

echo "${PREFIX} Tenant location: ${LOCATION} | user=${CPANEL_USER} | domain=${DOMAIN}"

# ── Helpers: ejecutar comandos local o remoto, copiar archivos ────────
remote_exec() {
  local cmd="$1"
  case "$LOCATION" in
    local) bash -c "$cmd" ;;
    vps2)  ssh -p "$VPS2_PORT" $SSH_OPTS root@"$VPS2_IP" "$cmd" ;;
    vps3)  ssh -p "$VPS3_PORT" $SSH_OPTS root@"$VPS3_IP" "$cmd" ;;
  esac
}

remote_copy() {
  local src="$1"; local dst="$2"
  # -O fuerza protocolo SCP legacy en lugar de SFTP — necesario porque algunos
  # servidores remotos (HestiaCP en VPS3, p.ej.) no tienen sftp-server instalado
  # y OpenSSH >=9 usa SFTP por default, causando "Connection closed" / exit 127.
  case "$LOCATION" in
    local) cp "$src" "$dst" ;;
    vps2)  scp -O -P "$VPS2_PORT" $SSH_OPTS "$src" root@"$VPS2_IP":"$dst" ;;
    vps3)  scp -O -P "$VPS3_PORT" $SSH_OPTS "$src" root@"$VPS3_IP":"$dst" ;;
  esac
}

# ── 4. Resolver TENANT_APP_DIR según panel del VPS (HestiaCP vs cPanel) ─
# Probamos primero HestiaCP (VPS3 usa esto). Si no existe, cPanel clásico (VPS2).
if remote_exec "[[ -d '${TENANT_APP_DIR_HESTIA}' ]]"; then
  TENANT_APP_DIR="${TENANT_APP_DIR_HESTIA}"
  PANEL_TYPE="hestiacp"
elif remote_exec "[[ -d '${TENANT_APP_DIR_CPANEL}' ]]"; then
  TENANT_APP_DIR="${TENANT_APP_DIR_CPANEL}"
  PANEL_TYPE="cpanel"
else
  echo "${PREFIX} ERROR: ningún TENANT_APP_DIR existe en ${LOCATION}" >&2
  echo "${PREFIX}   HestiaCP probado: ${TENANT_APP_DIR_HESTIA}" >&2
  echo "${PREFIX}   cPanel probado:   ${TENANT_APP_DIR_CPANEL}" >&2
  curl -s -X PATCH \
    -H "Authorization: Bearer ${AIRTABLE_TOKEN}" \
    -H "Content-Type: application/json" \
    --data "{\"fields\":{\"Import_Status\":\"Failed\",\"Import_Error\":\"TENANT_APP_DIR missing on ${LOCATION} (tried HestiaCP + cPanel paths)\"},\"typecast\":true}" \
    "https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/${PROJECTS_TABLE}/${RECORD_ID}" \
    > /dev/null 2>&1 || true
  exit 1
fi

echo "${PREFIX} Panel: ${PANEL_TYPE} | path: ${TENANT_APP_DIR}"
TENANT_JSON_PATH="${TENANT_APP_DIR}/storage/app/incoming-import.json"

# ── 4.5 Normalizar JSON del hunter al shape canónico ─────────────────
# Hunter v2 usa keys distintas al shape que espera bewpro:seed.
# Mapeo (no destructivo — solo agrega aliases sin remover originales):
#   services[].name              → services[].title
#   services[].service_category_slug → services[].category_slug
#   services[].order             → services[].sort_order
# Mismo para projects[], blog[], etc. cuando aplique.
NORMALIZED_FILE="${STASH_FILE}.normalized"
python3 - "$STASH_FILE" "$NORMALIZED_FILE" <<'PYEOF'
import json, sys
src, dst = sys.argv[1], sys.argv[2]
d = json.load(open(src))

def normalize_section(items, key_map):
    if not isinstance(items, list): return
    for item in items:
        if not isinstance(item, dict): continue
        for old, new in key_map.items():
            if old in item and new not in item:
                item[new] = item[old]

# Hunter v2 schema → canonical schema mappings
normalize_section(d.get('services', []), {
    'name': 'title',
    'service_category_slug': 'category_slug',
    'order': 'sort_order',
})
normalize_section(d.get('projects', []), {
    'name': 'title',
    'project_category_slug': 'category_slug',
    'order': 'sort_order',
})
normalize_section(d.get('blog', []), {
    'name': 'title',
    'blog_category_slug': 'category_slug',
    'order': 'sort_order',
})
normalize_section(d.get('team', []), {
    'order': 'sort_order',
})

# Categories siguen el mismo patrón
for cat_section in ['service_categories', 'project_categories', 'blog_categories',
                    'team_categories', 'faq_categories', 'reference_categories',
                    'gallery_categories', 'menu_categories', 'testimonial_categories']:
    normalize_section(d.get(cat_section, []), {
        'name': 'title',
        'order': 'sort_order',
    })

with open(dst, 'w') as f:
    json.dump(d, f, ensure_ascii=False, indent=2)
PYEOF

if [[ ! -f "$NORMALIZED_FILE" ]]; then
  echo "${PREFIX} ERROR: normalize falló (no se creó ${NORMALIZED_FILE})" >&2
  NORMALIZED_FILE="$STASH_FILE"  # fallback al original
fi
echo "${PREFIX} JSON normalizado: services/projects/blog/categories (name→title, order→sort_order)"

# ── 5. Copiar JSON al tenant + permisos ───────────────────────────────
# Asegurar que storage/app existe ANTES del scp (puede no haberse creado aún)
remote_exec "mkdir -p '${TENANT_APP_DIR}/storage/app' && chown ${CPANEL_USER}:${CPANEL_USER} '${TENANT_APP_DIR}/storage/app'"

if ! remote_copy "$NORMALIZED_FILE" "$TENANT_JSON_PATH"; then
  echo "${PREFIX} ERROR: SCP del JSON falló a ${LOCATION}:${TENANT_JSON_PATH}" >&2
  curl -s -X PATCH \
    -H "Authorization: Bearer ${AIRTABLE_TOKEN}" \
    -H "Content-Type: application/json" \
    --data '{"fields":{"Import_Status":"Failed","Import_Error":"SCP failed"},"typecast":true}' \
    "https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/${PROJECTS_TABLE}/${RECORD_ID}" \
    > /dev/null 2>&1 || true
  exit 1
fi
remote_exec "chown ${CPANEL_USER}:${CPANEL_USER} '${TENANT_JSON_PATH}' && chmod 640 '${TENANT_JSON_PATH}'"
echo "${PREFIX} JSON copiado a ${LOCATION}:${TENANT_JSON_PATH}"

# ── 6. Clear de tablas que el JSON va a reemplazar ────────────────────
# bewpro:seed solo append. Si el tenant ya tiene seed canónico del core,
# colisionan slugs únicos. Truncamos solo lo que el JSON va a reemplazar.
SECTIONS_PRESENT=$(python3 -c "
import json
d = json.load(open('$STASH_FILE'))
print(' '.join([k for k in d.keys() if not k.startswith('_')]))
" 2>/dev/null || echo "")

declare -A SECTION_TO_TABLES=(
  ['blog']='posts post_categories'
  ['faqs']='faqs faqs_categories'
  ['gallery']='gallery gallery_categories gallery_tags gallery_gallery_tag'
  ['menu']='menu_products menu_categories'
  ['testimonials']='testimonials testimonial_categories'
  ['services']='services service_categories'
  ['team']='team_members team_categories'
  ['references']='references reference_categories'
  ['projects']='projects project_categories'
)

TABLES_TO_TRUNCATE=""
for section in $SECTIONS_PRESENT; do
  if [[ -n "${SECTION_TO_TABLES[$section]:-}" ]]; then
    TABLES_TO_TRUNCATE="${TABLES_TO_TRUNCATE} ${SECTION_TO_TABLES[$section]}"
  fi
done

if [[ -n "$TABLES_TO_TRUNCATE" ]]; then
  echo "${PREFIX} Clearing tables (sections del JSON):$TABLES_TO_TRUNCATE"
  CLEAR_SQL="SET FOREIGN_KEY_CHECKS=0;"
  for tbl in $TABLES_TO_TRUNCATE; do
    CLEAR_SQL="${CLEAR_SQL} DELETE FROM \\\`${tbl}\\\`;"
  done
  CLEAR_SQL="${CLEAR_SQL} SET FOREIGN_KEY_CHECKS=1;"

  CLEAR_OUT=$(remote_exec "mysql ${TENANT_DB} -e \"${CLEAR_SQL}\"" 2>&1) || \
    echo "${PREFIX} WARN: clear parcial — output: ${CLEAR_OUT}"
fi

# ── 7. Ejecutar bewpro:seed dentro del tenant ─────────────────────────
# Usar `su -s /bin/bash` para bypassear "This account is currently not available"
# que aparece cuando el shell del user es nologin (HestiaCP lo deshabilita
# post-provisión por seguridad). El -s fuerza shell ignorando /etc/passwd.
echo "${PREFIX} Ejecutando bewpro:seed en ${LOCATION}:${CPANEL_USER}..."
SEED_CMD="su -s /bin/bash - ${CPANEL_USER} -c 'cd ${TENANT_APP_DIR} && php artisan bewpro:seed storage/app/incoming-import.json 2>&1'"
SEED_LOG=$(remote_exec "$SEED_CMD" 2>&1)
SEED_RC=$?

if [[ $SEED_RC -eq 0 ]] && echo "$SEED_LOG" | grep -q "Content seeded"; then
  RECORDS=$(echo "$SEED_LOG" | grep -oE "Content seeded: [0-9]+" | grep -oE "[0-9]+" | head -1)
  echo "${PREFIX} ✓ Content import OK — ${RECORDS:-?} records insertados"

  curl -s -X PATCH \
    -H "Authorization: Bearer ${AIRTABLE_TOKEN}" \
    -H "Content-Type: application/json" \
    --data '{"fields":{"Import_Status":"Completed"},"typecast":true}' \
    "https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/${PROJECTS_TABLE}/${RECORD_ID}" \
    > /dev/null 2>&1 || true

  rm -f "$STASH_FILE" 2>/dev/null || true
  rm -f "${STASH_FILE}.normalized" 2>/dev/null || true
  exit 0
else
  echo "${PREFIX} ✗ Content import FAILED (rc=${SEED_RC})" >&2
  echo "$SEED_LOG" | tail -15 >&2

  ERR_SUMMARY=$(echo "$SEED_LOG" | tail -3 | tr '\n' ' ' | sed 's/"/\\"/g' | cut -c1-300)
  curl -s -X PATCH \
    -H "Authorization: Bearer ${AIRTABLE_TOKEN}" \
    -H "Content-Type: application/json" \
    --data "{\"fields\":{\"Import_Status\":\"Failed\",\"Import_Error\":\"${ERR_SUMMARY}\"},\"typecast\":true}" \
    "https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/${PROJECTS_TABLE}/${RECORD_ID}" \
    > /dev/null 2>&1 || true

  exit 1
fi
