#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Detecta duplicados de pacientes por telefono + similitud de nombre.
Solo lee; genera /root/migracion/reporte_duplicados.csv para revision."""

import csv
import re
import unicodedata
import difflib
import xmlrpc.client

c = xmlrpc.client.ServerProxy('http://localhost:8069/xmlrpc/2/common')
uid = c.authenticate('skeen_odoo', 'admin', 'skeen_admin_2026', {})
m = xmlrpc.client.ServerProxy('http://localhost:8069/xmlrpc/2/object')


def kw(model, method, args, kwar=None):
    return m.execute_kw('skeen_odoo', uid, 'skeen_admin_2026', model, method, args, kwar or {})


def norm_name(s):
    s = unicodedata.normalize('NFKD', s or '')
    s = ''.join(ch for ch in s if not unicodedata.combining(ch))
    s = re.sub(r'[^a-z0-9 ]', ' ', s.lower())
    return ' '.join(sorted(s.split()))  # orden independiente


def norm_phone(p):
    return re.sub(r'\D', '', p or '')


FIELDS = ['id', 'name', 'phone', 'email', 'birth_date', 'legacy_id',
          'total_visits', 'last_visit', 'create_date', 'active']

patients = []
offset = 0
while True:
    batch = kw('res.partner', 'search_read',
               [[['is_patient', '=', True]]],
               {'fields': FIELDS, 'limit': 1000, 'offset': offset, 'order': 'id'})
    if not batch:
        break
    patients.extend(batch)
    offset += len(batch)
print(f'Pacientes leidos: {len(patients)}')

# Agrupar por telefono
by_phone = {}
for p in patients:
    ph = norm_phone(p['phone'])
    if ph:
        by_phone.setdefault(ph, []).append(p)

reporte = []
grupos_dup = 0
grupos_familia = 0
for phone, group in sorted(by_phone.items()):
    if len(group) < 2:
        continue
    names = [norm_name(p['name']) for p in group]
    # similitud maxima dentro del grupo
    max_ratio = 0.0
    for i in range(len(names)):
        for j in range(i + 1, len(names)):
            max_ratio = max(max_ratio, difflib.SequenceMatcher(None, names[i], names[j]).ratio())
    tipo = 'duplicado_probable' if max_ratio >= 0.80 else 'telefono_compartido'
    if tipo == 'duplicado_probable':
        grupos_dup += 1
    else:
        grupos_familia += 1
    # candidato a conservar: mas visitas, luego mas antiguo
    canon = sorted(group, key=lambda p: (-(p['total_visits'] or 0), p['create_date']))[0]
    for p in group:
        reporte.append({
            'telefono': phone,
            'tipo': tipo,
            'similitud_nombre': f'{max_ratio:.2f}',
            'conservar': 'SI' if p['id'] == canon['id'] else '',
            'id': p['id'],
            'nombre': p['name'],
            'email': p['email'] or '',
            'fecha_nac': p['birth_date'] or '',
            'visitas': p['total_visits'] or 0,
            'ultima_visita': p['last_visit'] or '',
            'legacy_id': p['legacy_id'] or '',
            'creado': p['create_date'],
        })

# Nombres identicos con telefonos distintos (posible duplicado extra)
by_name = {}
for p in patients:
    n = norm_name(p['name'])
    if len(n) >= 8:
        by_name.setdefault(n, []).append(p)
extra = 0
for name, group in by_name.items():
    phones = {norm_phone(p['phone']) for p in group}
    if len(group) > 1 and len(phones) > 1:
        extra += 1
        canon = sorted(group, key=lambda p: (-(p['total_visits'] or 0), p['create_date']))[0]
        for p in group:
            reporte.append({
                'telefono': norm_phone(p['phone']),
                'tipo': 'mismo_nombre_distinto_telefono',
                'similitud_nombre': '1.00',
                'conservar': 'SI' if p['id'] == canon['id'] else '',
                'id': p['id'],
                'nombre': p['name'],
                'email': p['email'] or '',
                'fecha_nac': p['birth_date'] or '',
                'visitas': p['total_visits'] or 0,
                'ultima_visita': p['last_visit'] or '',
                'legacy_id': p['legacy_id'] or '',
                'creado': p['create_date'],
            })

out = '/root/migracion/reporte_duplicados.csv'
with open(out, 'w', encoding='utf-8', newline='') as f:
    w = csv.DictWriter(f, fieldnames=['telefono', 'tipo', 'similitud_nombre', 'conservar',
                                      'id', 'nombre', 'email', 'fecha_nac', 'visitas',
                                      'ultima_visita', 'legacy_id', 'creado'])
    w.writeheader()
    w.writerows(reporte)

dup_rows = [r for r in reporte if r['tipo'] == 'duplicado_probable']
print(f'\nGrupos por telefono con duplicado probable: {grupos_dup} ({len(dup_rows)} registros)')
print(f'Grupos telefono compartido (familia): {grupos_familia}')
print(f'Grupos mismo nombre, distinto telefono: {extra}')
print(f'\nReporte: {out} ({len(reporte)} filas)')
print('\nMuestra de duplicados probables:')
shown = set()
for r in dup_rows[:20]:
    key = r['telefono']
    if key not in shown:
        print(f"  tel {key}:")
        shown.add(key)
    print(f"    [{'CONSERVAR' if r['conservar'] else 'fusionar '}] id={r['id']} {r['nombre']} (visitas={r['visitas']})")
