---
name: contact_import_key
kind: function
lang: py
domain: core
version: "1.0.0"
purity: pure
signature: "def contact_import_key(name: str = \"\", phones: list = None, emails: list = None) -> str"
description: "Genera una clave de importacion determinista de contactos para imports idempotentes. La identidad prioriza el telefono normalizado (mas estable entre exports de Google), luego el email, y por ultimo el nombre normalizado sin acentos. Re-importar el mismo .vcf matchea la fila existente sin depender de UIDs opacos. Pura, sin I/O."
tags: [contactos, import, hash, dav, dedup, core]
params:
  - name: name
    desc: "Nombre del contacto (FN). Solo se usa como ultimo recurso cuando no hay telefono ni email. Se normaliza con NFKD (quita acentos), lowercase, espacios colapsados, y se filtra a [a-z0-9 ]."
  - name: phones
    desc: "Lista de telefonos en cualquier formato (con prefijos, espacios, guiones). Para cada uno se extraen solo los digitos (re.sub r'\\D') y se toman los ultimos 9 si len>=9 (numero nacional estable), o todos los digitos si son menos. Vacios descartados, dedup + sort ascendente. None equivale a lista vacia."
  - name: emails
    desc: "Lista de emails. Cada uno se pasa a strip+lowercase; se descartan los vacios y los que no contienen '@'. Dedup + sort. None equivale a lista vacia."
output: "Clave determinista con formato 'v1-' + los primeros 16 caracteres hex del SHA-1 de la identity string. Longitud total fija de 19 caracteres. La identity string es 'tel:<phones>' si hay telefonos, 'email:<emails>' si no hay telefonos pero si emails, o 'name:<name_norm>' en otro caso."
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
tested: true
tests: ["test_determinismo_misma_entrada_misma_clave", "test_estabilidad_ante_formato_y_nombre_distinto", "test_fallback_a_email_cuando_no_hay_telefono", "test_fallback_a_nombre_insensible_a_acentos_y_mayusculas", "test_prefijo_v1_y_longitud"]
test_file_path: "python/functions/core/contact_import_key_test.py"
file_path: "python/functions/core/contact_import_key.py"
---

## Ejemplo

```python
from core.contact_import_key import contact_import_key

# El telefono manda y es robusto al formato: estos dos producen la MISMA clave.
k1 = contact_import_key("Bob", ["+34 600 11 22 33"])
k2 = contact_import_key("BOB DISTINTO", ["600112233"])
print(k1, k1 == k2)
# v1-8d3f... True   (mismo telefono normalizado -> misma clave)

# Sin telefono, cae a email; sin email, cae al nombre normalizado.
print(contact_import_key("Carol", [], ["CAROL@Example.com"]))   # v1-... (identity = email:carol@example.com)
print(contact_import_key("José Pérez"))                          # == contact_import_key("jose perez")
```

## Cuando usarla

Usala en el nucleo de un import idempotente de contactos: antes de insertar una
fila de un `.vcf` de Google, calcula la clave y busca esa clave en la tabla
destino. Si existe, actualizas la fila; si no, la insertas. Asi re-importar el
mismo export no duplica contactos y no depende de UIDs opacos (que Google rota)
ni del nombre (que el pipeline de import transforma: quita sufijos de lugar,
reordena). Es la primitiva de matching del sistema de import idempotente del
grupo `dav`.

## Gotchas

- **Pura y determinista**: misma entrada -> misma salida, sin red ni disco. No
  lanza excepciones (entradas `None`/vacias se tratan como lista/cadena vacia).
- **Prioridad telefono > email > nombre por estabilidad**: el telefono
  normalizado es lo mas estable entre exports de Google, por eso es la identidad
  primaria; el email es fallback; el nombre es el ultimo recurso porque el
  pipeline de import lo transforma (quita sufijos de lugar, reordena) y no es
  fiable como identidad.
- **Cambiar los telefonos cambia la clave**: si los telefonos de un contacto
  varian entre dos importaciones, la clave cambia y se trata como contacto
  distinto. Es una limitacion aceptada: la idempotencia es robusta solo para
  contactos cuyos telefonos no varian. Lo mismo aplica al fallback de email y al
  de nombre.
- **Ultimos 9 digitos**: solo se conservan los ultimos 9 digitos del telefono
  para ignorar prefijos de pais inconsistentes (`+34`, `0034`, sin prefijo
  producen la misma clave). Numeros con menos de 9 digitos se usan completos.
- **Prefijo `v1-`**: versiona el algoritmo. Si en el futuro cambia la
  normalizacion o el esquema de identidad, se sube a `v2-` y las claves nuevas no
  colisionan con las viejas; el consumidor puede migrar de forma controlada.
