<?php
declare(strict_types=1);

require_once __DIR__ . '/../conexion.php';
require_once __DIR__ . '/../_helpers.php';
require_once __DIR__ . '/../auth/guard.php';

$u = require_login();
require_module_write($u, "usuarios");
fp_ensure_percapita_columns($pdo);

function fp_detect_delimiter(string $line): string {
  $candidates = [";", ",", "\t", "|"];
  $best = ";";
  $bestCount = -1;
  foreach ($candidates as $d) {
    $count = substr_count($line, $d);
    if ($count > $bestCount) { $best = $d; $bestCount = $count; }
  }
  return $best;
}

function fp_to_utf8(string $value): string {
  $value = preg_replace('/^\xEF\xBB\xBF/', '', $value) ?? $value;
  if ($value === '') return '';
  if (function_exists('mb_check_encoding') && mb_check_encoding($value, 'UTF-8')) {
    return $value;
  }
  $converted = @iconv('Windows-1252', 'UTF-8//IGNORE', $value);
  if ($converted !== false) return $converted;
  $converted = @iconv('ISO-8859-1', 'UTF-8//IGNORE', $value);
  return $converted !== false ? $converted : $value;
}

function fp_header_key(string $key): string {
  $key = fp_to_utf8($key);
  $key = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $key) ?: $key;
  $key = strtolower(trim($key));
  $key = preg_replace('/[^a-z0-9]+/', '_', $key) ?? $key;
  return trim($key, '_');
}

function fp_cell(array $row, ?int $idx): string {
  if ($idx === null) return '';
  return fp_normalize_text(fp_to_utf8((string)($row[$idx] ?? '')));
}

function fp_find_col(array $headerKeys, array $names): ?int {
  foreach ($headerKeys as $idx => $key) {
    if (in_array($key, $names, true)) return (int)$idx;
  }
  return null;
}

function fp_parse_percapita_date(?string $value): ?string {
  $raw = fp_normalize_text((string)($value ?? ''));
  if ($raw === '') return null;

  if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $raw) === 1) {
    [$yyyy, $mm, $dd] = array_map('intval', explode('-', $raw));
    return checkdate($mm, $dd, $yyyy) ? sprintf('%04d-%02d-%02d', $yyyy, $mm, $dd) : null;
  }

  if (preg_match('/^(\d{1,2})[-\/](\d{1,2})[-\/](\d{4})$/', $raw, $m) === 1) {
    $dd = (int)$m[1];
    $mm = (int)$m[2];
    $yyyy = (int)$m[3];
    return checkdate($mm, $dd, $yyyy) ? sprintf('%04d-%02d-%02d', $yyyy, $mm, $dd) : null;
  }

  if (preg_match('/^(\d{4})(\d{2})(\d{2})$/', $raw, $m) === 1) {
    $yyyy = (int)$m[1];
    $mm = (int)$m[2];
    $dd = (int)$m[3];
    return checkdate($mm, $dd, $yyyy) ? sprintf('%04d-%02d-%02d', $yyyy, $mm, $dd) : null;
  }

  // Excel puede entregar fechas como número serial al guardar CSV desde algunas configuraciones.
  if (is_numeric($raw)) {
    $serial = (int)$raw;
    if ($serial > 20000 && $serial < 80000) {
      $base = new DateTimeImmutable('1899-12-30');
      return $base->modify('+' . $serial . ' days')->format('Y-m-d');
    }
  }

  return null;
}

function fp_age_from_birthdate(?string $date): ?int {
  if (!$date || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) return null;
  try {
    $birth = new DateTimeImmutable($date);
    $today = new DateTimeImmutable('today');
    if ($birth > $today) return null;
    return (int)$birth->diff($today)->y;
  } catch (Throwable $e) {
    return null;
  }
}

function fp_genero_percapita(?string $value): ?string {
  $v = mb_strtolower(fp_normalize_text((string)($value ?? '')), 'UTF-8');
  if ($v === '') return null;
  if (str_starts_with($v, 'muj') || $v === 'f' || str_starts_with($v, 'fem')) return 'Femenino';
  if (str_starts_with($v, 'hom') || $v === 'm' || str_starts_with($v, 'mas')) return 'Masculino';
  return mb_convert_case($v, MB_CASE_TITLE, 'UTF-8');
}

try {
  if (empty($_FILES)) {
    json_response(['ok' => false, 'message' => 'Debes seleccionar el CSV de Percápita FONASA.'], 400);
  }

  $file = $_FILES['percapita'] ?? $_FILES['csv_percapita'] ?? $_FILES['excel'] ?? reset($_FILES);
  if (!is_array($file) || (int)($file['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
    json_response(['ok' => false, 'message' => 'No se pudo recibir el archivo.'], 400);
  }

  $tmp = (string)$file['tmp_name'];
  $originalName = (string)($file['name'] ?? 'percapita.csv');
  $ext = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
  if (!in_array($ext, ['csv', 'txt'], true)) {
    json_response(['ok' => false, 'message' => 'Por ahora esta herramienta recibe CSV o TXT exportado desde FONASA. Guarda el Excel como CSV e intenta nuevamente.'], 400);
  }

  $fh = fopen($tmp, 'rb');
  if (!$fh) json_response(['ok' => false, 'message' => 'No se pudo abrir el archivo.'], 400);

  $firstLine = '';
  while (($line = fgets($fh)) !== false) {
    if (trim($line) !== '') { $firstLine = $line; break; }
  }
  if ($firstLine === '') {
    fclose($fh);
    json_response(['ok' => false, 'message' => 'El CSV está vacío.'], 400);
  }

  $delimiter = fp_detect_delimiter($firstLine);
  rewind($fh);

  $headers = fgetcsv($fh, 0, $delimiter);
  if (!is_array($headers) || !$headers) {
    fclose($fh);
    json_response(['ok' => false, 'message' => 'No se pudo leer la cabecera del CSV.'], 400);
  }

  $headerKeys = array_map(static fn($h) => fp_header_key((string)$h), $headers);
  $runIndex = fp_find_col($headerKeys, ['run', 'rut', 'rut_usuario', 'rut_paciente', 'numero_identificacion', 'numero_documento']);
  if ($runIndex === null) {
    fclose($fh);
    json_response(['ok' => false, 'message' => 'No se encontró la columna RUN/RUT en el CSV. Revisa que la cabecera diga RUN como en el archivo FONASA.'], 400);
  }

  $nombresIndex = fp_find_col($headerKeys, ['nombres', 'nombre', 'nombre_paciente']);
  $apPatIndex = fp_find_col($headerKeys, ['apellido_paterno', 'ap_paterno', 'paterno']);
  $apMatIndex = fp_find_col($headerKeys, ['apellido_materno', 'ap_materno', 'materno']);
  $fechaNacIndex = fp_find_col($headerKeys, ['fecha_nacimiento', 'fec_nacimiento', 'fecha_nac', 'nacimiento']);
  $generoIndex = fp_find_col($headerKeys, ['genero', 'sexo']);

  $csvRows = [];
  $leidos = 0;
  $sinRun = 0;
  $duplicados = 0;
  while (($row = fgetcsv($fh, 0, $delimiter)) !== false) {
    if (!is_array($row)) continue;
    $leidos++;
    $run = fp_normalize_run_key(fp_cell($row, $runIndex));
    if ($run === '') { $sinRun++; continue; }
    if (isset($csvRows[$run])) $duplicados++;

    $nombres = fp_cell($row, $nombresIndex);
    $apellidosParts = array_filter([fp_cell($row, $apPatIndex), fp_cell($row, $apMatIndex)], static fn($v) => $v !== '');
    $apellidos = implode(' ', $apellidosParts);
    $fechaNac = fp_parse_percapita_date(fp_cell($row, $fechaNacIndex));
    $genero = fp_genero_percapita(fp_cell($row, $generoIndex));

    // Si el RUN aparece repetido, conservamos el último dato no vacío del CSV.
    $prev = $csvRows[$run] ?? [];
    $csvRows[$run] = [
      'rut' => $run,
      'nombres' => $nombres !== '' ? $nombres : ($prev['nombres'] ?? null),
      'apellidos' => $apellidos !== '' ? $apellidos : ($prev['apellidos'] ?? null),
      'fecha_nacimiento' => $fechaNac ?: ($prev['fecha_nacimiento'] ?? null),
      'edad' => fp_age_from_birthdate($fechaNac) ?? ($prev['edad'] ?? null),
      'genero' => $genero ?: ($prev['genero'] ?? null),
    ];
  }
  fclose($fh);

  if (!$csvRows) {
    json_response(['ok' => false, 'message' => 'No se encontraron RUN válidos en el archivo.'], 400);
  }

  $runList = array_keys($csvRows);
  $normExpr = fp_sql_normalized_rut_expr('rut');

  $pdo->beginTransaction();

  $totalUsuariosAntes = (int)$pdo->query('SELECT COUNT(*) FROM usuarios')->fetchColumn();

  // Primero se deja toda la base como no percapitada. Luego se reactivan los RUN del CSV.
  $pdo->exec("UPDATE usuarios SET percapitado = 0, fecha_actualizacion_percapita = CURDATE()");

  $encontrados = [];
  $rutPrincipalPorNorm = [];
  $filasBdCoincidentes = 0;
  $chunks = array_chunk($runList, 700);
  foreach ($chunks as $chunk) {
    $placeholders = implode(',', array_fill(0, count($chunk), '?'));
    $sqlSelect = "SELECT rut, $normExpr AS run_norm FROM usuarios WHERE $normExpr IN ($placeholders)";
    $stSel = $pdo->prepare($sqlSelect);
    $stSel->execute($chunk);
    $rows = $stSel->fetchAll(PDO::FETCH_ASSOC) ?: [];
    foreach ($rows as $r) {
      $norm = (string)($r['run_norm'] ?? '');
      if ($norm === '') continue;
      $encontrados[$norm] = true;
      $filasBdCoincidentes++;
      if (!isset($rutPrincipalPorNorm[$norm])) $rutPrincipalPorNorm[$norm] = (string)$r['rut'];
    }

    $sqlUpdate = "UPDATE usuarios SET percapitado = 1, inscrito_cesfam = 1, fecha_actualizacion_percapita = CURDATE() WHERE $normExpr IN ($placeholders)";
    $st = $pdo->prepare($sqlUpdate);
    $st->execute($chunk);
  }

  // Completa datos básicos de personas existentes solo cuando el dato actual está vacío.
  $stUpdateDatos = $pdo->prepare("
    UPDATE usuarios
    SET
      nombres = COALESCE(NULLIF(nombres, ''), :nombres, nombres),
      apellidos = COALESCE(NULLIF(apellidos, ''), :apellidos, apellidos),
      fecha_nacimiento = CASE
        WHEN (fecha_nacimiento IS NULL OR fecha_nacimiento = '0000-00-00') THEN COALESCE(:fecha_nacimiento, fecha_nacimiento)
        ELSE fecha_nacimiento
      END,
      edad = CASE WHEN (edad IS NULL OR edad = 0) THEN COALESCE(:edad, edad) ELSE edad END,
      genero = COALESCE(NULLIF(genero, ''), :genero, genero),
      prevision = CASE WHEN (prevision IS NULL OR TRIM(prevision) = '' OR LOWER(TRIM(prevision)) IN ('desconocido', 'ninguna', 'sin dato')) THEN 'Fonasa' ELSE prevision END
    WHERE rut = :rut_bd
  ");

  $actualizadosDatos = 0;
  foreach ($rutPrincipalPorNorm as $norm => $rutBd) {
    $data = $csvRows[$norm] ?? null;
    if (!$data) continue;
    $stUpdateDatos->execute([
      ':nombres' => $data['nombres'] ?: null,
      ':apellidos' => $data['apellidos'] ?: null,
      ':fecha_nacimiento' => $data['fecha_nacimiento'] ?: null,
      ':edad' => $data['edad'],
      ':genero' => $data['genero'] ?: null,
      ':rut_bd' => $rutBd,
    ]);
    $actualizadosDatos += $stUpdateDatos->rowCount();
  }

  $nuevos = [];
  foreach ($runList as $run) {
    if (!isset($encontrados[$run])) $nuevos[] = $csvRows[$run];
  }

  $insertados = 0;
  $erroresInsert = [];
  $stInsert = $pdo->prepare("
    INSERT INTO usuarios (
      rut, fecha_nacimiento, edad, apellidos, nombres, genero,
      prevision, inscrito_cesfam, percapitado, fecha_actualizacion_percapita,
      estratificacion_riesgo, cantidad_condiciones_cronicas, detalle_diagnosticos_cronicos
    ) VALUES (
      :rut, :fecha_nacimiento, :edad, :apellidos, :nombres, :genero,
      'Fonasa', 1, 1, CURDATE(),
      'G0', 0, NULL
    )
  ");

  foreach ($nuevos as $data) {
    try {
      $stInsert->execute([
        ':rut' => $data['rut'],
        ':fecha_nacimiento' => $data['fecha_nacimiento'] ?: null,
        ':edad' => $data['edad'],
        ':apellidos' => $data['apellidos'] ?: null,
        ':nombres' => $data['nombres'] ?: null,
        ':genero' => $data['genero'] ?: null,
      ]);
      $insertados += $stInsert->rowCount();
    } catch (Throwable $e) {
      $erroresInsert[] = $data['rut'];
      error_log('IMPORT PERCAPITA INSERT USER ERROR RUT ' . $data['rut'] . ': ' . $e->getMessage());
    }
  }

  // Regla de negocio: toda persona presente en Percápita FONASA debe quedar también como inscrita CESFAM.
  $inscritosCorregidosPorPercapita = (int)$pdo->exec("UPDATE usuarios SET inscrito_cesfam = 1 WHERE percapitado = 1 AND COALESCE(inscrito_cesfam, 0) <> 1");

  $marcadosSiFinal = (int)$pdo->query('SELECT COUNT(*) FROM usuarios WHERE percapitado = 1')->fetchColumn();
  $marcadosNo = (int)$pdo->query('SELECT COUNT(*) FROM usuarios WHERE percapitado = 0')->fetchColumn();
  $totalUsuariosDespues = (int)$pdo->query('SELECT COUNT(*) FROM usuarios')->fetchColumn();

  $muestraNuevos = array_slice(array_map(static function($data) {
    $nombre = trim((string)($data['nombres'] ?? '') . ' ' . (string)($data['apellidos'] ?? ''));
    return trim((string)$data['rut'] . ($nombre !== '' ? ' - ' . $nombre : ''));
  }, $nuevos), 0, 50);

  $pdo->commit();

  fp_log_activity($pdo, $u, 'Personas', 'Actualizar Percápita FONASA', 'Se actualizó Percápita FONASA: ' . $marcadosSiFinal . ' percapitados y ' . $marcadosNo . ' no percapitados.', 'importacion', 'percapita');

  json_response([
    'ok' => true,
    'summary' => [
      'archivo' => $originalName,
      'filas_leidas' => $leidos,
      'run_unicos_csv' => count($runList),
      'run_duplicados_csv' => $duplicados,
      'sin_run' => $sinRun,
      'total_usuarios_bd_antes' => $totalUsuariosAntes,
      'total_usuarios_bd_despues' => $totalUsuariosDespues,
      'filas_bd_coincidentes' => $filasBdCoincidentes,
      'actualizados_datos_basicos' => $actualizadosDatos,
      'run_csv_no_existian_en_bd' => count($nuevos),
      'usuarios_creados_desde_csv' => $insertados,
      'usuarios_no_creados_por_error' => count($erroresInsert),
      'muestra_creados' => $muestraNuevos,
      'muestra_no_creados' => array_slice($erroresInsert, 0, 50),
      'marcados_percapitados' => $marcadosSiFinal,
      'inscritos_corregidos_por_percapita' => $inscritosCorregidosPorPercapita,
      'marcados_no_percapitados' => $marcadosNo,
      // Compatibilidad con el JS anterior.
      'total_usuarios_bd' => $totalUsuariosAntes,
      'run_csv_no_encontrados' => count($nuevos),
      'muestra_no_encontrados' => $muestraNuevos,
      'accion' => 'Se marcó percapitado=1 e inscrito_cesfam=1 para RUN presentes en el CSV, percapitado=0 para los demás, y se crearon como nuevos los RUN del CSV que no existían en la base. No se eliminó información clínica, familiar ni estratificación.'
    ]
  ]);
} catch (Throwable $e) {
  if (isset($pdo) && $pdo instanceof PDO && $pdo->inTransaction()) $pdo->rollBack();
  error_log('IMPORT PERCAPITA ERROR: ' . $e->getMessage());
  $isLocal = in_array($_SERVER['REMOTE_ADDR'] ?? '', ['127.0.0.1', '::1'], true);
  json_response(['ok' => false, 'message' => $isLocal ? $e->getMessage() : 'Error procesando CSV de Percápita.'], 500);
}
