#!/usr/bin/env bash
# mas_syn2mas_migration — Migra usuarios Synapse a MAS via mas-cli syn2mas.
# Fuerza dry-run primero, archiva el log, aborta si conflicts > threshold,
# y solo ejecuta la migracion real cuando se pasa --apply.
#
# Usage:
#   mas_syn2mas_migration --ssh-host <host> --mas-container <name> \
#       --synapse-config-path <path-on-host> --log-dir <local-path> \
#       [--max-conflicts N] [--apply]
#
# Output: JSON en stdout con status, dry_run_log, apply_log, conflicts, users_migrated, duration_s

set -euo pipefail

mas_syn2mas_migration() {
    local ssh_host=""
    local mas_container=""
    local synapse_config_path=""
    local log_dir=""
    local max_conflicts=0
    local do_apply=false

    # ---- Parse args ----
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --ssh-host)
                ssh_host="$2"
                shift 2
                ;;
            --mas-container)
                mas_container="$2"
                shift 2
                ;;
            --synapse-config-path)
                synapse_config_path="$2"
                shift 2
                ;;
            --log-dir)
                log_dir="$2"
                shift 2
                ;;
            --max-conflicts)
                max_conflicts="$2"
                shift 2
                ;;
            --apply)
                do_apply=true
                shift
                ;;
            --help|-h)
                cat >&2 <<'USAGE'
mas_syn2mas_migration - Migra usuarios Synapse a Matrix Authentication Service (MAS)

Usage:
  mas_syn2mas_migration \
    --ssh-host <host> \
    --mas-container <name> \
    --synapse-config-path <path-on-host> \
    --log-dir <local-path> \
    [--max-conflicts N] \
    [--apply]

Opciones:
  --ssh-host              Alias SSH del VPS (ej. organic-machine.com)
  --mas-container         Nombre del container MAS (ej. element_matrix_chat-mas-1)
  --synapse-config-path   Ruta en el VPS al homeserver.yaml
                          (ej. /home/ubuntu/CodeProyects/element_matrix_chat/synapse_data/homeserver.yaml)
  --log-dir               Directorio local donde archivar logs dry-run y apply
  --max-conflicts N       Tope de conflictos en dry-run antes de abortar (default 0)
  --apply                 Ejecutar migracion real. Sin esta flag: solo dry-run.

Comportamiento:
  1. Siempre ejecuta dry-run primero y archiva el log.
  2. Si conflicts > max-conflicts -> status=aborted, exit 2.
  3. Sin --apply -> status=ok (dry-run completado), exit 0.
  4. Con --apply -> ejecuta migracion real, archiva log, verifica postcondicion.

Output JSON: {"status":"ok|aborted|error","dry_run_log":"path","apply_log":"path|null","conflicts":N,"users_migrated":N,"duration_s":N}
USAGE
                echo '{"status":"help","dry_run_log":"","apply_log":null,"conflicts":0,"users_migrated":0,"duration_s":0}'
                return 0
                ;;
            *)
                echo "mas_syn2mas_migration: argumento desconocido: $1" >&2
                return 1
                ;;
        esac
    done

    # ---- Validar argumentos obligatorios ----
    local errors=()
    [[ -z "$ssh_host"             ]] && errors+=("--ssh-host es obligatorio")
    [[ -z "$mas_container"        ]] && errors+=("--mas-container es obligatorio")
    [[ -z "$synapse_config_path"  ]] && errors+=("--synapse-config-path es obligatorio")
    [[ -z "$log_dir"              ]] && errors+=("--log-dir es obligatorio")

    if [[ ${#errors[@]} -gt 0 ]]; then
        for err in "${errors[@]}"; do
            echo "ERROR: $err" >&2
        done
        echo '{"status":"error","dry_run_log":"","apply_log":null,"conflicts":-1,"users_migrated":0,"duration_s":0}'
        return 1
    fi

    # Validar que max_conflicts es un entero no negativo
    if ! [[ "$max_conflicts" =~ ^[0-9]+$ ]]; then
        echo "ERROR: --max-conflicts debe ser un entero >= 0, recibido: $max_conflicts" >&2
        echo '{"status":"error","dry_run_log":"","apply_log":null,"conflicts":-1,"users_migrated":0,"duration_s":0}'
        return 1
    fi

    # ---- Dependencias locales ----
    if ! command -v jq &>/dev/null; then
        echo "ERROR: jq no encontrado. Instalar: apt install jq / brew install jq" >&2
        echo '{"status":"error","dry_run_log":"","apply_log":null,"conflicts":-1,"users_migrated":0,"duration_s":0}'
        return 1
    fi

    # ---- Crear log-dir con permisos restringidos ----
    mkdir -p "$log_dir"
    chmod 0700 "$log_dir"

    local ts
    ts=$(date +%s)

    local dry_run_log="${log_dir}/syn2mas_dryrun_${ts}.log"
    local apply_log_path="null"
    local apply_log_file="${log_dir}/syn2mas_apply_${ts}.log"

    # La ruta del homeserver.yaml dentro del container MAS se pasa como --synapse-config
    # MAS monta el directorio del synapse bajo /data/ por convencion, pero la ruta real
    # puede variar — usamos la ruta tal como existe en el host (montada via volume).
    # El comando real esperado: docker exec <container> mas-cli syn2mas --synapse-config <path>
    # donde <path> es la ruta tal como el container la ve (via volume mount).
    # Asumimos que el VPS tiene el config accesible en la misma ruta dentro del container.
    local container_config="/data/homeserver.yaml"

    echo "mas_syn2mas_migration: ssh-host=${ssh_host} container=${mas_container} max-conflicts=${max_conflicts} apply=${do_apply}" >&2

    # =========================================================================
    # PASO 1: DRY-RUN obligatorio
    # =========================================================================
    echo "mas_syn2mas_migration: ejecutando dry-run..." >&2

    local dry_exit=0
    # Capturar stdout+stderr del dry-run en el log y tambien en variable para parsing
    local dry_output
    dry_output=$(ssh "$ssh_host" \
        "docker exec '${mas_container}' mas-cli syn2mas \
            --synapse-config '${container_config}' \
            --dry-run" \
        2>&1) || dry_exit=$?

    # Archivar log con timestamp + header informativo
    {
        echo "# mas_syn2mas_migration dry-run"
        echo "# ts=${ts} ssh-host=${ssh_host} container=${mas_container}"
        echo "# synapse-config-path=${synapse_config_path}"
        echo "# exit=${dry_exit}"
        echo "# ---"
        printf '%s\n' "$dry_output"
    } > "$dry_run_log"
    chmod 0600 "$dry_run_log"

    echo "mas_syn2mas_migration: dry-run exit=${dry_exit}, log=${dry_run_log}" >&2

    if [[ $dry_exit -ne 0 ]]; then
        # Si el comando SSH falla completamente (no es fallo de syn2mas sino de conectividad)
        echo "mas_syn2mas_migration: ERROR — dry-run falló con exit ${dry_exit}" >&2
        local escaped_out
        escaped_out=$(printf '%s' "${dry_output}" | jq -Rs '.')
        local dry_run_log_json
        dry_run_log_json=$(printf '%s' "$dry_run_log" | jq -Rs '.')
        echo "{\"status\":\"error\",\"dry_run_log\":${dry_run_log_json},\"apply_log\":null,\"conflicts\":-1,\"users_migrated\":0,\"duration_s\":0}"
        return 1
    fi

    # =========================================================================
    # PASO 2: Parsear conflicts del dry-run
    # =========================================================================
    # Regex sobre lineas tipo:
    #   "Conflict:", "Skipping:", "Error processing user", "conflict"
    # También contamos líneas que indiquen usuarios problemáticos.
    local conflicts=0
    local conflict_lines
    conflict_lines=$(printf '%s\n' "$dry_output" | \
        grep -ciE '(conflict|skipping|error processing user|cannot migrate|already exists)' 2>/dev/null || true)

    # grep -c devuelve string; convertir a int defensivamente
    if [[ "$conflict_lines" =~ ^[0-9]+$ ]]; then
        conflicts=$conflict_lines
    else
        # Parser falló de forma inesperada — abortar defensivamente
        echo "mas_syn2mas_migration: ERROR — no se pudo parsear el conteo de conflicts del dry-run (parser defensivo)" >&2
        local dry_run_log_json
        dry_run_log_json=$(printf '%s' "$dry_run_log" | jq -Rs '.')
        echo "{\"status\":\"error\",\"dry_run_log\":${dry_run_log_json},\"apply_log\":null,\"conflicts\":-1,\"users_migrated\":0,\"duration_s\":0}"
        return 1
    fi

    echo "mas_syn2mas_migration: conflicts detectados en dry-run: ${conflicts} (max permitido: ${max_conflicts})" >&2

    # =========================================================================
    # PASO 3: Verificar threshold de conflicts
    # =========================================================================
    if [[ $conflicts -gt $max_conflicts ]]; then
        echo "mas_syn2mas_migration: ABORTADO — conflicts (${conflicts}) > max-conflicts (${max_conflicts})" >&2
        echo "Revisar: ${dry_run_log}" >&2
        local dry_run_log_json
        dry_run_log_json=$(printf '%s' "$dry_run_log" | jq -Rs '.')
        echo "{\"status\":\"aborted\",\"dry_run_log\":${dry_run_log_json},\"apply_log\":null,\"conflicts\":${conflicts},\"users_migrated\":0,\"duration_s\":0}"
        return 2
    fi

    # =========================================================================
    # PASO 4: Si no --apply, terminar aqui con status=ok (dry-run completado)
    # =========================================================================
    if [[ "$do_apply" == "false" ]]; then
        echo "mas_syn2mas_migration: dry-run completado (${conflicts} conflicts). Revisar log y re-ejecutar con --apply." >&2
        local dry_run_log_json
        dry_run_log_json=$(printf '%s' "$dry_run_log" | jq -Rs '.')
        echo "{\"status\":\"ok\",\"dry_run_log\":${dry_run_log_json},\"apply_log\":null,\"conflicts\":${conflicts},\"users_migrated\":0,\"duration_s\":0}"
        return 0
    fi

    # =========================================================================
    # PASO 5: Migracion REAL (--apply)
    # =========================================================================
    echo "mas_syn2mas_migration: ejecutando migracion REAL..." >&2
    local apply_start
    apply_start=$(date +%s)

    local apply_exit=0
    local apply_output
    apply_output=$(ssh "$ssh_host" \
        "docker exec '${mas_container}' mas-cli syn2mas \
            --synapse-config '${container_config}'" \
        2>&1) || apply_exit=$?

    local apply_end
    apply_end=$(date +%s)
    local duration_s=$(( apply_end - apply_start ))

    # Archivar log de apply
    {
        echo "# mas_syn2mas_migration apply"
        echo "# ts=${ts} ssh-host=${ssh_host} container=${mas_container}"
        echo "# synapse-config-path=${synapse_config_path}"
        echo "# exit=${apply_exit} duration_s=${duration_s}"
        echo "# ---"
        printf '%s\n' "$apply_output"
    } > "$apply_log_file"
    chmod 0600 "$apply_log_file"

    apply_log_path="$apply_log_file"
    echo "mas_syn2mas_migration: apply exit=${apply_exit}, duration=${duration_s}s, log=${apply_log_file}" >&2

    if [[ $apply_exit -ne 0 ]]; then
        echo "mas_syn2mas_migration: ERROR — migracion real falló con exit ${apply_exit}" >&2
        local dry_run_log_json apply_log_json
        dry_run_log_json=$(printf '%s' "$dry_run_log" | jq -Rs '.')
        apply_log_json=$(printf '%s' "$apply_log_file" | jq -Rs '.')
        echo "{\"status\":\"error\",\"dry_run_log\":${dry_run_log_json},\"apply_log\":${apply_log_json},\"conflicts\":${conflicts},\"users_migrated\":0,\"duration_s\":${duration_s}}"
        return 1
    fi

    # =========================================================================
    # PASO 6: Postcondicion — comparar usuarios en MAS vs Synapse
    # =========================================================================
    echo "mas_syn2mas_migration: verificando postcondicion (usuarios MAS vs Synapse)..." >&2

    local mas_user_count=0
    local synapse_user_count=0
    local users_migrated=0
    local post_status="ok"

    # Contar usuarios en MAS via mas-cli admin user list
    local mas_count_raw
    mas_count_raw=$(ssh "$ssh_host" \
        "docker exec '${mas_container}' mas-cli manage list-users --json 2>/dev/null | jq length" \
        2>/dev/null || echo "0")

    if [[ "$mas_count_raw" =~ ^[0-9]+$ ]]; then
        mas_user_count=$mas_count_raw
    else
        echo "mas_syn2mas_migration: ADVERTENCIA — no se pudo obtener conteo de usuarios MAS (output: ${mas_count_raw})" >&2
        post_status="ok"  # No abortar, solo advertir
    fi

    # Contar usuarios locales en Synapse via psql (excluyendo bots/AS)
    # Intentamos obtener el count; si falla, continuamos sin abortar
    local synapse_count_raw
    synapse_count_raw=$(ssh "$ssh_host" \
        "docker exec '${mas_container}' mas-cli syn2mas --synapse-config '${container_config}' --dry-run 2>&1 | grep -oE 'Found [0-9]+ users' | grep -oE '[0-9]+' | head -1" \
        2>/dev/null || echo "0")

    if [[ "$synapse_count_raw" =~ ^[0-9]+$ ]]; then
        synapse_user_count=$synapse_count_raw
    fi

    users_migrated=$mas_user_count

    # Si tenemos ambos counts y difieren significativamente, marcar como warning en log
    if [[ $synapse_user_count -gt 0 && $mas_user_count -eq 0 ]]; then
        echo "mas_syn2mas_migration: ADVERTENCIA — MAS reporta 0 usuarios pero Synapse tenia ${synapse_user_count}" >&2
        post_status="error"
    fi

    echo "mas_syn2mas_migration: postcondicion: mas_users=${mas_user_count} synapse_users=${synapse_user_count} status=${post_status}" >&2

    # =========================================================================
    # PASO 7: Emitir JSON final
    # =========================================================================
    local dry_run_log_json apply_log_json
    dry_run_log_json=$(printf '%s' "$dry_run_log" | jq -Rs '.')
    apply_log_json=$(printf '%s' "$apply_log_file" | jq -Rs '.')

    echo "{\"status\":\"${post_status}\",\"dry_run_log\":${dry_run_log_json},\"apply_log\":${apply_log_json},\"conflicts\":${conflicts},\"users_migrated\":${users_migrated},\"duration_s\":${duration_s}}"
    return 0
}

# Ejecutar si se llama directamente (no sourced)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    mas_syn2mas_migration "$@"
fi
