#!/usr/bin/env bash
set -euo pipefail

SENDGRID_API_KEY="${SENDGRID_API_KEY:?Falta SENDGRID_API_KEY}"
MYSQL_PASS="${MYSQL_PASS:?Falta MYSQL_PASS}"

MYSQL_HOST="${MYSQL_HOST:-localhost}"
MYSQL_USER="${MYSQL_USER:-linder8_sendgrid_marketing}"
MYSQL_DB="${MYSQL_DB:-linder8_sendgrid_marketing}"

COMPANY="${COMPANY:-LINDERLAKE}"
CONTACTS_PER_LIST="${CONTACTS_PER_LIST:-2000}"
BATCH_SIZE="${BATCH_SIZE:-2000}"
PREFIX="${PREFIX:-Campaign_${COMPANY}_Random}"

# Async-verification tunables (SENDGRID-OPS-002 Phase 5).
IMPORT_JOB_POLL_INTERVAL="${IMPORT_JOB_POLL_INTERVAL:-5}"
IMPORT_JOB_MAX_WAIT="${IMPORT_JOB_MAX_WAIT:-600}"
LIST_COUNT_POLL_INTERVAL="${LIST_COUNT_POLL_INTERVAL:-5}"
LIST_COUNT_MAX_WAIT="${LIST_COUNT_MAX_WAIT:-300}"
LIST_COUNT_TOLERANCE="${LIST_COUNT_TOLERANCE:-0}"

# Guard against pathological zero-interval configs that would spin forever.
(( IMPORT_JOB_POLL_INTERVAL >= 1 )) || IMPORT_JOB_POLL_INTERVAL=1
(( LIST_COUNT_POLL_INTERVAL >= 1 )) || LIST_COUNT_POLL_INTERVAL=1

WORKDIR="${WORKDIR:-/tmp/sendgrid_dynamic_lists}"
RUN_ID="$(date '+%Y%m%d_%H%M%S')"

CONTACTS_TSV="$WORKDIR/contacts_to_use.tsv"
CHUNKS_DIR="$WORKDIR/chunks"
CREATED_TSV="$WORKDIR/created_lists.tsv"

rm -rf "$WORKDIR"
mkdir -p "$WORKDIR" "$CHUNKS_DIR"

need_cmd() {
  command -v "$1" >/dev/null || { echo "ERROR: falta $1"; exit 1; }
}

need_cmd mysql
need_cmd curl
need_cmd jq
need_cmd python3
need_cmd split

# --- SENDGRID-OPS-002 hardening helpers ---------------------------------

sg_get_json() {
  # $1 URL, $2 out_file. Echoes HTTP code on stdout.
  local URL="$1" OUT="$2"
  curl --connect-timeout 10 --max-time 60 --retry 3 --retry-delay 2 \
    -sS -o "$OUT" -w '%{http_code}' \
    -H "Authorization: Bearer $SENDGRID_API_KEY" \
    "$URL"
}

wait_for_import_job() {
  # Blocks until job is terminal or MAX_WAIT is exceeded.
  # $1 JOB_ID, $2 LIST_ID (for logging), $3 LIST_NAME
  local JOB_ID="$1" LIST_ID="$2" LIST_NAME="$3"
  local WAITED=0 HTTP STATUS JSON="$WORKDIR/job_${JOB_ID}.json"

  while (( WAITED < IMPORT_JOB_MAX_WAIT )); do
    HTTP="$(sg_get_json "https://api.sendgrid.com/v3/marketing/contacts/imports/$JOB_ID" "$JSON" || true)"

    if [[ "$HTTP" != "200" ]]; then
      echo "WARN import-poll HTTP=$HTTP list=$LIST_NAME job=$JOB_ID waited=${WAITED}s" >&2
      sleep "$IMPORT_JOB_POLL_INTERVAL"
      WAITED=$((WAITED + IMPORT_JOB_POLL_INTERVAL))
      continue
    fi

    STATUS="$(jq -r '.status // empty' "$JSON")"
    case "$STATUS" in
      completed)
        echo "IMPORT_JOB_OK list=$LIST_NAME job=$JOB_ID waited=${WAITED}s"
        return 0
        ;;
      errored|failed)
        echo "IMPORT_JOB_FAILED list=$LIST_NAME job=$JOB_ID status=$STATUS waited=${WAITED}s" >&2
        jq . "$JSON" >&2
        return 1
        ;;
      pending|processing|"")
        sleep "$IMPORT_JOB_POLL_INTERVAL"
        WAITED=$((WAITED + IMPORT_JOB_POLL_INTERVAL))
        ;;
      *)
        echo "IMPORT_JOB_UNKNOWN_STATUS list=$LIST_NAME job=$JOB_ID status=$STATUS" >&2
        jq . "$JSON" >&2
        return 1
        ;;
    esac
  done

  echo "IMPORT_JOB_TIMEOUT list=$LIST_NAME job=$JOB_ID max_wait=${IMPORT_JOB_MAX_WAIT}s" >&2
  return 1
}

verify_list_count() {
  # $1 LIST_ID, $2 LIST_NAME, $3 EXPECTED
  local LIST_ID="$1" LIST_NAME="$2" EXPECTED="$3"
  local WAITED=0 HTTP ACTUAL DIFF JSON="$WORKDIR/list_${LIST_ID}.json"

  while (( WAITED < LIST_COUNT_MAX_WAIT )); do
    HTTP="$(sg_get_json "https://api.sendgrid.com/v3/marketing/lists/$LIST_ID?contact_sample=false" "$JSON" || true)"

    if [[ "$HTTP" == "404" ]]; then
      echo "LIST_MISSING list=$LIST_NAME id=$LIST_ID (404)" >&2
      return 1
    fi

    if [[ "$HTTP" != "200" ]]; then
      echo "WARN list-poll HTTP=$HTTP list=$LIST_NAME waited=${WAITED}s" >&2
      sleep "$LIST_COUNT_POLL_INTERVAL"
      WAITED=$((WAITED + LIST_COUNT_POLL_INTERVAL))
      continue
    fi

    ACTUAL="$(jq -r '.contact_count // 0' "$JSON")"
    if [[ "$ACTUAL" =~ ^[0-9]+$ ]] && (( ACTUAL >= EXPECTED - LIST_COUNT_TOLERANCE )); then
      echo "LIST_COUNT_OK list=$LIST_NAME expected=$EXPECTED actual=$ACTUAL waited=${WAITED}s"
      return 0
    fi

    sleep "$LIST_COUNT_POLL_INTERVAL"
    WAITED=$((WAITED + LIST_COUNT_POLL_INTERVAL))
  done

  # Emit final actual for diagnosis
  ACTUAL="$(jq -r '.contact_count // 0' "$JSON" 2>/dev/null || echo -1)"
  DIFF=$((EXPECTED - ACTUAL))
  echo "LIST_COUNT_MISMATCH list=$LIST_NAME id=$LIST_ID expected=$EXPECTED actual=$ACTUAL diff=$DIFF max_wait=${LIST_COUNT_MAX_WAIT}s" >&2
  return 1
}

# ------------------------------------------------------------------------

cat > "$WORKDIR/exclude_lists.txt" <<'EOF'
2025_BCS_P_BCS_2026_02_20
2025_BCS_P_Myrex_Competitors
2025_C_BCSENGINEERS_Clients
2025_Clients_Dlcossich
2025_Clients_Ecook
EOF

echo "=== 1) PREPARANDO TABLA DE LISTAS DINÁMICAS ==="

mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASS" "$MYSQL_DB" <<'SQL'
CREATE TABLE IF NOT EXISTS dynamic_sendgrid_lists (
  id BIGINT NOT NULL AUTO_INCREMENT,
  run_id VARCHAR(50) NOT NULL,
  company_name VARCHAR(100) NOT NULL,
  sendgrid_list_id VARCHAR(100) NOT NULL,
  list_name VARCHAR(255) NOT NULL,
  contact_count INT NOT NULL DEFAULT 0,
  contacts_per_list INT NOT NULL DEFAULT 0,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  UNIQUE KEY uq_sendgrid_list_id (sendgrid_list_id),
  KEY idx_run_id (run_id),
  KEY idx_company_name (company_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
SQL

echo "=== 2) GENERANDO CONTACTOS ELEGIBLES DESDE MYSQL ==="
echo "Empresa: $COMPANY"
echo "Contactos por lista: $CONTACTS_PER_LIST"

mysql --batch --raw --skip-column-names \
  -h "$MYSQL_HOST" \
  -u "$MYSQL_USER" \
  -p"$MYSQL_PASS" \
  "$MYSQL_DB" <<SQL > "$CONTACTS_TSV"
SELECT DISTINCT LOWER(c.email), c.first_name, c.last_name
FROM contacts c
WHERE c.company_name = '$COMPANY'
  AND c.status = 'active'
  AND c.unsubscribed = 0
  AND NOT EXISTS (
    SELECT 1
    FROM contact_list_memberships m
    WHERE m.contact_id = c.id
      AND m.list_name IN (
        '2025_BCS_P_BCS_2026_02_20',
        '2025_BCS_P_Myrex_Competitors',
        '2025_C_BCSENGINEERS_Clients',
        '2025_Clients_Dlcossich',
        '2025_Clients_Ecook'
      )
  )
ORDER BY RAND();
SQL

TOTAL_CONTACTS="$(wc -l < "$CONTACTS_TSV" | tr -d ' ')"
echo "Contactos elegibles: $TOTAL_CONTACTS"

if [[ "$TOTAL_CONTACTS" -eq 0 ]]; then
  echo "ERROR: no hay contactos elegibles."
  exit 1
fi

echo "=== 3) DIVIDIENDO EN CHUNKS ==="

split -l "$CONTACTS_PER_LIST" -d -a 4 "$CONTACTS_TSV" "$CHUNKS_DIR/chunk_"

TOTAL_LISTS="$(find "$CHUNKS_DIR" -type f -name 'chunk_*' | wc -l | tr -d ' ')"
echo "Listas a crear: $TOTAL_LISTS"

echo -e "sendgrid_list_id\tlist_name\tcontact_count" > "$CREATED_TSV"

echo "=== 4) CREANDO LISTAS EN SENDGRID Y AGREGANDO CONTACTOS ==="

LIST_NUM=0

for CHUNK_FILE in "$CHUNKS_DIR"/chunk_*; do
  LIST_NUM=$((LIST_NUM + 1))
  LIST_NAME="${PREFIX}_${RUN_ID}_${LIST_NUM}"
  CONTACT_COUNT="$(wc -l < "$CHUNK_FILE" | tr -d ' ')"

  echo "Lista $LIST_NUM/$TOTAL_LISTS: $LIST_NAME ($CONTACT_COUNT contactos)"

  CREATE_RESP="$(
    curl -sS -X POST "https://api.sendgrid.com/v3/marketing/lists" \
      -H "Authorization: Bearer $SENDGRID_API_KEY" \
      -H "Content-Type: application/json" \
      --data "$(jq -n --arg name "$LIST_NAME" '{name:$name}')"
  )"

  LIST_ID="$(echo "$CREATE_RESP" | jq -r '.id // empty')"

  if [[ -z "$LIST_ID" ]]; then
    echo "ERROR creando lista:"
    echo "$CREATE_RESP" | jq .
    exit 1
  fi

  echo "  SendGrid List ID: $LIST_ID"

  SPLIT_DIR="$WORKDIR/batches_${LIST_NUM}"
  mkdir -p "$SPLIT_DIR"
  split -l "$BATCH_SIZE" -d -a 4 "$CHUNK_FILE" "$SPLIT_DIR/batch_"

  BATCH_NUM=0
  ADDED_SO_FAR=0

  for BATCH_FILE in "$SPLIT_DIR"/batch_*; do
    BATCH_NUM=$((BATCH_NUM + 1))
    BATCH_COUNT="$(wc -l < "$BATCH_FILE" | tr -d ' ')"

    echo "  Batch $BATCH_NUM ($BATCH_COUNT contactos)"

    PAYLOAD="$WORKDIR/payload_${LIST_NUM}_${BATCH_NUM}.json"

    python3 - "$BATCH_FILE" "$LIST_ID" "$PAYLOAD" <<'PY'
import json
import sys

batch_file, list_id, payload_file = sys.argv[1], sys.argv[2], sys.argv[3]

contacts = []

with open(batch_file, encoding="utf-8") as f:
    for line in f:
        parts = line.rstrip("\n").split("\t")
        email = parts[0].strip().lower() if len(parts) > 0 else ""
        first = parts[1].strip() if len(parts) > 1 else ""
        last = parts[2].strip() if len(parts) > 2 else ""

        if not email:
            continue

        contacts.append({
            "email": email,
            "first_name": first,
            "last_name": last
        })

payload = {
    "list_ids": [list_id],
    "contacts": contacts
}

with open(payload_file, "w", encoding="utf-8") as out:
    json.dump(payload, out, ensure_ascii=False)
PY

    ADD_RESP="$(
      curl -sS -X PUT "https://api.sendgrid.com/v3/marketing/contacts" \
        -H "Authorization: Bearer $SENDGRID_API_KEY" \
        -H "Content-Type: application/json" \
        --data-binary "@$PAYLOAD"
    )"

    JOB_ID="$(echo "$ADD_RESP" | jq -r '.job_id // .id // empty')"

    if [[ -z "$JOB_ID" ]]; then
      echo "  ERROR agregando contactos:"
      echo "$ADD_RESP" | jq .
      exit 1
    fi

    echo "  Job ID: $JOB_ID"

    # HARDENED: block until this async import job is verified complete.
    if ! wait_for_import_job "$JOB_ID" "$LIST_ID" "$LIST_NAME"; then
      echo "STOP: async import job failed for list $LIST_NAME (id=$LIST_ID job=$JOB_ID)" >&2
      exit 1
    fi

    ADDED_SO_FAR=$((ADDED_SO_FAR + BATCH_COUNT))
    sleep 2
  done

  # HARDENED: re-read the list and require contact_count == expected chunk size.
  # (The final chunk may be smaller than CONTACTS_PER_LIST; we assert against
  #  the actual chunk size, not the nominal CONTACTS_PER_LIST.)
  if ! verify_list_count "$LIST_ID" "$LIST_NAME" "$CONTACT_COUNT"; then
    echo "STOP: list $LIST_NAME (id=$LIST_ID) did not reach expected count=$CONTACT_COUNT" >&2
    exit 1
  fi

  echo -e "${LIST_ID}\t${LIST_NAME}\t${CONTACT_COUNT}" >> "$CREATED_TSV"

  mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASS" "$MYSQL_DB" <<SQL
INSERT INTO dynamic_sendgrid_lists
(run_id, company_name, sendgrid_list_id, list_name, contact_count, contacts_per_list)
VALUES
('$RUN_ID', '$COMPANY', '$LIST_ID', '$LIST_NAME', $CONTACT_COUNT, $CONTACTS_PER_LIST);
SQL

done

echo "=== 5) RESUMEN ==="

mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASS" "$MYSQL_DB" <<SQL
SELECT run_id, company_name, COUNT(*) AS listas, SUM(contact_count) AS contactos
FROM dynamic_sendgrid_lists
WHERE run_id = '$RUN_ID'
GROUP BY run_id, company_name;

SELECT list_name, sendgrid_list_id, contact_count
FROM dynamic_sendgrid_lists
WHERE run_id = '$RUN_ID'
ORDER BY id;
SQL

echo "DONE JARVIS 🚀"
echo "Run ID: $RUN_ID"
echo "Archivo creado: $CREATED_TSV"
