import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'pylibs'))
import openpyxl, re
from datetime import datetime, date

OUT_DIR = os.path.dirname(os.path.abspath(__file__))

# ── Fecha de corte (argv[1]) y ruta del Excel (argv[2]) ──────────────────────
if len(sys.argv) > 1:
    CUT = date(*map(int, sys.argv[1].split('-')))
else:
    CUT = date(2026, 6, 30)

XLSX_PATH = sys.argv[2] if len(sys.argv) > 2 else r'C:\juicios 2026.xlsx'
wb = openpyxl.load_workbook(XLSX_PATH, data_only=True)

TODAY = date.today()

# ── Helpers SQL ───────────────────────────────────────────────────────────────
def q(v, maxlen=None):
    if v is None: return 'NULL'
    v = str(v).strip()
    if not v or v.lower() == 'none': return 'NULL'
    if maxlen and len(v) > maxlen: v = v[:maxlen]
    return "'" + v.replace("\\","\\\\").replace("'","\\'").replace("\r","").replace("\n"," | ") + "'"

def qd(v):
    if v is None: return 'NULL'
    if isinstance(v, (datetime, date)):
        d = v.date() if isinstance(v, datetime) else v
        return "'" + d.strftime('%Y-%m-%d') + "'"
    s = str(v).strip()
    if len(s) >= 10 and s[:4].isdigit(): return "'" + s[:10] + "'"
    return 'NULL'

def qi(v, default='NULL', maxval=None):
    if v is None: return default
    try:
        n = int(float(str(v)))
        if maxval is not None and n > maxval: return 'NULL'
        return str(n)
    except: return default

def count_imputados(v):
    """Infiere cantidad: separadores son ';' o ' y ' (no coma — va dentro del apellido)."""
    if not v: return 1
    s = str(v).strip()
    if not s: return 1
    parts = re.split(r';|\s+y\s+', s)
    return max(1, len([p for p in parts if p.strip()]))

def get_date(v):
    if v is None: return None
    if isinstance(v, (datetime, date)):
        return v.date() if isinstance(v, datetime) else v
    try:
        s = str(v).strip()
        if len(s) >= 10: return datetime.strptime(s[:10], '%Y-%m-%d').date()
    except: pass
    return None

def norm_est_imp(v):
    if not v: return 'En libertad'
    v = str(v).upper().strip()
    if 'PRESO' in v: return 'Preso'
    if 'REBELDE' in v: return 'Rebelde'
    return 'En libertad'

AA_ESTADO_MAP = {
    'en espera':     'En espera',
    'para agendar':  'Para Agendar',
    'programado':    'Programado',
    'agendado':      'Agendado',
    'sobreagendado': 'Sobreagendado',
    'realizado':     'Realizado',
    'abreviado':     'Abreviado',
    'cancelado':     'Cancelado',
}
def norm_estado_aa(v):
    if not v: return 'Para Agendar'
    return AA_ESTADO_MAP.get(str(v).strip().lower(), 'Para Agendar')

def norm_tipo_tribunal(v):
    if not v: return 'Pluripersonal'
    s = str(v).strip().lower()
    if 'unipersonal' in s:          return 'Unipersonal'
    if 'jurado' in s:               return 'Juicio por Jurados'
    return 'Pluripersonal'

def norm_condicion(cond, sub):
    cond = str(cond or '').strip().upper()
    sub  = str(sub  or '').strip()
    if 'SOB' in cond or 'SOBRE' in cond:
        sc = sub if sub else cond
        return ('SobreAgendado', sc)
    return ('Titular', 'Titular')

def get(ws, r, c):
    return ws.cell(r, c).value if c else None

# ── Name parsing ──────────────────────────────────────────────────────────────
SKIP_TOKENS = {
    'mpd','mpa','privado','publico','público','mpd/privado','renuncio','renunció',
    'sd','s/d','abrevio','abrevió','no','tiene','ver','mail','en','fecha',
    'y','de','la','los','ex','lic','dr','dra','sppdp','mpdp',
}

def parse_names(raw):
    if not raw: return []
    s = str(raw)
    s = re.sub(r'\([^)]*\)', ' ', s)
    s = re.sub(r'\d{1,2}/\d{1,2}(/\d{2,4})?', ' ', s)
    parts = re.split(r'[,;]', s)
    result = []
    for p in parts:
        p = p.strip()
        if not p: continue
        first = re.split(r'[\s]+', p)[0].strip()
        first = re.sub(r'[^a-zA-ZáéíóúÁÉÍÓÚñÑüÜ]', '', first)
        if len(first) < 3: continue
        if first.lower() in SKIP_TOKENS: continue
        result.append(first)
    return result

def safe_var(name, prefix):
    s = re.sub(r'[^A-Z0-9]', '_', name.upper())[:20]
    return f'@{prefix}_{s}'

def juez_var(name):
    """Devuelve la variable SQL para un juez. INTERDISTRITAL N → 'J900' directo."""
    if not name: return 'NULL'
    s = str(name).strip()
    if not s: return 'NULL'
    if re.search(r'interdistrital', s, re.IGNORECASE):
        return "'J900'"
    return '@j_' + re.sub(r'[^A-Z0-9]', '_', s.upper())

# ── Column maps ───────────────────────────────────────────────────────────────
J26 = dict(
    cuij=23, imputados=3, delitos=4, condicion=5, sub_condicion=6,
    estado_imputado=7, estado=9, testigos=11, jornadas=12,
    extras=13, pre_alegatos=14, duplicidad=15, turno=16,
    debate_desde=18, debate_hasta=19, fallo=20, bloqueo=21,
    tipo_tribunal=24,
    presidencia=25, vocal1=26, vocal2=27, tribunal_orig=28,
    intervinieron=29, col_mpa=30, col_mpa2=31, col_mpa3=32,
    col_quer=33, col_mpd=34,
    col_def_pub=35, col_def_pub_orig=36, col_def_part=37, col_def_part_orig=38,
    observaciones=40, medidas_flag=41, medidas_det=42,
    fecha_acusacion=43, fecha_preliminar=44, fecha_res_prel=45,
    fecha_aa=46, fecha_ingreso=47, motivo_no_ag=48,
    fecha_det=49, venc_pp2=50, venc_pp3=51, venc_pp=52,
    pena_anios=56, pena_meses=57,
    delito_menor=59, art_menor=60, pres_menor_anios=61, pres_menor_meses=62,
    uf_menor=63, fecha_pres_menor=64,
    delito_mayor=68, art_mayor=69, pres_mayor_anios=70, pres_mayor_meses=71,
    uf_mayor=72, fecha_pres_mayor=73,
)


# Mapa de estados del Excel → enum agj_agendamientos.estado
AG_ESTADO_MAP = {
    'programado': 'Programado',
    'agendado':   'Agendado',
    'cancelado':  'Cancelado',
    'suspendido': 'Suspendido',
    'realizado':  'Realizado',
    'abreviado':  'Realizado',   # 'Abreviado' no existe en el enum → se guarda como Realizado
}

# ── Collect rows ──────────────────────────────────────────────────────────────
rows_data = []
read_errors = []

for sname, cols, insert_ag in [
    ('Juicios2026', J26, True),
]:
    ws = wb[sname]
    for r in range(2, ws.max_row+1):
        try:
            raw_cuij = get(ws, r, cols['cuij'])
            if not raw_cuij: continue
            estado = str(get(ws, r, cols['estado']) or '').strip()
            cuij_raw = str(raw_cuij).strip()
            cuij_parts = re.findall(r'\d{2}-\d{7,9}-\d', cuij_raw)
            if not cuij_parts:
                cuij_parts = [c.strip() for c in re.split(r'[,|\s]+', cuij_raw) if c.strip()]
            cuij_principal = cuij_parts[0] if cuij_parts else cuij_raw[:15]
            otros = ', '.join(cuij_parts[1:]) if len(cuij_parts) > 1 else None
            fecha_aa_val = get(ws, r, cols['fecha_aa']) or get(ws, r, cols['fecha_ingreso'])
            if not get_date(fecha_aa_val):
                read_errors.append(f'[{sname}] Fila {r} | {cuij_principal} | Sin fecha de AA válida')
                continue
            debate_desde_dt = get_date(get(ws, r, cols['debate_desde']))
            pres_raw = get(ws, r, cols.get('presidencia'))
            has_tribunal = bool(pres_raw and str(pres_raw).strip())
            do_ag = False
            ag_estado = None
            if insert_ag and debate_desde_dt is not None and debate_desde_dt <= CUT:
                do_ag = True
                ag_estado = AG_ESTADO_MAP.get(estado.lower(), 'Programado')
                if not has_tribunal:
                    read_errors.append(f'[{sname}] Fila {r} | {cuij_principal} | Agendamiento sin tribunal asignado (se importa con tribunal vacío)')
            rows_data.append((cuij_principal, otros, cols, ws, r, do_ag, ag_estado, sname, debate_desde_dt))
        except Exception as e:
            read_errors.append(f'[{sname}] Fila {r} | — | Lectura: {e}')

# ── Collect unique names (dict name→primera_fila) ────────────────────────────
juez_names   = {}
fiscal_names = {}
def_names    = {}
quer_names   = {}

for row in rows_data:
    cuij_principal, otros, cols, ws, r, do_ag, ag_estado, sname, debate_desde_dt = row
    def g(k): return get(ws, r, cols.get(k))
    for k, label in [('presidencia','Presidencia'), ('vocal1','Vocal 1'), ('vocal2','Vocal 2')]:
        v = g(k)
        if v:
            vs = str(v).strip()
            if vs and not re.search(r'interdistrital', vs, re.IGNORECASE):
                juez_names.setdefault(vs, (r, label))
    for name in parse_names(g('intervinieron')):
        juez_names.setdefault(name, (r, 'Intervinieron'))
    for k, label in [('col_mpa','MPA'), ('col_mpa2','MPA2'), ('col_mpa3','MPA3')]:
        for name in parse_names(g(k)):
            fiscal_names.setdefault(name, (r, label))
    for name in parse_names(g('col_quer')):
        quer_names.setdefault(name, (r, 'Querellante'))
    for name in parse_names(g('col_def_pub')):
        def_names.setdefault(name, (r, 'Def. Público'))
    for name in parse_names(g('col_def_part')):
        def_names.setdefault(name, (r, 'Def. Particular'))

# ── Generate SQL ──────────────────────────────────────────────────────────────
lines = []
lines.append('-- ============================================================')
lines.append('-- Script 02: DML -- AAs, Agendamientos, Litigantes, Jueces IPP')
lines.append('-- Origen: juicios 2026.xlsx | Hoja: Juicios2026')
lines.append(f'-- Fecha de corte: {CUT} | Generado: {TODAY}')
lines.append(f'-- Filas leídas: {len(rows_data)}')
lines.append('-- ============================================================')
lines.append('')
lines.append('SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;')
lines.append('SET FOREIGN_KEY_CHECKS = 0;')
lines.append('')

lines.append('-- ── Jueces (tribunal + IPP) ─────────────────────────────────────────────────')
for name in sorted(juez_names):
    safe = re.sub(r'[^A-Z0-9]', '_', name.upper())
    safe_like = name.replace("'", "\\'")
    lines.append(f"SET @j_{safe} = (SELECT juez_id FROM mrbs_juez WHERE nombre LIKE '%{safe_like}%' ORDER BY juez_id LIMIT 1);")
lines.append('')

lines.append('-- ── Fiscales ────────────────────────────────────────────────────────────────')
for name in sorted(fiscal_names):
    var = safe_var(name, 'f')
    sl  = name.replace("'", "\\'")
    lines.append(f"SET {var} = (SELECT litigante_id FROM v_litigantes WHERE nombre LIKE '%{sl}%' AND rol='Fiscal' ORDER BY litigante_id LIMIT 1);")
lines.append('')

lines.append('-- ── Querellantes ────────────────────────────────────────────────────────────')
for name in sorted(quer_names):
    var = safe_var(name, 'q')
    sl  = name.replace("'", "\\'")
    lines.append(f"SET {var} = (SELECT litigante_id FROM v_litigantes WHERE nombre LIKE '%{sl}%' AND rol='Defensor Privado' ORDER BY litigante_id LIMIT 1);")
lines.append('')

lines.append('-- ── Defensores ──────────────────────────────────────────────────────────────')
for name in sorted(def_names):
    var = safe_var(name, 'd')
    sl  = name.replace("'", "\\'")
    lines.append(f"SET {var} = (SELECT litigante_id FROM v_litigantes WHERE nombre LIKE '%{sl}%' AND rol IN ('Defensor Público','Defensor Privado') ORDER BY litigante_id LIMIT 1);")
lines.append('')

# ── Tabla temporal: registrar variables que no se resuelvan en BD ─────────────
lines.append('-- ── Verificación: litigantes/jueces no encontrados en BD ──────────────────')
lines.append('CREATE TEMPORARY TABLE IF NOT EXISTS _nf (tipo VARCHAR(20), nombre VARCHAR(200), fila INT, columna VARCHAR(50)) ENGINE=MEMORY;')
for name, (fila, col) in sorted(juez_names.items()):
    safe = re.sub(r'[^A-Z0-9]', '_', name.upper())
    lines.append(f"INSERT INTO _nf SELECT 'Juez', {q(name)}, {fila}, {q(col)} FROM DUAL WHERE @j_{safe} IS NULL;")
for name, (fila, col) in sorted(fiscal_names.items()):
    safe = re.sub(r'[^A-Z0-9]', '_', name.upper())[:20]
    lines.append(f"INSERT INTO _nf SELECT 'Fiscal', {q(name)}, {fila}, {q(col)} FROM DUAL WHERE @f_{safe} IS NULL;")
for name, (fila, col) in sorted(quer_names.items()):
    safe = re.sub(r'[^A-Z0-9]', '_', name.upper())[:20]
    lines.append(f"INSERT INTO _nf SELECT 'Querellante', {q(name)}, {fila}, {q(col)} FROM DUAL WHERE @q_{safe} IS NULL;")
for name, (fila, col) in sorted(def_names.items()):
    safe = re.sub(r'[^A-Z0-9]', '_', name.upper())[:20]
    lines.append(f"INSERT INTO _nf SELECT 'Defensor', {q(name)}, {fila}, {q(col)} FROM DUAL WHERE @d_{safe} IS NULL;")
lines.append('')

seen_cuijs = set()
aa_count   = 0
ag_count   = 0
gen_errors = []

for row in rows_data:
    cuij_principal, otros, cols, ws, r, do_ag, ag_estado, sname, debate_desde_dt = row
    is_dup = cuij_principal in seen_cuijs
    seen_cuijs.add(cuij_principal)

    row_lines = []
    try:
        def g(k): return get(ws, r, cols.get(k))
        fecha_aa_eff  = g('fecha_aa') or g('fecha_ingreso')
        estado_imp    = norm_est_imp(g('estado_imputado'))
        condicion, sub_condicion = norm_condicion(g('condicion'), g('sub_condicion'))
        med_flag = 1 if qi(g('medidas_flag')) == '1' else 0
        dup_flag = 1 if qi(g('duplicidad'))   == '2' else 0  # valor 2 → duplicidad activa
        cant_imp = str(count_imputados(g('imputados')))
        cant_det = '1' if estado_imp == 'Preso' else '0'
        ipp_names = parse_names(g('intervinieron'))
        juez_aa_var = ('NULL' if not ipp_names
                       else '@j_' + re.sub(r'[^A-Z0-9]', '_', ipp_names[0].upper())[:20])

        # Observaciones: texto base + defensores originales si hay datos
        obs_parts = []
        obs_val = g('observaciones')
        if obs_val and str(obs_val).strip():
            obs_parts.append(str(obs_val).strip())
        for k in ['col_def_pub_orig', 'col_def_part_orig']:
            v = g(k)
            if v and str(v).strip():
                obs_parts.append(str(v).strip())
        observaciones_final = '\n'.join(obs_parts) if obs_parts else None

        # Estado del AA: copiar textual si tiene debate dentro del corte; resto → 'Para Agendar'
        estado_aa = (norm_estado_aa(g('estado'))
                     if debate_desde_dt is not None and debate_desde_dt <= CUT
                     else 'Para Agendar')

        if not is_dup:
            row_lines.append(f'-- [{sname}] {cuij_principal}')
            row_lines.append("INSERT INTO agj_autos_apertura (")
            row_lines.append("  cuij_principal, otros_cuijs, imputados, cantidad_imputados, delitos,")
            row_lines.append("  fecha_acusacion, fecha_preliminar, fecha_resolucion_preliminar,")
            row_lines.append("  fecha_auto_apertura, fecha_ingreso_agenda, motivo_no_agendamiento,")
            row_lines.append("  testigos_aa, jornadas_en_aa, duplicidad_plazos,")
            row_lines.append("  estado_imputado, cantidad_detenidos, fecha_detencion,")
            row_lines.append("  vencimiento_pp_2, vencimiento_pp_3, vencimiento_pp_actual,")
            row_lines.append("  medidas_juzgado_familia, detalle_medidas_familia,")
            row_lines.append("  pena_solicitada_anios, pena_solicitada_meses,")
            row_lines.append("  delito_menor, articulos_delito_menor,")
            row_lines.append("  prescripcion_menor_anios, prescripcion_menor_meses,")
            row_lines.append("  ultima_interruptiva_menor, fecha_prescripcion_menor,")
            row_lines.append("  delito_mayor, articulos_delito_mayor,")
            row_lines.append("  prescripcion_mayor_anios, prescripcion_mayor_meses,")
            row_lines.append("  ultima_interruptiva_mayor, fecha_prescripcion_mayor,")
            row_lines.append("  observaciones, estado, prioridad, prioridad_agregada, tipo_tribunal, juez_aa_id")
            row_lines.append(") VALUES (")
            row_lines.append(f"  {q(cuij_principal,15)}, {q(otros)}, {q(g('imputados'),502)}, {cant_imp}, {q(g('delitos'))},")
            row_lines.append(f"  {qd(g('fecha_acusacion'))}, {qd(g('fecha_preliminar'))}, {qd(g('fecha_res_prel'))},")
            row_lines.append(f"  {qd(fecha_aa_eff)}, {qd(g('fecha_ingreso'))}, {q(g('motivo_no_ag'),300)},")
            row_lines.append(f"  {qi(g('testigos'),'0')}, {qi(g('jornadas'))}, {dup_flag},")
            row_lines.append(f"  {q(estado_imp)}, {cant_det}, {qd(g('fecha_det'))},")
            row_lines.append(f"  {qd(g('venc_pp2'))}, {qd(g('venc_pp3'))}, {qd(g('venc_pp'))},")
            row_lines.append(f"  {med_flag}, {q(g('medidas_det'),400)},")
            row_lines.append(f"  {qi(g('pena_anios'),maxval=127)}, {qi(g('pena_meses'),maxval=11)},")
            row_lines.append(f"  {q(g('delito_menor'),200)}, {q(g('art_menor'),100)},")
            row_lines.append(f"  {qi(g('pres_menor_anios'),maxval=99)}, {qi(g('pres_menor_meses'),maxval=11)},")
            row_lines.append(f"  {qd(g('uf_menor'))}, {qd(g('fecha_pres_menor'))},")
            row_lines.append(f"  {q(g('delito_mayor'),200)}, {q(g('art_mayor'),100)},")
            row_lines.append(f"  {qi(g('pres_mayor_anios'),maxval=99)}, {qi(g('pres_mayor_meses'),maxval=11)},")
            row_lines.append(f"  {qd(g('uf_mayor'))}, {qd(g('fecha_pres_mayor'))},")
            row_lines.append(f"  {q(observaciones_final)}, {q(estado_aa)}, 0, 0, {q(norm_tipo_tribunal(g('tipo_tribunal')))}, {juez_aa_var}")
            row_lines.append(");")
            row_lines.append("SET @aa_id = LAST_INSERT_ID();")

            # Jueces IPP (skip first — ya está en juez_aa_id)
            for i, jname in enumerate(ipp_names[1:], start=1):
                vname = '@j_' + re.sub(r'[^A-Z0-9]', '_', jname.upper())[:20]
                row_lines.append(f"INSERT IGNORE INTO agj_aa_jueces_ipp (aa_id, juez_id, orden) SELECT @aa_id, {vname}, {i} FROM DUAL WHERE {vname} IS NOT NULL;")

            # Fiscales (MPA, MPA2, MPA3)
            f_names = []
            for k in ['col_mpa', 'col_mpa2', 'col_mpa3']:
                f_names += parse_names(g(k))
            for i, fname in enumerate(f_names):
                var = safe_var(fname, 'f')
                row_lines.append(f"INSERT IGNORE INTO agj_aa_litigantes (aa_id, litigante_id, rol_en_causa, orden) SELECT @aa_id, {var}, 'Fiscal', {i+1} FROM DUAL WHERE {var} IS NOT NULL;")

            # Querellantes
            q_names = parse_names(g('col_quer'))
            for i, qname in enumerate(q_names):
                var = safe_var(qname, 'q')
                row_lines.append(f"INSERT IGNORE INTO agj_aa_litigantes (aa_id, litigante_id, rol_en_causa, orden) SELECT @aa_id, {var}, 'Querellante', {i+1} FROM DUAL WHERE {var} IS NOT NULL;")

            # Defensores (Defensor Público + Defensor Particular)
            d_ord = 1
            for col_key in ['col_def_pub', 'col_def_part']:
                for dname in parse_names(g(col_key)):
                    var = safe_var(dname, 'd')
                    row_lines.append(f"INSERT IGNORE INTO agj_aa_litigantes (aa_id, litigante_id, rol_en_causa, orden) SELECT @aa_id, {var}, 'Defensor', {d_ord} FROM DUAL WHERE {var} IS NOT NULL;")
                    d_ord += 1

            aa_count += 1

        else:
            row_lines.append(f'-- [{sname}] {cuij_principal} (2.º+ agendamiento — AA ya insertado)')
            row_lines.append(f"SET @aa_id = (SELECT id FROM agj_autos_apertura WHERE cuij_principal = {q(cuij_principal)} AND deleted_at IS NULL LIMIT 1);")
            if debate_desde_dt is not None and debate_desde_dt <= CUT:
                row_lines.append(f"UPDATE agj_autos_apertura SET estado = {q(estado_aa)} WHERE id = @aa_id AND estado = 'Para Agendar';")

        # Agendamiento
        if do_ag:
            jv_pte = juez_var(g('presidencia'))
            jv_v1  = juez_var(g('vocal1'))
            jv_v2  = juez_var(g('vocal2'))
            row_lines.append("INSERT INTO agj_agendamientos (")
            row_lines.append("  aa_id, condicion, sub_condicion, turno, estado,")
            row_lines.append("  jornadas, jornadas_extras, dia_pre_alegatos,")
            row_lines.append("  debate_desde, debate_hasta, fecha_fallo, fecha_fin_bloqueo,")
            row_lines.append("  presidente_id, vocal_1_id, vocal_2_id, tribunal_original")
            row_lines.append(") VALUES (")
            row_lines.append(f"  @aa_id, {q(condicion)}, {q(sub_condicion)}, {q(g('turno'))}, {q(ag_estado)},")
            row_lines.append(f"  {qi(g('jornadas'),'0')}, {qi(g('extras'),'0')}, {qi(g('pre_alegatos'),'0')},")
            row_lines.append(f"  {qd(g('debate_desde'))}, {qd(g('debate_hasta'))}, {qd(g('fallo'))}, {qd(g('bloqueo'))},")
            row_lines.append(f"  {jv_pte}, {jv_v1}, {jv_v2}, {q(g('tribunal_orig'),200)}")
            row_lines.append(");")
            # El trigger trg_ag_after_insert sobreescribe el estado del AA con 'Agendado'.
            # Si el estado correcto es terminal (Realizado, Abreviado, etc.), restaurarlo.
            if estado_aa not in ('Para Agendar', 'Programado', 'Agendado', 'Sobreagendado'):
                row_lines.append(f"UPDATE agj_autos_apertura SET estado = {q(estado_aa)} WHERE id = @aa_id;")
            ag_count += 1

        row_lines.append('')
        lines.extend(row_lines)

    except Exception as e:
        gen_errors.append(f'[{sname}] Fila {r} | {cuij_principal} | Generación: {e}')

# ── Actualizar estado de AAs según agendamientos ──────────────────────────────

lines.append('SET FOREIGN_KEY_CHECKS = 1;')
lines.append(f'-- Fin: {aa_count} AAs, {ag_count} agendamientos, {len(gen_errors)} errores de generación')

out = '\n'.join(lines)

# ── Script 01: borrar datos existentes ────────────────────────────────────────
borrar = [
    '-- Script 01: borrar datos existentes antes de la importación',
    f'-- Generado: {TODAY}',
    'SET FOREIGN_KEY_CHECKS = 0;',
    'DELETE FROM agj_aa_litigantes;',
    'DELETE FROM agj_aa_jueces_ipp;',
    'DELETE FROM agj_agendamientos;',
    'DELETE FROM agj_autos_apertura;',
    'SET FOREIGN_KEY_CHECKS = 1;',
]
with open(os.path.join(OUT_DIR, '01_borrar.sql'), 'w', encoding='utf-8') as f:
    f.write('\n'.join(borrar))

with open(os.path.join(OUT_DIR, '02_insertar.sql'), 'w', encoding='utf-8') as f:
    f.write(out)

# ── Log de errores (2 líneas de cabecera + errores) ───────────────────────────
all_errors = read_errors + gen_errors
log_path = os.path.join(OUT_DIR, 'import_errors.log')
with open(log_path, 'w', encoding='utf-8') as f:
    f.write(f'Generado: {TODAY} | Corte: {CUT} | {len(rows_data)} filas | {aa_count} AAs | {ag_count} agendamientos\n')
    f.write(f'{len(all_errors)} error(es) de lectura/generación\n')
    for err in all_errors:
        f.write(err + '\n')

print(f'Generado 02_insertar.sql: {aa_count} AAs, {ag_count} agendamientos, {len(out)//1024} KB')
if all_errors:
    print(f'AVISO: {len(all_errors)} errores -- ver import_errors.log')
else:
    print('Sin errores')
