#!/usr/bin/env bash
# create_chrome_profile — crea un perfil Chrome/Chromium nuevo en un user-data-dir,
# opcionalmente lanzando chromium headless para que la managed policy instale las
# extensiones forzadas (uBlock, web_proxy). Edita Local State para asignar el nombre
# legible al perfil.

set -euo pipefail

create_chrome_profile() {
    # ── defaults ──────────────────────────────────────────────────────────────
    local _udd=""
    local _profile_dir=""
    local _name=""
    local _port=9250
    local _chrome_path=""
    local _no_launch=0
    local _timeout_sec=25
    local _dry_run=0

    # ── parse args ─────────────────────────────────────────────────────────────
    _usage() {
        cat >&2 <<'EOF'
Usage: create_chrome_profile --user-data-dir <dir> --profile <dir-name> --name <legible>
           [--port N] [--chrome-path <path>] [--no-launch] [--timeout-sec N] [--dry-run]

  --user-data-dir    Raíz del user-data-dir de Chrome/Chromium (obligatorio).
  --profile          Nombre de la carpeta del perfil dentro de user-data-dir, ej: Default,
                     "Profile 1", Automation (obligatorio).
  --name             Nombre legible que aparece en el selector de perfil, ej: Work, Aurgi
                     (obligatorio).
  --port             Puerto CDP para el lanzamiento headless. Default: 9250.
                     Usar un puerto distinto al 9222 global para no chocar.
  --chrome-path      Ruta explícita al binario chromium/chrome. Auto-detecta si se omite.
  --no-launch        No lanza chromium. Crea la carpeta y edita Local State offline.
                     El perfil no tendrá extensiones instaladas; útil para tests/CRUD.
  --timeout-sec      Segundos esperando a que Preferences aparezca tras el lanzamiento.
                     Default: 25.
  --dry-run          Describe las acciones sin lanzar ni escribir nada.

Exit codes:
  0  éxito
  1  error de argumento o validación
  2  lock: ya hay un chromium usando este user-data-dir
  3  timeout esperando a que Preferences se cree
  4  error editando Local State (JSON inválido tras escritura)
EOF
        return 1
    }

    while [[ $# -gt 0 ]]; do
        case "$1" in
            --user-data-dir)  _udd="$2";         shift 2 ;;
            --profile)        _profile_dir="$2"; shift 2 ;;
            --name)           _name="$2";         shift 2 ;;
            --port)           _port="$2";         shift 2 ;;
            --chrome-path)    _chrome_path="$2";  shift 2 ;;
            --no-launch)      _no_launch=1;        shift   ;;
            --timeout-sec)    _timeout_sec="$2";  shift 2 ;;
            --dry-run)        _dry_run=1;          shift   ;;
            -h|--help)        _usage; return 0 ;;
            *) echo "create_chrome_profile: argumento desconocido: $1" >&2; return 1 ;;
        esac
    done

    # ── validaciones obligatorias ──────────────────────────────────────────────
    if [[ -z "$_udd" ]]; then
        echo "create_chrome_profile: --user-data-dir es obligatorio" >&2
        return 1
    fi
    if [[ -z "$_profile_dir" ]]; then
        echo "create_chrome_profile: --profile es obligatorio" >&2
        return 1
    fi
    if [[ -z "$_name" ]]; then
        echo "create_chrome_profile: --name es obligatorio" >&2
        return 1
    fi

    local _profile_path="${_udd}/${_profile_dir}"
    local _local_state="${_udd}/Local State"
    local _prefs_file="${_profile_path}/Preferences"

    # ── guard: lock por user-data-dir ─────────────────────────────────────────
    # Dos procesos chromium no pueden compartir el mismo user-data-dir.
    if [[ $_dry_run -eq 0 && $_no_launch -eq 0 ]]; then
        local _singleton="${_udd}/SingletonLock"
        if [[ -e "$_singleton" ]]; then
            echo "create_chrome_profile: ya hay un chromium corriendo con --user-data-dir=${_udd}" >&2
            echo "  (encontrado: ${_singleton})" >&2
            echo "  Ciérralo o usa un user-data-dir distinto." >&2
            return 2
        fi
    fi

    # ── detección del binario chromium ────────────────────────────────────────
    local _bin=""
    if [[ -n "$_chrome_path" ]]; then
        if [[ ! -x "$_chrome_path" ]]; then
            echo "create_chrome_profile: binario no encontrado o no ejecutable: ${_chrome_path}" >&2
            return 1
        fi
        _bin="$_chrome_path"
    elif [[ $_no_launch -eq 0 ]]; then
        for _candidate in chromium chromium-browser google-chrome brave-browser; do
            if command -v "$_candidate" &>/dev/null; then
                _bin="$_candidate"
                break
            fi
        done
        if [[ -z "$_bin" ]]; then
            echo "create_chrome_profile: no se encontró binario chromium en PATH" >&2
            echo "  Probados: chromium, chromium-browser, google-chrome, brave-browser" >&2
            echo "  Usa --chrome-path o --no-launch." >&2
            return 1
        fi
    fi

    # ── modo dry-run ──────────────────────────────────────────────────────────
    if [[ $_dry_run -eq 1 ]]; then
        echo "=== create_chrome_profile DRY-RUN ===" >&2
        echo "  user-data-dir : ${_udd}" >&2
        echo "  profile       : ${_profile_dir}" >&2
        echo "  name          : ${_name}" >&2
        if [[ $_no_launch -eq 1 ]]; then
            echo "  modo          : --no-launch (sin chromium)" >&2
            echo "  acciones      : mkdir -p ${_profile_path}" >&2
            echo "                  editar ${_local_state} → info_cache + profiles_order" >&2
        else
            echo "  binario       : ${_bin}" >&2
            echo "  puerto CDP    : ${_port}" >&2
            echo "  timeout       : ${_timeout_sec}s" >&2
            echo "  acciones      : systemd-run unit=create-prof-<rand> chromium headless" >&2
            echo "                  poll Preferences hasta ${_timeout_sec}s" >&2
            echo "                  systemctl --user stop unit" >&2
            echo "                  editar ${_local_state} → info_cache + profiles_order" >&2
        fi
        printf '{"profile":"%s","name":"%s","launched":false,"preferences_created":false,"dry_run":true}\n' \
            "$_profile_dir" "$_name"
        return 0
    fi

    # ── crear directorio del perfil ───────────────────────────────────────────
    mkdir -p "$_profile_path"

    # ── también asegurar que user-data-dir existe ──────────────────────────────
    mkdir -p "$_udd"

    # ── modo --no-launch: solo estructura + Local State ────────────────────────
    local _launched=false
    local _prefs_created=false

    if [[ $_no_launch -eq 1 ]]; then
        _update_local_state "$_udd" "$_local_state" "$_profile_dir" "$_name"
        if [[ -f "$_prefs_file" ]]; then
            _prefs_created=true
        fi
        printf '{"profile":"%s","name":"%s","launched":false,"preferences_created":%s}\n' \
            "$_profile_dir" "$_name" "$_prefs_created"
        return 0
    fi

    # ── lanzar chromium headless vía systemd-run ──────────────────────────────
    # systemd-run --user aísla el proceso del cgroup del agente (evita exit-144).
    # NO se pasa --disable-extensions para que la managed policy instale las
    # extensiones force-listed (uBlock, web_proxy).
    local _rand
    _rand="$(tr -dc 'a-z0-9' </dev/urandom | head -c 8 2>/dev/null || echo "$$")"
    local _unit="create-prof-${_rand}"

    systemd-run \
        --user \
        --collect \
        --unit="$_unit" \
        --setenv=DISPLAY=:0 \
        --setenv=XAUTHORITY="${HOME}/.Xauthority" \
        "$_bin" \
        "--user-data-dir=${_udd}" \
        "--profile-directory=${_profile_dir}" \
        "--headless=new" \
        "--no-first-run" \
        "--remote-debugging-port=${_port}" \
        "--remote-allow-origins=*" \
        "about:blank" 2>/dev/null || true

    _launched=true

    # ── poll: esperar a que Preferences exista ────────────────────────────────
    local _elapsed=0
    while [[ $_elapsed -lt $_timeout_sec ]]; do
        if [[ -f "$_prefs_file" ]]; then
            _prefs_created=true
            break
        fi
        sleep 1
        (( _elapsed++ )) || true
    done

    # ── detener el unit Y matar TODO el árbol de chromium de este udd ───────────
    # Necesario para poder editar Local State sin que Chrome lo sobreescriba. Ni el
    # `systemctl stop` ni un `pkill -f --user-data-dir=` bastan: los procesos hijos
    # (zygote/gpu/renderer) no repiten el flag --user-data-dir pero sí referencian la
    # ruta del user-data-dir en otros argumentos. Los matamos por PID seleccionando
    # los procesos chromium cuyo cmdline contiene la ruta del udd (seguro: no mata
    # este propio script porque filtramos por '[c]hromium').
    systemctl --user kill -s SIGKILL "$_unit" 2>/dev/null || true
    systemctl --user stop "$_unit" 2>/dev/null || true
    # Matar por PID los procesos cuyo comm es exactamente "chromium" (pgrep -x) y cuyo cmdline
    # contiene la ruta del udd. Usamos pgrep -x para NO auto-matchear grep/pgrep: el path del udd
    # contiene la cadena "chromium" (~/.config/chromium-cdp).
    local _wait=0 _p _pids
    while :; do
        _pids=""
        for _p in $(pgrep -x chromium 2>/dev/null); do
            tr '\0' ' ' < "/proc/$_p/cmdline" 2>/dev/null | grep -qF -- "$_udd" && _pids="$_pids $_p"
        done
        [[ -z "${_pids// }" ]] && break
        # shellcheck disable=SC2086
        kill -TERM $_pids 2>/dev/null || true
        sleep 0.5
        (( _wait++ )) || true
        if [[ $_wait -ge 20 ]]; then
            # shellcheck disable=SC2086
            kill -9 $_pids 2>/dev/null || true
            break
        fi
    done
    rm -f "${_udd}/SingletonLock" 2>/dev/null || true

    if [[ "$_prefs_created" == false ]]; then
        echo "create_chrome_profile: timeout (${_timeout_sec}s) esperando a que se cree: ${_prefs_file}" >&2
        echo "  El directorio del perfil puede existir pero está vacío." >&2
        printf '{"profile":"%s","name":"%s","launched":true,"preferences_created":false,"error":"timeout"}\n' \
            "$_profile_dir" "$_name"
        return 3
    fi

    # ── editar Local State para asignar nombre legible ────────────────────────
    _update_local_state "$_udd" "$_local_state" "$_profile_dir" "$_name"

    printf '{"profile":"%s","name":"%s","launched":true,"preferences_created":true}\n' \
        "$_profile_dir" "$_name"
}

# ── helper: editar Local State con python3 ────────────────────────────────────
# Crea/actualiza info_cache.<profile_dir> con name + is_using_default_name=false
# y añade profile_dir a profiles_order si no está.
_update_local_state() {
    local _udd="$1"
    local _local_state="$2"
    local _profile_dir="$3"
    local _name="$4"
    local _today
    _today="$(date +%Y%m%d)"

    # Si Local State no existe, crear una estructura mínima
    if [[ ! -f "$_local_state" ]]; then
        printf '{"profile":{"info_cache":{},"profiles_order":[]}}\n' > "$_local_state"
    fi

    # Backup antes de modificar (no sobreescribir el del mismo día)
    local _backup="${_local_state}.bak.${_today}"
    if [[ ! -f "$_backup" ]]; then
        cp "$_local_state" "$_backup"
    fi

    # Editar con python3
    if ! python3 - "$_local_state" "$_profile_dir" "$_name" <<'PY'; then
import sys, json

ls_path    = sys.argv[1]
prof_dir   = sys.argv[2]
prof_name  = sys.argv[3]

with open(ls_path, "r", encoding="utf-8") as f:
    data = json.load(f)

# Asegurar estructura profile
profile_section = data.setdefault("profile", {})
info_cache = profile_section.setdefault("info_cache", {})

# Crear o actualizar la entrada del perfil en info_cache
entry = info_cache.setdefault(prof_dir, {})
entry["name"] = prof_name
entry["is_using_default_name"] = False

# Añadir a profiles_order si no está
order = profile_section.setdefault("profiles_order", [])
if prof_dir not in order:
    order.append(prof_dir)

with open(ls_path, "w", encoding="utf-8") as f:
    json.dump(data, f, separators=(",", ":"))
PY
        echo "create_chrome_profile: error editando Local State con python3" >&2
        return 4
    fi

    # Validar JSON tras escritura
    if ! python3 -c "import json,sys; json.load(open(sys.argv[1]))" "$_local_state" 2>/dev/null; then
        echo "create_chrome_profile: JSON inválido tras escribir Local State; restaurando backup" >&2
        cp "$_backup" "$_local_state"
        return 4
    fi
}

# ── auto-ejecución ────────────────────────────────────────────────────────────
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    create_chrome_profile "$@"
fi
