#!/bin/bash
# process-airtable.sh — Provisiona proyectos desde Airtable (Pipeline_Status = "Required")
# Uso: ./process-airtable.sh [--dry-run]
#
# Requiere: /root/scripts/.airtable.env con:
#   AIRTABLE_TOKEN=pat...
#   AIRTABLE_BASE_ID=app...
#   AIRTABLE_TABLE_ID=tbl...
#
# Campos usados desde Airtable (tabla Projects):
#   Name              → título del proyecto
#   Cpanel_User       → base_name cPanel (si vacío, se genera desde Name)
#   Email             → email del admin (si vacío: admin@{base_name}.bewpro.com)
#   Slug (from Product) → product slug para bewpro:new
#   Domain            → URL del sitio (si vacío: https://{base_name}.bewpro.com)
#   Notes             → texto: contiene CLEAN=true y/o COLORS=#HEX,... (opciones de provisión)
#
# Escribe de vuelta en Airtable:
#   Pipeline_Status   → "On Development"
#   Cpanel_User       → base_name usado
#   Provisioned_DB    → {base_name}_bp
#   Provisioned_Password → password generado

set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SETUP_SCRIPT="${SCRIPT_DIR}/setup_cd_project2.sh"

CONFIG_FILE="/root/scripts/.airtable.env"

########################################
# FLAGS
########################################

DRY_RUN=false
for arg in "$@"; do
  [[ "$arg" == "--dry-run" ]] && DRY_RUN=true
done

########################################
# CHEQUEO DE ROOT
########################################

if [[ "$(id -u)" -ne 0 ]]; then
  echo "Este script debe ejecutarse como root." >&2
  exit 1
fi

########################################
# DEPENDENCIAS
########################################

for cmd in curl python3 jq openssl; do
  if ! command -v "$cmd" &>/dev/null; then
    echo "ERROR: '$cmd' no está instalado." >&2
    exit 1
  fi
done

if [[ ! -x "$SETUP_SCRIPT" ]]; then
  echo "ERROR: setup_cd_project2.sh no encontrado o no ejecutable: ${SETUP_SCRIPT}" >&2
  exit 1
fi

########################################
# CARGAR CONFIG DE AIRTABLE
########################################

if [[ -f "$CONFIG_FILE" ]]; then
  # shellcheck disable=SC1090
  source "$CONFIG_FILE"
fi

AIRTABLE_TOKEN="${AIRTABLE_TOKEN:-}"
AIRTABLE_BASE_ID="${AIRTABLE_BASE_ID:-}"
AIRTABLE_TABLE_ID="${AIRTABLE_TABLE_ID:-}"

if [[ -z "$AIRTABLE_TOKEN" || -z "$AIRTABLE_BASE_ID" || -z "$AIRTABLE_TABLE_ID" ]]; then
  echo "ERROR: Faltan variables de Airtable." >&2
  echo "Creá ${CONFIG_FILE} con:" >&2
  echo "  AIRTABLE_TOKEN=pat..." >&2
  echo "  AIRTABLE_BASE_ID=app..." >&2
  echo "  AIRTABLE_TABLE_ID=tbl... (o nombre de tabla, e.g. Projects)" >&2
  exit 1
fi

AIRTABLE_API_URL="https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/${AIRTABLE_TABLE_ID}"

########################################
# FUNCIONES AIRTABLE
########################################

airtable_get_required() {
  local filter
  filter=$(python3 -c "import urllib.parse; print(urllib.parse.quote('{Pipeline_Status}=\"Required\"'))")
  curl -s \
    -H "Authorization: Bearer ${AIRTABLE_TOKEN}" \
    -H "Content-Type: application/json" \
    "${AIRTABLE_API_URL}?filterByFormula=${filter}&sort%5B0%5D%5Bfield%5D=Name&sort%5B0%5D%5Bdirection%5D=asc"
}

airtable_patch() {
  local record_id="$1"
  local payload="$2"
  curl -s -X PATCH \
    -H "Authorization: Bearer ${AIRTABLE_TOKEN}" \
    -H "Content-Type: application/json" \
    -d "$payload" \
    "${AIRTABLE_API_URL}/${record_id}"
}

airtable_mark_processing() {
  local record_id="$1"
  local payload='{"fields":{"Pipeline_Status":"Processing"}}'
  airtable_patch "$record_id" "$payload"
}

airtable_mark_failed() {
  local record_id="$1"
  # Solo marca Failed — no toca Notes para preservar CLEAN/COLORS
  local payload='{"fields":{"Pipeline_Status":"Failed"}}'
  airtable_patch "$record_id" "$payload"
}

airtable_mark_on_development() {
  local record_id="$1"
  local db_name="$2"
  local password="$3"
  local cpanel_user="$4"
  local app_url="$5"

  # Grace period: 15 días desde hoy
  local grace_end
  grace_end=$(date -d "+15 days" '+%Y-%m-%d' 2>/dev/null || date -v+15d '+%Y-%m-%d' 2>/dev/null || "")

  local payload
  payload=$(python3 -c "
import json, sys
data = {
    'fields': {
        'Pipeline_Status': 'On Development',
        'Cpanel_User': sys.argv[1],
        'Provisioned_DB': sys.argv[2],
        'Provisioned_Password': sys.argv[3],
        'Domain': sys.argv[4]
    }
}
if sys.argv[5]:
    data['fields']['Grace_Period_End'] = sys.argv[5]
print(json.dumps(data))
" "$cpanel_user" "$db_name" "$password" "$app_url" "$grace_end")

  airtable_patch "$record_id" "$payload"
}

airtable_create_subscription() {
  local project_record_id="$1"
  local project_name="$2"
  local cpanel_user="$3"
  local app_url="$4"

  local payload
  payload=$(python3 -c "
import json, sys
data = {
    'fields': {
        'Project': sys.argv[1],
        'Copia de Project': [sys.argv[2]],
        'Billing_Model': 'Stripe',
        'Status': 'Active'
    }
}
print(json.dumps(data))
" "$project_name" "$project_record_id")

  curl -s -X POST \
    -H "Authorization: Bearer ${AIRTABLE_TOKEN}" \
    -H "Content-Type: application/json" \
    -d "$payload" \
    "https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/tblnpr52JhFBBi2Mg"
}

########################################
# PARSEAR REGISTROS DE AIRTABLE
########################################

parse_records() {
  local json="$1"

  # Devuelve líneas: record_id|name|cpanel_user|email|slug|domain
  python3 - "$json" <<'PYEOF'
import sys, json, re

raw = sys.argv[1]
try:
    data = json.loads(raw)
except Exception as e:
    print(f"ERROR parsing JSON: {e}", file=sys.stderr)
    sys.exit(1)

records = data.get('records', [])
if not records:
    print("NO_RECORDS")
    sys.exit(0)

def make_base_name(title):
    """Genera base_name desde título: lowercase alfanumérico, max 14 chars."""
    return re.sub(r'[^a-z0-9]', '', title.lower())[:14]

def normalize_domain(domain, base_name):
    """Asegura que el dominio tenga https://. Descarta cualquier valor que no sea una URL limpia."""
    # Tomar solo la primera línea (evita corrupción con saltos de línea embebidos)
    d = domain.split('\n')[0].strip()
    # Rechazar placeholders o valores que no parezcan un dominio real
    if not d or d in ('---', '-', 'N/A', 'n/a'):
        return f"https://{base_name}.bewpro.com"
    # Validar que tenga la forma de un dominio (letras, números, puntos, guiones)
    if not re.match(r'^https?://[a-zA-Z0-9]', d) and not re.match(r'^[a-zA-Z0-9][\w.-]+\.[a-zA-Z]{2,}$', d):
        return f"https://{base_name}.bewpro.com"
    if not d.startswith('http'):
        return f"https://{d}"
    return d

for r in records:
    fields = r.get('fields', {})
    record_id = r.get('id', '')
    name       = fields.get('Name', '').strip()
    cpanel_user = fields.get('Cpanel_User', '').strip()
    email      = fields.get('Email', '').strip()

    # "Slug (from Product)" es un lookup — viene como array
    slug_raw = fields.get('Slug (from Product)', [])
    if isinstance(slug_raw, list):
        slug = slug_raw[0].strip() if slug_raw else ''
    else:
        slug = str(slug_raw).strip()
    # Fallback: campo Slug de texto plano (escrito por el webhook de Stripe)
    if not slug:
        slug = fields.get('Slug', '').strip()

    domain_raw = fields.get('Domain', '').strip()

    # Provision options: parseados desde Notes (formato "CLEAN=true\nCOLORS=#HEX,...")
    notes = fields.get('Notes', '').strip()
    clean = 'false'
    colors = ''
    for line in notes.split('\n'):
        line = line.strip()
        if line.startswith('CLEAN='):
            clean = line.split('=', 1)[1].strip().lower()
        elif line.startswith('COLORS='):
            colors = line.split('=', 1)[1].strip()

    if not name or not slug:
        print(f"SKIP|{record_id}|{name}|missing name or slug", file=sys.stderr)
        continue

    # base_name: usar Cpanel_User si existe, si no generar desde Name
    base_name = cpanel_user if cpanel_user else make_base_name(name)

    # email fallback
    if not email:
        email = f"admin@{base_name}.bewpro.com"

    # normalizar dominio
    domain = normalize_domain(domain_raw, base_name)

    print(f"{record_id}|{name}|{base_name}|{email}|{slug}|{domain}|{clean}|{colors}")
PYEOF
}

########################################
# MAIN
########################################

echo "============================================="
echo "  PROCESS AIRTABLE — Pipeline Provisioning"
if $DRY_RUN; then
  echo "  MODE: DRY RUN (sin cambios reales)"
fi
echo "============================================="
echo ""

echo "Consultando Airtable (Pipeline_Status = Required)..."
RESPONSE=$(airtable_get_required)

if echo "$RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); sys.exit(0 if 'records' in d else 1)" 2>/dev/null; then
  :
else
  echo "ERROR: Respuesta inesperada de Airtable:" >&2
  echo "$RESPONSE" >&2
  exit 1
fi

RECORDS=$(parse_records "$RESPONSE")

if [[ "$RECORDS" == "NO_RECORDS" || -z "$RECORDS" ]]; then
  echo "No hay proyectos con Pipeline_Status = 'Required'. Nada que hacer."
  exit 0
fi

COUNT=$(echo "$RECORDS" | grep -c '.' || true)
echo "Proyectos a provisionar: ${COUNT}"
echo ""

SUCCEEDED=0
FAILED=0
FAILED_NAMES=()

# Formato de línea: record_id|name|base_name|email|slug|domain|clean|colors
while IFS='|' read -r RECORD_ID NAME BASE_NAME EMAIL SLUG DOMAIN CLEAN_FLAG COLORS_VAL; do
  echo "---------------------------------------------"
  echo "  Proyecto:  ${NAME}"
  echo "  base_name: ${BASE_NAME}"
  echo "  Email:     ${EMAIL}"
  echo "  Slug:      ${SLUG}"
  echo "  Domain:    ${DOMAIN}"
  echo "  DB:        ${BASE_NAME}_bp"
  echo "  Clean:     ${CLEAN_FLAG:-false}"
  echo "  Colors:    ${COLORS_VAL:-default}"
  echo ""

  PASSWORD=$(openssl rand -base64 12 | tr -d '/+=')

  if $DRY_RUN; then
    echo "  [DRY RUN] CLEAN_PROVISION=${CLEAN_FLAG:-false} BRAND_COLORS=\"${COLORS_VAL:-}\" setup_cd_project2.sh ${BASE_NAME} ${EMAIL} \"${NAME}\" ${SLUG} <password> ${DOMAIN}"
    echo ""
    continue
  fi

  # Marcar como Processing ANTES de provisionar — evita race condition con crons paralelos
  echo "  Marcando como Processing en Airtable..."
  airtable_mark_processing "$RECORD_ID" > /dev/null

  # Exportar flags opcionales para setup_cd_project2.sh
  export CLEAN_PROVISION="${CLEAN_FLAG:-false}"
  export BRAND_COLORS="${COLORS_VAL:-}"

  # Ejecutar setup script; STDOUT = URL del sitio, STDERR = logs
  APP_URL=""
  if APP_URL=$(bash "$SETUP_SCRIPT" "$BASE_NAME" "$EMAIL" "$NAME" "$SLUG" "$PASSWORD" "$DOMAIN"); then
    echo "  OK — ${APP_URL}"

    # 1. Actualizar Project en Airtable
    echo "  Actualizando Airtable..."
    PATCH_RESULT=$(airtable_mark_on_development "$RECORD_ID" "${BASE_NAME}_bp" "$PASSWORD" "$BASE_NAME" "$APP_URL")

    if echo "$PATCH_RESULT" | python3 -c "import sys,json; d=json.load(sys.stdin); sys.exit(0 if 'id' in d else 1)" 2>/dev/null; then
      echo "    Project: Pipeline_Status=On Development, Domain=${APP_URL}"
    else
      echo "  WARN: Project PATCH falló:" >&2
      echo "$PATCH_RESULT" >&2
    fi

    # 2. Crear Subscription record
    SUB_RESULT=$(airtable_create_subscription "$RECORD_ID" "$NAME" "$BASE_NAME" "$APP_URL")
    if echo "$SUB_RESULT" | python3 -c "import sys,json; d=json.load(sys.stdin); sys.exit(0 if 'id' in d else 1)" 2>/dev/null; then
      echo "    Subscription: creada (Stripe/Active)"
    else
      echo "  WARN: Subscription no creada:" >&2
      echo "$SUB_RESULT" >&2
    fi

    # 3. Emails: bienvenida al cliente + notificación al reseller
    GRACE_END=$(date -d "+15 days" '+%Y-%m-%d' 2>/dev/null || date -v+15d '+%Y-%m-%d' 2>/dev/null || "")
    echo "  Enviando emails (cliente: ${EMAIL})..."

    # Intentar via artisan (usa templates Laravel profesionales)
    ARTISAN_CMD="php artisan bewpro:send-welcome '${EMAIL}' '${NAME}' '${APP_URL}' '${PASSWORD}' --product='${SLUG}'"
    if [[ -n "${GRACE_END}" ]]; then
      ARTISAN_CMD="${ARTISAN_CMD} --grace-end='${GRACE_END}'"
    fi
    # TODO: agregar --reseller-email cuando tengamos el dato del reseller desde Airtable

    su - "${BASE_NAME}" -c "
      cd public_html/git-files/${BASE_NAME} && \
      ${ARTISAN_CMD}
    " >&2 \
      && echo "    Emails: enviados via artisan" \
      || {
        # Fallback: send-welcome-email.php (legacy)
        echo "  WARN: artisan falló, intentando fallback..." >&2
        PHP_BIN_GLOBAL=$(which php 2>/dev/null || echo "php")
        EMAIL_SCRIPT="$(dirname "$SETUP_SCRIPT")/send-welcome-email.php"
        if [[ -f "$EMAIL_SCRIPT" ]]; then
          $PHP_BIN_GLOBAL "$EMAIL_SCRIPT" "$EMAIL" "$NAME" "$APP_URL" "$PASSWORD" "$EMAIL" 2>/dev/null \
            && echo "    Email: enviado via fallback" \
            || echo "  WARN: email no enviado" >&2
        else
          echo "  WARN: No se pudo enviar email (artisan ni fallback)" >&2
        fi
      }

    SUCCEEDED=$((SUCCEEDED + 1))
  else
    echo "  ERROR: Provisioning falló para '${NAME}'." >&2

    # Marcar como Failed en Airtable para que no quede bloqueado en Processing
    airtable_mark_failed "$RECORD_ID" > /dev/null
    echo "    Airtable: Pipeline_Status=Failed" >&2

    FAILED=$((FAILED + 1))
    FAILED_NAMES+=("$NAME")
  fi

  echo ""
done <<< "$RECORDS"

echo "============================================="
if $DRY_RUN; then
  echo "  DRY RUN completado — ${COUNT} proyecto(s) en cola"
else
  echo "  Resultado: ${SUCCEEDED} OK, ${FAILED} fallidos"
  if [[ ${#FAILED_NAMES[@]} -gt 0 ]]; then
    echo "  Fallidos:"
    for n in "${FAILED_NAMES[@]}"; do
      echo "    - ${n}"
    done
  fi
fi
echo "============================================="

# Exit con error si hubo fallos
[[ $FAILED -gt 0 ]] && exit 1
exit 0
