/**
 * Lista de personas: misma barra superior (Tabla); abajo, tabla (DataGrid) o tarjetas según vista.
 * Selección masiva (checkbox / clic en fila) solo en vista tabla; la vista tarjetas no es seleccionable.
 * Los ítems suelen incluir nombre, email, documento, estado; la columna Actividad usa fecha de última actividad (relativa).
 */
import { useState, useMemo, useEffect, useRef, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { blend } from '@mui/system/colorManipulator';
import { Typography } from '../../Atoms/Typography/Typography';
import { Badge } from '../../Atoms/Badge/Badge';
import { PrimaryActionButton } from '../../Atoms/PrimaryActionButton/PrimaryActionButton';
import { Icon } from '../../Atoms/Icon/Icon';
import { Skeleton } from '../../Atoms/Skeleton/Skeleton';
import { MenuAcciones } from '../MenuAcciones/MenuAcciones';
import { CardsPersonas } from '../CardsPersonas/CardsPersonas';
import {
  Tabla,
  TABLA_TOOLBAR_ICONS_DEFAULT,
  RED_BAR_RECORDS_TEXT_STYLE,
  RED_BAR_BULK_ACTION_BUTTON_STYLE,
  RED_BAR_BULK_ACTION_SEPARATOR_STYLE,
} from '../Tabla/Tabla';
import {
  tiempoRelativoEnEspanol,
  clampRegistrosPorPagina,
  resolvePageAfterPageSizeChange,
} from '../Tabla/tablaRegistrosAndTimeUtils.js';
import { FONT_FAMILY_SANS, FONT_FAMILY_MONO } from '../../../designTokens';
import { buildPersonaDocumentoLabel } from './buildPersonaDocumentoLabel';
import { formatPersonaDateDdMmYyyy, getPersonaNombreInitials } from './listaPersonasColumnHelpers';
import {
  PERSONA_TABLA_COL_SELECT_WIDTH_PX,
  PERSONA_TABLA_FIELD_ACCIONES,
  PERSONA_TABLA_ROW_SELECTED_CLASS,
  isPersonaTableRowClickIgnoredForSelection,
  selectedSetHasId,
} from './listaPersonasTableUtils';

/**
 * Mismo tono opaco que `action.hover` sobre `background.paper` (el rgba de MUI no coincide con `darken` fijo).
 * Sirve para toda la fila marcada y para columnas sticky sin bandas de otro gris.
 * @param {import('@mui/material').Theme} theme
 */
function personaTablaRowSelectedOpaqueBg(theme) {
  const paper = theme.palette.background.paper;
  const o = theme.palette.action.hoverOpacity ?? (theme.palette.mode === 'light' ? 0.04 : 0.08);
  return theme.palette.mode === 'light'
    ? blend(paper, theme.palette.common.black, o)
    : blend(paper, theme.palette.common.white, o);
}

/**
 * Columnas de datos del DataGrid: `flex`/`minWidth` por defecto (Persona un poco más ancha); redimensionables.
 * Sin `width` fijo salvo la columna de selección (`__select`).
 */
const PERSONA_TABLA_DATA_COL_FLEX = 1;
const PERSONA_TABLA_DATA_COL_MIN_WIDTH = 140;
/** Columna Persona (nombre + email): más ancha por defecto que el resto. */
const PERSONA_TABLA_COL_PERSONA_MIN_WIDTH = 200;
const PERSONA_TABLA_COL_PERSONA_FLEX = 1.25;
/** Columna Acciones (icono ⋮): más estrecha que el resto; cabecera + icono caben con margen. */
const PERSONA_TABLA_COL_ACCIONES_MIN_WIDTH = 116;
const PERSONA_TABLA_COL_ACCIONES_FLEX = 0.72;

/**
 * Checkbox en cabecera: marca/desmarca los ids de la página actual.
 * Solo aparece marcado si están seleccionados todos los de la página; si hay cero o solo algunos, desmarcado (sin estado indeterminado).
 */
function PersonaSelectAllPageHeaderCheckbox({ pageIds, selectedIdSet, onTogglePage, ariaLabel }) {
  const allSelected =
    pageIds.length > 0 && pageIds.every((id) => selectedSetHasId(selectedIdSet, id));

  return (
    <div style={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <input
        type="checkbox"
        aria-label={ariaLabel}
        checked={allSelected}
        disabled={pageIds.length === 0}
        onClick={(e) => e.stopPropagation()}
        onChange={(e) => {
          e.stopPropagation();
          onTogglePage?.(e.target.checked);
        }}
        style={{
          width: 16,
          height: 16,
          cursor: pageIds.length === 0 ? 'default' : 'pointer',
          accentColor: '#38656D',
        }}
      />
    </div>
  );
}

function PersonaAvatar({ row, initials }) {
  const [imgFailed, setImgFailed] = useState(false);
  const photoSrc =
    row?.foto
    ?? row?.photo
    ?? row?.photoUrl
    ?? row?.avatarUrl
    ?? row?.imageUrl
    ?? row?.imagen
    ?? row?.profilePicture
    ?? row?.profilePictureUrl
    ?? row?.picture
    ?? '';
  const src = typeof photoSrc === 'string' ? photoSrc.trim() : '';
  const shouldShowImg = !!src && !imgFailed;
 
  return (
    <div
      style={{
        width: 40,
        height: 40,
        minWidth: 40,
        minHeight: 40,
        borderRadius: '999px',
        border: '1px solid var(--color-main-700, #38656D)',
        background: 'var(--color-neutrals-white, #FFFFFF)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        boxSizing: 'border-box',
        overflow: 'hidden',
      }}
    >
      {shouldShowImg ? (
        <img
          src={src}
          alt=""
          onError={() => setImgFailed(true)}
          style={{
            width: '100%',
            height: '100%',
            objectFit: 'cover',
            display: 'block',
          }}
        />
      ) : (
        <Typography
          component="span"
          style={{
            fontFamily: FONT_FAMILY_SANS,
            fontWeight: 500,
            fontStyle: 'normal',
            fontSize: '14px',
            lineHeight: '100%',
            letterSpacing: '0px',
            color: 'var(--color-main-700, #38656D)',
            margin: 0,
          }}
        >
          {initials}
        </Typography>
      )}
    </div>
  );
}
 
function getPersonasTablaColumns(
  t,
  selectedIdSet,
  onToggleSelect,
  pageIds,
  onTogglePageSelect,
  viewActionText,
  onViewClick,
  showViewCardButton,
  shouldShowViewCardButton,
  actionButtonText,
  onActionClick,
  archiveActionText,
  unarchiveActionText,
  onArchiveClick,
  onUnarchiveClick,
  deleteActionText,
  onDeleteClick,
  showEditCardButton,
  showDeleteCardButton,
  showArchiveCardButton,
  shouldShowEditCardButton,
  shouldShowArchiveCardButton,
  shouldShowDeleteCardButton,
) {
  return [
    {
      field: '__select',
      headerName: '',
      width: PERSONA_TABLA_COL_SELECT_WIDTH_PX,
      flex: 0,
      sortable: false,
      filterable: false,
      disableColumnMenu: true,
      renderHeader: () => (
        <PersonaSelectAllPageHeaderCheckbox
          pageIds={pageIds}
          selectedIdSet={selectedIdSet}
          onTogglePage={onTogglePageSelect}
          ariaLabel={t('persona.table.selectPageAria', {
            defaultValue: 'Seleccionar todas las personas de esta página',
          })}
        />
      ),
      renderCell: (params) => {
        const rowId = params.row?.id ?? params.id;
        const checked = rowId != null ? selectedSetHasId(selectedIdSet, rowId) : false;
        return (
          <div style={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <input
              type="checkbox"
              aria-label={t('persona.table.selectRowAria', { defaultValue: 'Seleccionar persona' })}
              checked={!!checked}
              onClick={(e) => e?.stopPropagation?.()}
              onChange={(e) => {
                e?.stopPropagation?.();
                if (rowId == null) return;
                onToggleSelect?.(rowId, e.target.checked, params.row);
              }}
              style={{
                width: 16,
                height: 16,
                cursor: 'pointer',
                accentColor: '#38656D',
              }}
            />
          </div>
        );
      },
    },
    {
      field: 'nombreComercial',
      headerName: t('persona.table.header.person', { defaultValue: 'Persona' }),
      flex: PERSONA_TABLA_COL_PERSONA_FLEX,
      minWidth: PERSONA_TABLA_COL_PERSONA_MIN_WIDTH,
      valueGetter: (value, row) => row.nombreComercial ?? row.nombreFantasia ?? '',
      renderCell: (params) => {
        const nombre = params.row?.nombreComercial ?? params.row?.nombreFantasia ?? params.value ?? '';
        if (!nombre) return null;
        const email =
          params.row?.email
          ?? params.row?.correo
          ?? params.row?.correoElectronico
          ?? params.row?.correo_electronico
          ?? params.row?.mail
          ?? '';
        const initials = getPersonaNombreInitials(nombre);
 
        return (
          <div
            style={{
              width: '100%',
              minWidth: 0,
              display: 'flex',
              alignItems: 'center',
              gap: 12,
            }}
          >
            <PersonaAvatar row={params.row} initials={initials} />
            <div
              style={{
                minWidth: 0,
                display: 'flex',
                flexDirection: 'column',
                justifyContent: 'center',
              }}
            >
              <Typography
                component="span"
                style={{
                  fontFamily: FONT_FAMILY_SANS,
                  fontWeight: 600,
                  fontStyle: 'normal',
                  fontSize: '16px',
                  lineHeight: '24px',
                  letterSpacing: '0%',
                  color: 'var(--color-main-800, #29474C)',
                  margin: 0,
                  whiteSpace: 'nowrap',
                  overflow: 'hidden',
                  textOverflow: 'ellipsis',
                }}
              >
                {nombre}
              </Typography>
              <Typography
                component="span"
                style={{
                  fontFamily: FONT_FAMILY_SANS,
                  fontWeight: 400,
                  fontStyle: 'normal',
                  fontSize: '14px',
                  lineHeight: '21px',
                  letterSpacing: '0.01em',
                  color: 'var(--color-main-800, #29474C)',
                  margin: 0,
                  whiteSpace: 'nowrap',
                  overflow: 'hidden',
                  textOverflow: 'ellipsis',
                }}
              >
                {email || '—'}
              </Typography>
            </div>
          </div>
        );
      },
    },
    {
      field: 'fechaNacimiento',
      headerName: t('persona.table.header.birthDate', { defaultValue: 'Fecha de nacimiento' }),
      flex: PERSONA_TABLA_DATA_COL_FLEX,
      minWidth: PERSONA_TABLA_DATA_COL_MIN_WIDTH,
      valueGetter: (value, row) =>
        row.fechaNacimiento ?? row.fecha_nacimiento ?? row.birthDate ?? row.fechaDeNacimiento ?? value ?? '',
      renderCell: (params) => {
        const raw =
          params.row?.fechaNacimiento
          ?? params.row?.fecha_nacimiento
          ?? params.row?.birthDate
          ?? params.row?.fechaDeNacimiento
          ?? params.value;
        const formatted = formatPersonaDateDdMmYyyy(raw);
        return formatted ? (
          <Typography component="span" style={{ fontFamily: FONT_FAMILY_SANS, fontSize: 14, lineHeight: '21px', color: 'var(--color-main-800, #29474C)' }}>
            {formatted}
          </Typography>
        ) : null;
      },
    },
    {
      field: 'documento',
      headerName: t('persona.table.header.document', { defaultValue: 'Documento' }),
      flex: PERSONA_TABLA_DATA_COL_FLEX,
      minWidth: PERSONA_TABLA_DATA_COL_MIN_WIDTH,
      valueGetter: (value, row) => buildPersonaDocumentoLabel(row, value),
      renderCell: (params) => {
        const doc = buildPersonaDocumentoLabel(params.row, params.value);
        return doc ? (
          <Typography component="span" style={{ fontFamily: FONT_FAMILY_SANS, fontSize: 14, lineHeight: '21px', color: 'var(--color-main-800, #29474C)' }}>
            {doc}
          </Typography>
        ) : null;
      },
    },
    {
      field: 'estado',
      headerName: t('empresa.table.header.status', { defaultValue: 'Estado' }),
      headerAlign: 'center',
      align: 'center',
      flex: PERSONA_TABLA_DATA_COL_FLEX,
      minWidth: PERSONA_TABLA_DATA_COL_MIN_WIDTH,
      valueGetter: (value, row) => getPersonaTablaEstadoDisplay(row)?.label ?? '',
      renderCell: (params) => {
        const shown = getPersonaTablaEstadoDisplay(params.row);
        if (!shown) return null;
        const statusVariant =
          params.row?.statusVariant
          || shown.variant;
        return (
          <div style={{ width: '100%', display: 'flex', justifyContent: 'center' }}>
            <Badge variant={statusVariant} size="medium">
              {shown.label}
            </Badge>
          </div>
        );
      },
    },
    {
      field: 'ultimaActividad',
      headerName: t('persona.table.header.lastActivity', { defaultValue: 'Actividad' }),
      flex: PERSONA_TABLA_DATA_COL_FLEX,
      minWidth: PERSONA_TABLA_DATA_COL_MIN_WIDTH,
      valueGetter: (value, row) => getPersonaUltimaActividadFecha(row) ?? '',
      renderCell: (params) => {
        const raw = getPersonaUltimaActividadFecha(params.row);
        const text = tiempoRelativoEnEspanol(raw);
        return (
          <Typography
            component="span"
            style={{
              fontFamily: FONT_FAMILY_SANS,
              fontWeight: 400,
              fontSize: '14px',
              lineHeight: '21px',
              letterSpacing: '0.01em',
              color: 'var(--color-main-800, #29474C)',
            }}
          >
            {text}
          </Typography>
        );
      },
    },
    {
      field: PERSONA_TABLA_FIELD_ACCIONES,
      headerName: t('empresa.table.header.actions', { defaultValue: 'Acciones' }),
      flex: PERSONA_TABLA_COL_ACCIONES_FLEX,
      minWidth: PERSONA_TABLA_COL_ACCIONES_MIN_WIDTH,
      headerAlign: 'center',
      align: 'center',
      sortable: false,
      filterable: false,
      disableColumnMenu: true,
      resizable: false,
      renderCell: (params) => {
        let index = 0;
        try {
          if (params.api && typeof params.api.getRowIndex === 'function') {
            index = params.api.getRowIndex(params.id);
          }
        } catch (_) {}
        const isViewVisible = typeof shouldShowViewCardButton === 'function'
          ? !!shouldShowViewCardButton(params.row, index)
          : showViewCardButton;
        const isEditVisible = typeof shouldShowEditCardButton === 'function'
          ? !!shouldShowEditCardButton(params.row, index)
          : showEditCardButton;
        const isArchiveVisible = typeof shouldShowArchiveCardButton === 'function'
          ? !!shouldShowArchiveCardButton(params.row, index)
          : showArchiveCardButton;
        const isDeleteVisible = typeof shouldShowDeleteCardButton === 'function'
          ? !!shouldShowDeleteCardButton(params.row, index)
          : showDeleteCardButton;
 
        return (
          <div style={{ width: '100%', display: 'flex', justifyContent: 'center' }}>
            <MenuAcciones
              ariaLabel={t('table.actionsAria', { defaultValue: 'Acciones' })}
              menuWidth={isArchiveVisible ? 148 : 132}
              actions={[
                ...(isViewVisible && viewActionText
                  ? [{
                      key: 'view',
                      icon: 'EyeIcon',
                      label: viewActionText,
                      onClick: (event) => onViewClick?.(params.row, index, event),
                    }]
                  : []),
                ...(isEditVisible && actionButtonText
                  ? [{
                      key: 'edit',
                      icon: 'PencilSquareIcon',
                      label: actionButtonText,
                      onClick: (event) => onActionClick?.(params.row, index, event),
                    }]
                  : []),
                ...(() => {
                  if (!isArchiveVisible || (!archiveActionText && !unarchiveActionText)) return [];
                  const estado = (params.row?.estado ?? params.row?.status ?? '').toString().trim();
                  const isArchived = estado === 'Archivada';
                  const label = isArchived
                    ? (unarchiveActionText || 'Desarchivar')
                    : (archiveActionText || 'Archivar');
                  const handler = isArchived ? onUnarchiveClick : onArchiveClick;
                  if (typeof handler !== 'function') return [];
                  return [{
                    key: isArchived ? 'unarchive' : 'archive',
                    icon: isArchived ? 'ArrowUturnLeftIcon' : 'ArchiveBoxIcon',
                    label,
                    onClick: (event) => handler?.(params.row, index, event),
                  }];
                })(),
                ...(isDeleteVisible && deleteActionText
                  ? [{
                      key: 'delete',
                      icon: 'TrashIcon',
                      label: deleteActionText,
                      onClick: (event) => onDeleteClick?.(params.row, index, event),
                    }]
                  : []),
              ]}
            />
          </div>
        );
      },
    },
  ];
}
 
const toolbarStyles = `
  .anima-listapersonas__toolbar-btn--with-border {
    border: 1px solid var(--color-main-700, #38656D) !important;
  }
  .anima-listapersonas__toolbar-btn--with-border:active {
    background: var(--color-main-700, #38656D) !important;
  }
  .anima-listapersonas__toolbar-btn--with-border:active .anima-listapersonas__toolbar-btn-icon {
    color: var(--color-neutrals-white, #FFFFFF) !important;
  }
  .anima-listapersonas__toolbar-btn--selected,
  .anima-listapersonas__toolbar-btn--with-border.anima-listapersonas__toolbar-btn--selected {
    background: var(--color-main-700, #38656D) !important;
    border: 1px solid var(--color-main-700, #38656D) !important;
  }
  .anima-listapersonas__toolbar-btn--selected .anima-listapersonas__toolbar-btn-icon {
    color: var(--color-neutrals-white, #FFFFFF) !important;
  }
  /* Mismas reglas que placeholderStyles en Tabla para iconos de vista (lista/cards sin Tabla montada). */
  .anima-listapersonas .anima-tabla__toolbar-btn--with-border {
    border: 1px solid var(--color-main-700, #38656D) !important;
  }
  .anima-listapersonas .anima-tabla__toolbar-btn--with-border:active {
    background: var(--color-main-700, #38656D) !important;
  }
  .anima-listapersonas .anima-tabla__toolbar-btn--with-border:active .anima-tabla__toolbar-btn-icon {
    color: var(--color-neutrals-white, #FFFFFF) !important;
  }
  .anima-listapersonas .anima-tabla__toolbar-btn--selected,
  .anima-listapersonas .anima-tabla__toolbar-btn--with-border.anima-tabla__toolbar-btn--selected {
    background: var(--color-main-700, #38656D) !important;
    border: 1px solid var(--color-main-700, #38656D) !important;
  }
  .anima-listapersonas .anima-tabla__toolbar-btn--selected .anima-tabla__toolbar-btn-icon {
    color: var(--color-neutrals-white, #FFFFFF) !important;
  }
  /* Descarga: sin outlined (vista lista / tarjetas mantienen borde) */
  .anima-listapersonas .anima-tabla__toolbar-icons .anima-tabla__toolbar-btn:first-child:not(.anima-tabla__toolbar-btn--selected) {
    border: none !important;
    background: transparent !important;
    box-shadow: none !important;
  }
  .anima-listapersonas .anima-tabla__toolbar-icons .anima-tabla__toolbar-btn:first-child:not(.anima-tabla__toolbar-btn--selected) .anima-tabla__toolbar-btn-icon {
    color: var(--color-main-700, #38656D) !important;
  }
  .anima-listapersonas .anima-tabla__toolbar-icons .anima-tabla__toolbar-btn:first-child:active {
    background: rgba(56, 101, 109, 0.1) !important;
  }
  .anima-listapersonas .anima-tabla__toolbar-icons .anima-tabla__toolbar-btn:first-child:active .anima-tabla__toolbar-btn-icon {
    color: var(--color-main-700, #38656D) !important;
  }
  .anima-listapersonas__search-input::placeholder {
    font-family: var(--font-family-sans);
    font-weight: 400;
    font-style: italic;
    font-size: 16px;
    line-height: 24px;
    color: var(--color-grey-700, #474747);
    opacity: 1;
  }
  /*
   * SM/MD (≤1023px): mismo margen lateral (12px); saltos verticales un poco más amplios (~14px) entre filas.
   */
  @media (max-width: 1023px) {
    .anima-listapersonas .anima-tabla__search-wrap {
      flex-wrap: wrap !important;
      align-items: center !important;
      box-sizing: border-box !important;
      padding-left: 12px !important;
      padding-right: 12px !important;
      margin-bottom: 14px !important;
      gap: 8px !important;
      row-gap: 14px !important;
      width: 100% !important;
      max-width: 100% !important;
    }
    /*
     * Tabla fija maxWidth 498px en el contenedor del input; en SM/MD búsqueda + filtros deben usar todo el ancho disponible.
     * Primer hijo = caja del input; el botón de filtros sigue al lado (flex-shrink: 0 en Tabla).
     */
    .anima-listapersonas .anima-tabla__search-wrap > div:first-of-type {
      max-width: 100% !important;
      flex: 1 1 auto !important;
      min-width: 0 !important;
    }
    /* Barra registros/página: quita height:21px inline y alinea como en móvil ≤768 */
    .anima-listapersonas .anima-tabla__red-bar {
      height: auto !important;
      min-height: 0 !important;
      display: grid !important;
      grid-template-columns: 1fr auto !important;
      grid-template-rows: auto auto !important;
      align-items: center !important;
      column-gap: 12px !important;
      row-gap: 8px !important;
      padding: 0 !important;
      margin-bottom: 14px !important;
      box-sizing: border-box !important;
    }
    .anima-listapersonas .anima-tabla__red-bar-registros {
      grid-column: 1 !important;
      grid-row: 1 !important;
      padding-left: 12px !important;
    }
    .anima-listapersonas .anima-tabla__red-bar-pagination {
      display: contents !important;
    }
    .anima-listapersonas .anima-tabla__red-bar-pagina-text {
      grid-column: 1 !important;
      grid-row: 2 !important;
      padding-left: 12px !important;
    }
    .anima-listapersonas .anima-tabla__red-bar-pagination-buttons {
      grid-column: 2 !important;
      grid-row: 1 / -1 !important;
      align-self: center !important;
      justify-self: end !important;
      gap: 8px !important;
      padding-right: 12px !important;
    }
    .anima-listapersonas .anima-tabla__narrow-bulk-row {
      padding: 8px 12px 12px !important;
      gap: 10px !important;
    }
    /* Texto “n seleccionada(s)” un poco más a la derecha */
    .anima-listapersonas .anima-tabla__narrow-bulk-row > span:first-of-type {
      margin-left: 12px !important;
    }
    /*
     * Tabla (≤768px) aplica margin-top:-1.5rem al wrap del grid cuando hay barra de scroll horizontal;
     * sin selección no existe fila bulk ni clase --after-narrow-bulk → la cabecera tapa la paginación.
     * En ListaPersonas SM/MD el margen negativo no se usa: la tabla va siempre debajo del bloque rojo.
     */
    .anima-listapersonas .anima-tabla__middle-table-wrap {
      margin-top: 0 !important;
    }
    .anima-listapersonas .anima-tabla__toolbar-icons {
      flex-basis: 100% !important;
      width: 100% !important;
      max-width: 100% !important;
      margin-left: 0 !important;
      padding-left: 0 !important;
      padding-right: 0 !important;
      display: flex !important;
      flex-wrap: nowrap !important;
      align-items: center !important;
      justify-content: flex-start !important;
      gap: 8px !important;
      box-sizing: border-box !important;
    }
    /* Descarga a la izquierda; vistas lista + tarjetas juntas a la derecha */
    .anima-listapersonas .anima-tabla__toolbar-icons .anima-tabla__toolbar-btn:nth-child(2) {
      margin-left: auto !important;
    }
    /* Mismo tamaño y estilo que los botones de paginación (48×48, radio 12px) */
    .anima-listapersonas .anima-tabla__toolbar-icons .anima-tabla__toolbar-btn {
      width: 48px !important;
      height: 48px !important;
      min-width: 48px !important;
      min-height: 48px !important;
      padding: 0 !important;
      gap: 0 !important;
      border-radius: 12px !important;
      box-sizing: border-box !important;
      display: flex !important;
      align-items: center !important;
      justify-content: center !important;
    }
    .anima-listapersonas .anima-tabla__toolbar-icons .anima-tabla__toolbar-btn.anima-tabla__toolbar-btn--with-border:not(.anima-tabla__toolbar-btn--selected) {
      border: 1px solid var(--color-main-700, #38656D) !important;
      background: var(--color-neutrals-white, #ffffff) !important;
    }
    .anima-listapersonas .anima-tabla__toolbar-icons .anima-tabla__toolbar-btn.anima-tabla__toolbar-btn--selected {
      background: var(--color-main-700, #38656D) !important;
      border: 1px solid var(--color-main-700, #38656D) !important;
    }
    .anima-listapersonas .anima-tabla__toolbar-icons .anima-tabla__toolbar-btn--selected .anima-tabla__toolbar-btn-icon {
      color: var(--color-neutrals-white, #ffffff) !important;
    }
    .anima-listapersonas .anima-tabla__toolbar-icons .anima-tabla__toolbar-btn--with-border:not(.anima-tabla__toolbar-btn--selected) .anima-tabla__toolbar-btn-icon {
      color: var(--color-main-700, #38656D) !important;
    }
    .anima-listapersonas .anima-tabla__red-bar-pagination button {
      width: 48px !important;
      height: 48px !important;
      min-width: 48px !important;
      min-height: 48px !important;
      display: flex !important;
      align-items: center !important;
      justify-content: center !important;
      flex-shrink: 0 !important;
      border: 1px solid var(--color-main-700, #38656D) !important;
      border-radius: 12px !important;
      box-sizing: border-box !important;
    }
  }
  /* Móvil (≤768px): botones de paginación teal si hay página; blanco si no. */
  @media (max-width: 768px) {
    .anima-listapersonas .anima-tabla__red-bar-pagination button:not(:disabled) {
      background: var(--color-main-700, #38656D) !important;
      border-color: var(--color-main-700, #38656D) !important;
    }
    .anima-listapersonas .anima-tabla__red-bar-pagination button:disabled {
      background: var(--color-neutrals-white, #ffffff) !important;
      opacity: 1 !important;
    }
    .anima-listapersonas .anima-tabla__red-bar-pagination button:not(:disabled) svg {
      color: var(--color-neutrals-white, #ffffff) !important;
    }
    .anima-listapersonas .anima-tabla__red-bar-pagination button:disabled svg {
      color: var(--color-main-400, #84A0A5) !important;
    }
  }
  /* Más aire entre búsqueda y barra de registros solo en desktop */
  @media (min-width: 1024px) {
    .anima-listapersonas .anima-tabla__search-wrap {
      margin-bottom: 20px !important;
    }
    .anima-listapersonas .anima-tabla__red-bar {
      margin-bottom: 12px !important;
    }
  }
  .anima-listapersonas .anima-tabla__grid .MuiDataGrid-cell {
    padding-top: 14px !important;
    padding-bottom: 14px !important;
  }
  /* No añadir padding extra al header: columnHeaderHeight es 48px y el padding rompe el layout (recorte / “Acciones” rara) */
  .anima-listapersonas .anima-tabla__grid .MuiDataGrid-columnHeader,
  .anima-listapersonas .anima-tabla__grid .MuiDataGrid-cell {
    border-right: none !important;
  }
  /* Separador vertical entre Persona y el resto */
  .anima-listapersonas .anima-tabla__grid .MuiDataGrid-columnHeader[data-field="nombreComercial"],
  .anima-listapersonas .anima-tabla__grid .MuiDataGrid-cell[data-field="nombreComercial"] {
    border-right: 2px solid #919191 !important;
  }
  .anima-listapersonas .anima-tabla__grid .MuiDataGrid-cell {
    border-bottom: none !important;
  }
  .anima-listapersonas .anima-tabla__grid .MuiDataGrid-columnHeaders {
    border-bottom: none !important;
  }
  .anima-listapersonas .anima-tabla__grid .MuiDataGrid-cell[data-field="${PERSONA_TABLA_FIELD_ACCIONES}"] {
    overflow: visible !important;
  }
`;
 
const COLOR_MAIN = 'var(--color-cyan-19, #29474C)';
const COLOR_SECONDARY = 'var(--color-gray-600, #4b5563)';
const BORDER_COLOR = '#C4C4C4';
const LISTA_PERSONAS_PAGE_SIZE_DEFAULT = 10;
 
const DEFAULT_STATUS_VARIANT = {
  Activa: 'success',
  Archivada: 'inactive',
};

/**
 * Columna Estado (tabla): solo Activa o Archivada; Borrador y otros valores no se muestran.
 */
function getPersonaTablaEstadoDisplay(row) {
  const raw = (row?.estado ?? row?.status ?? '').toString().trim();
  if (!raw) return null;
  const key = raw.toLowerCase();
  if (key === 'activa') {
    return { label: 'Activa', variant: DEFAULT_STATUS_VARIANT.Activa };
  }
  if (key === 'archivada') {
    return { label: 'Archivada', variant: DEFAULT_STATUS_VARIANT.Archivada };
  }
  return null;
}

/** Fecha de última actividad para la columna Actividad (primer campo definido). */
function getPersonaUltimaActividadFecha(row) {
  return (
    row?.ultimaActividad
    ?? row?.ultimoAcceso
    ?? row?.fechaUltimaActividad
    ?? row?.fechaUltimoAcceso
    ?? row?.lastActivity
    ?? row?.lastActivityAt
    ?? null
  );
}

/**
 * Lista de personas (tabla / cards).
 *
 * **Paginación controlada (p. ej. backend):** pasá solo los `items` de la página actual, el total global y callbacks.
 * El número **subrayado** en “Registros” es **cuántas filas por página** quiere el usuario: al confirmarlo se llama
 * `onPageSizeChange(nuevoTamaño)` y seguido `onPageChange(páginaSugerida)` para mantener el primer registro visible;
 * el padre debe actualizar estado, `pageSize`, `totalPages`, volver a pedir datos al servidor si aplica y pasar el nuevo
 * slice en `items`. Sin `onPageSizeChange` en modo controlado, ese número queda solo lectura.
 *
 * **Paginación interna:** sin esas props, la lista pagina y cambia el tamaño de página en cliente sobre el array `items`.
 *
 * **Ver (tabla y cards):** el componente **no navega solo**: pasá `onViewClick` y ahí implementá la pantalla destino o la acción (p. ej. `navigate` de react-router, abrir drawer/modal, `window.open`, etc.). Se dispara al elegir **Ver** en el menú Acciones de la tabla y al pulsar el botón outline **Ver** en vista cards. Firma: `(persona, index, event) => void` — `persona` es el ítem de `items` (suele incluir `id`).
 *
 * @param {string} [viewActionText='Ver'] — Etiqueta de Ver (menú tabla y botón en cards).
 * @param {(persona: object, index: number, event: unknown) => void} [onViewClick] — Punto de extensión del consumidor para Ver (navegación u otra UX).
 * @param {boolean} [showViewCardButton=true] — Muestra u oculta Ver por fila en **tabla y cards** (salvo `shouldShowViewCardButton`).
 * @param {(persona: object, index: number) => boolean} [shouldShowViewCardButton] — Override por fila para Ver (tabla y cards).
 *
 * @param {object} props
 */
export const ListaPersonas = ({
  title = 'Personas',
  showTitle = true,
  items = [],
  /** Opcional: clic en tarjeta (vista cards), no afecta selección. En tabla, la selección va por fila/checkbox. */
  onItemClick,
  /** Ids seleccionados (modo controlado). Si no se pasa, se usa estado interno. */
  selectedIds,
  /** Callback de selección: (ids: Array<string|number>, context) => void */
  onSelectedIdsChange,
  /** Botón de filtros (al final de la barra de búsqueda en vista tabla). Por defecto visible; pasar `false` para ocultarlo. */
  showFiltersButton = true,
  filtersButtonLabel,
  filtersCount,
  activeFiltersCount,
  onFiltersClick,
  advancedFiltersModalTitle,
  advancedFiltersModalContent,
  advancedFiltersModalFooter,
  advancedFiltersModalSize,
  advancedFiltersApplyLabel,
  advancedFiltersCancelLabel,
  onAdvancedFiltersApply,
  onAdvancedFiltersCancel,
  advancedFiltersModalProps,
  /** Fila debajo del buscador y antes de la tabla (ej. filtros aplicados). */
  filtersArea,
  appliedFilters,
  onAppliedFilterRemove,
  onAppliedFiltersClear,
  showAppliedFiltersLabel,
  appliedFiltersLabel,
  appliedFiltersClearLabel,
  filtersAreaContainerClassName,
  filtersAreaContainerStyle,
  /** Acciones en masa (misma barra que la tabla). */
  onBulkEditClick,
  onBulkArchiveClick,
  onBulkExportClick,
  viewActionText = 'Ver',
  /**
   * Ver: el consumidor define qué ocurre (ruta, modal, drawer, etc.). Tabla = menú Acciones; cards = botón outline.
   * `(persona, index, event) => void` — `persona` es el elemento de `items`.
   */
  onViewClick,
  showViewCardButton = true,
  shouldShowViewCardButton,
  actionButtonText = '',
  onActionClick,
  archiveActionText = 'Archivar',
  unarchiveActionText = 'Desarchivar',
  onArchiveClick,
  onUnarchiveClick,
  deleteActionText = 'Eliminar',
  onDeleteClick,
  showEditCardButton = true,
  showArchiveCardButton = true,
  showDeleteCardButton = true,
  /** Vista cards: máximo de caracteres para Documento; si excede, aplica truncado con puntos suspensivos. */
  cardsDocumentoMaxChars,
  shouldShowEditCardButton,
  shouldShowArchiveCardButton,
  shouldShowDeleteCardButton,
  emptyMessage = 'No hay personas cargadas.',
  renderItem,
  searchValue,
  onSearchChange,
  searchPlaceholder,
  /** Con paginación controlada: cantidad de filas en `items` (página actual); alinear con lo que devuelve el backend. */
  registrosCurrent,
  /** Total de registros en servidor (para “Registros: … de N” y límites del número subrayado). */
  tableTotalCount,
  /** Opcional: rango 1-based explícito; si no, se calcula con página y tamaño de página. */
  registrosRangoDesde,
  registrosRangoHasta,
  /** Registros por página actual; debe coincidir con la petición al backend. Al editar el número subrayado, actualizar vía `onPageSizeChange`. */
  pageSize,
  /** Página actual 1-based (controlada). */
  currentPage: currentPageProp,
  /** Total de páginas (controlado); recalcular en el padre cuando cambie `pageSize` o el total. */
  totalPages: totalPagesProp,
  onPrevPage,
  onNextPage,
  /**
   * Paginación controlada: ir a la página `page` (1-based). También se invoca tras cambiar el tamaño de página
   * con la página sugerida para conservar el primer ítem visible; el padre puede aceptarla o ajustarla y luego pedir datos.
   */
  onPageChange,
  /**
   * Obligatoria para permitir editar el número subrayado en modo controlado. Recibe el tamaño ya acotado
   * (`clampRegistrosPorPagina`). Tras esto se llama `onPageChange` con la página sugerida.
   */
  onPageSizeChange,
  tableLoading = false,
  className = '',
  style = {},
  titleStyle = {},
  listStyle = {},
  itemClassName = '',
  itemStyle = {},
  ...props
}) => {
  const { t } = useTranslation();
  const [viewMode, setViewMode] = useState('tabla'); // 'tabla' | 'cards'
  const [internalPage, setInternalPage] = useState(1);
  const [internalPageSize, setInternalPageSize] = useState(LISTA_PERSONAS_PAGE_SIZE_DEFAULT);
  const [internalSelectedIds, setInternalSelectedIds] = useState(() => []);
  const isSelectionControlled = Array.isArray(selectedIds);
  const effectiveSelectedIds = isSelectionControlled ? selectedIds : internalSelectedIds;
  const selectedIdSet = useMemo(() => new Set(effectiveSelectedIds ?? []), [effectiveSelectedIds]);

  const handleToggleSelect = useCallback(
    (rowId, nextChecked, row) => {
      const next = new Set(selectedIdSet);
      if (nextChecked) next.add(rowId);
      else next.delete(rowId);
      const nextIds = Array.from(next);
      if (!isSelectionControlled) setInternalSelectedIds(nextIds);
      onSelectedIdsChange?.(nextIds, { rowId, checked: nextChecked, row });
    },
    [selectedIdSet, isSelectionControlled, onSelectedIdsChange],
  );

  const handlePersonaTableRowClick = useCallback(
    (params, event) => {
      if (isPersonaTableRowClickIgnoredForSelection(event?.target)) return;
      const rowId = params.id ?? params.row?.id;
      if (rowId == null) return;
      handleToggleSelect(rowId, !selectedSetHasId(selectedIdSet, rowId), params.row);
    },
    [selectedIdSet, handleToggleSelect],
  );

  const personasTableSx = useMemo(
    () => ({
      /* Quitar gris de hover por defecto del DataGrid; el tono solo aplica con fila seleccionada (checkbox). */
      '& .MuiDataGrid-row:hover': {
        backgroundColor: '#FFFFFF',
      },
      '& .MuiDataGrid-row:hover .MuiDataGrid-cell': {
        backgroundColor: '#FFFFFF',
      },
      [`& .MuiDataGrid-row.${PERSONA_TABLA_ROW_SELECTED_CLASS}`]: {
        backgroundColor: personaTablaRowSelectedOpaqueBg,
      },
      [`& .MuiDataGrid-row.${PERSONA_TABLA_ROW_SELECTED_CLASS} .MuiDataGrid-cell`]: {
        backgroundColor: personaTablaRowSelectedOpaqueBg,
      },
      /*
       * Columnas fijas con sticky + `disableVirtualization` en Tabla.
       * Sin desactivar virtualización, MUI deja de montar columnas al hacer scroll X y el sticky falla.
       * z-index ≥ cabeceras/celdas ancladas de MUI (40/30): si no, las columnas que hacen scroll se pintan encima.
       */
      '& .MuiDataGrid-columnHeader[data-field="__select"]': {
        position: 'sticky',
        left: 0,
        zIndex: 42,
        backgroundColor: 'var(--color-main-100, #D3DFE1)',
      },
      [`& .MuiDataGrid-row:not(.${PERSONA_TABLA_ROW_SELECTED_CLASS}) .MuiDataGrid-cell[data-field="__select"]`]: {
        position: 'sticky',
        left: 0,
        zIndex: 33,
        backgroundColor: '#FFFFFF',
      },
      '& .MuiDataGrid-columnHeader[data-field="nombreComercial"]': {
        position: 'sticky',
        left: PERSONA_TABLA_COL_SELECT_WIDTH_PX,
        zIndex: 41,
        backgroundColor: 'var(--color-main-100, #D3DFE1)',
      },
      [`& .MuiDataGrid-row:not(.${PERSONA_TABLA_ROW_SELECTED_CLASS}) .MuiDataGrid-cell[data-field="nombreComercial"]`]: {
        position: 'sticky',
        left: PERSONA_TABLA_COL_SELECT_WIDTH_PX,
        zIndex: 31,
        backgroundColor: '#FFFFFF',
      },
      /* Sticky: posición y capa en todas las filas (el fondo blanco solo si la fila no está marcada, arriba). */
      '& .MuiDataGrid-cell[data-field="__select"]': {
        position: 'sticky',
        left: 0,
        zIndex: 33,
      },
      '& .MuiDataGrid-cell[data-field="nombreComercial"]': {
        position: 'sticky',
        left: PERSONA_TABLA_COL_SELECT_WIDTH_PX,
        zIndex: 31,
      },
    }),
    [],
  );

  const getPersonasRowClassName = useCallback(
    (params) => {
      const { id } = params;
      if (id == null) return '';
      return selectedSetHasId(selectedIdSet, id) ? PERSONA_TABLA_ROW_SELECTED_CLASS : '';
    },
    [selectedIdSet],
  );

  const totalRegistros = items.length;
  const totalRegistrosLabel =
    tableTotalCount !== undefined && tableTotalCount !== null ? tableTotalCount : totalRegistros;
  const isPaginationControlled =
    typeof currentPageProp === 'number' ||
    typeof totalPagesProp === 'number' ||
    typeof onPrevPage === 'function' ||
    typeof onNextPage === 'function' ||
    registrosCurrent !== undefined ||
    tableTotalCount !== undefined;

  const currentPage = isPaginationControlled ? (currentPageProp ?? 1) : internalPage;
  const rawPageSize = isPaginationControlled ? (pageSize ?? internalPageSize) : internalPageSize;
  const effectivePageSize =
    totalRegistrosLabel > 0
      ? clampRegistrosPorPagina(rawPageSize, totalRegistrosLabel)
      : rawPageSize;

  useEffect(() => {
    if (isPaginationControlled || totalRegistrosLabel <= 0) return;
    const next = clampRegistrosPorPagina(internalPageSize, totalRegistrosLabel);
    if (next !== internalPageSize) setInternalPageSize(next);
  }, [isPaginationControlled, totalRegistrosLabel, internalPageSize]);

  const totalPages = isPaginationControlled
    ? (totalPagesProp ?? 1)
    : Math.max(1, Math.ceil(totalRegistros / effectivePageSize));

  const startIndex = isPaginationControlled ? 0 : (currentPage - 1) * effectivePageSize;
  const itemsForRender = isPaginationControlled
    ? items
    : items.slice(startIndex, startIndex + effectivePageSize);

  const pageIds = useMemo(
    () => itemsForRender.map((item) => item.id).filter((id) => id != null),
    [itemsForRender],
  );

  const handleTogglePageSelect = useCallback(
    (checked) => {
      if (pageIds.length === 0) return;
      const next = new Set(selectedIdSet);
      if (checked) {
        pageIds.forEach((id) => next.add(id));
      } else {
        pageIds.forEach((id) => next.delete(id));
      }
      const nextIds = Array.from(next);
      if (!isSelectionControlled) setInternalSelectedIds(nextIds);
      onSelectedIdsChange?.(nextIds, { pageToggle: true, checked, pageIds });
    },
    [pageIds, selectedIdSet, isSelectionControlled, onSelectedIdsChange],
  );

  const personasTablaColumns = useMemo(
    () => getPersonasTablaColumns(
      t,
      selectedIdSet,
      handleToggleSelect,
      pageIds,
      handleTogglePageSelect,
      viewActionText,
      onViewClick,
      showViewCardButton,
      shouldShowViewCardButton,
      actionButtonText,
      onActionClick,
      archiveActionText,
      unarchiveActionText,
      onArchiveClick,
      onUnarchiveClick,
      deleteActionText,
      onDeleteClick,
      showEditCardButton,
      showDeleteCardButton,
      showArchiveCardButton,
      shouldShowEditCardButton,
      shouldShowArchiveCardButton,
      shouldShowDeleteCardButton,
    ),
    [
      t,
      selectedIdSet,
      pageIds,
      handleTogglePageSelect,
      viewActionText,
      onViewClick,
      showViewCardButton,
      shouldShowViewCardButton,
      actionButtonText,
      onActionClick,
      archiveActionText,
      unarchiveActionText,
      onArchiveClick,
      onUnarchiveClick,
      deleteActionText,
      onDeleteClick,
      showEditCardButton,
      showDeleteCardButton,
      showArchiveCardButton,
      shouldShowEditCardButton,
      shouldShowArchiveCardButton,
      shouldShowDeleteCardButton,
      handleToggleSelect,
    ],
  );

  const registrosN =
    registrosCurrent !== undefined && registrosCurrent !== null
      ? registrosCurrent
      : itemsForRender.length;
  const hasPrevPage = currentPage > 1;
  const hasNextPage = currentPage < totalPages;
 
  const handlePrevPage = () => {
    if (isPaginationControlled) {
      onPrevPage?.();
    } else {
      setInternalPage((p) => Math.max(1, p - 1));
    }
  };
 
  const handleNextPage = () => {
    if (isPaginationControlled) {
      onNextPage?.();
    } else {
      setInternalPage((p) => Math.min(totalPages, p + 1));
    }
  };

  const canEditPageSize = !isPaginationControlled || typeof onPageSizeChange === 'function';

  const handleRegistrosPorPaginaCommit = useCallback(
    (rawNext) => {
      const clamped = clampRegistrosPorPagina(rawNext, totalRegistrosLabel);
      if (clamped === 0 || totalRegistrosLabel === 0) return;
      const newPage = resolvePageAfterPageSizeChange({
        currentPage,
        previousPageSize: effectivePageSize,
        nextPageSize: clamped,
        totalRegistrosLabel,
      });
      if (isPaginationControlled) {
        onPageSizeChange?.(clamped);
        onPageChange?.(newPage);
      } else {
        setInternalPageSize(clamped);
        setInternalPage(newPage);
      }
    },
    [
      totalRegistrosLabel,
      effectivePageSize,
      currentPage,
      isPaginationControlled,
      onPageSizeChange,
      onPageChange,
    ],
  );

  return (
    <div
      className={`anima-listapersonas ${className}`}
      style={{ ...style }}
      {...props}
    >
      <style>{toolbarStyles}</style>
      <div style={{ padding: 0, border: 'none', overflow: 'visible' }}>
        <Tabla
          users={itemsForRender}
          tableColumns={personasTablaColumns}
          searchPlaceholder={searchPlaceholder ?? t('empresa.table.searchPlaceholder', { defaultValue: 'Buscar personas' })}
          searchValue={searchValue}
          onSearchChange={onSearchChange}
          showFiltersButton={showFiltersButton}
          filtersButtonLabel={filtersButtonLabel}
          filtersCount={filtersCount}
          activeFiltersCount={activeFiltersCount}
          onFiltersClick={onFiltersClick}
          advancedFiltersModalTitle={advancedFiltersModalTitle}
          advancedFiltersModalContent={advancedFiltersModalContent}
          advancedFiltersModalFooter={advancedFiltersModalFooter}
          advancedFiltersModalSize={advancedFiltersModalSize}
          advancedFiltersApplyLabel={advancedFiltersApplyLabel}
          advancedFiltersCancelLabel={advancedFiltersCancelLabel}
          onAdvancedFiltersApply={onAdvancedFiltersApply}
          onAdvancedFiltersCancel={onAdvancedFiltersCancel}
          advancedFiltersModalProps={advancedFiltersModalProps}
          filtersArea={filtersArea}
          appliedFilters={appliedFilters}
          onAppliedFilterRemove={onAppliedFilterRemove}
          onAppliedFiltersClear={onAppliedFiltersClear}
          showAppliedFiltersLabel={showAppliedFiltersLabel}
          appliedFiltersLabel={appliedFiltersLabel}
          appliedFiltersClearLabel={appliedFiltersClearLabel}
          filtersAreaContainerClassName={filtersAreaContainerClassName}
          filtersAreaContainerStyle={filtersAreaContainerStyle}
          selectedCount={(effectiveSelectedIds?.length ?? 0)}
          onBulkEditClick={onBulkEditClick}
          onBulkArchiveClick={onBulkArchiveClick}
          onBulkExportClick={onBulkExportClick}
          tableLoading={tableLoading}
          sinContenido={items.length === 0}
          emptyStateLabel={emptyMessage}
          registrosCurrent={registrosN}
          tableTotalCount={totalRegistrosLabel}
          registrosRangoDesde={registrosRangoDesde}
          registrosRangoHasta={registrosRangoHasta}
          pageSize={effectivePageSize}
          currentPage={currentPage}
          totalPages={totalPages}
          onPrevPage={handlePrevPage}
          onNextPage={handleNextPage}
          onRegistrosPorPaginaCommit={canEditPageSize ? handleRegistrosPorPaginaCommit : undefined}
          toolbarIcons={[
            { ...TABLA_TOOLBAR_ICONS_DEFAULT[0], onClick: () => {} },
            { ...TABLA_TOOLBAR_ICONS_DEFAULT[1], onClick: () => setViewMode('tabla'), selected: viewMode === 'tabla' },
            {
              ...TABLA_TOOLBAR_ICONS_DEFAULT[2],
              href: undefined,
              onClick: () => setViewMode('cards'),
              ariaLabel: 'Cards personas',
              selected: viewMode === 'cards',
            },
          ]}
          rowHeight={72}
          disableVirtualization
          redBarSteadyLeftOnNarrow
          containerStyle={{ border: 'none', borderRadius: 0, minHeight: 0 }}
          onRowClick={handlePersonaTableRowClick}
          getRowClassName={getPersonasRowClassName}
          tableSx={personasTableSx}
          tableArea={
            viewMode === 'cards' ? (
              <CardsPersonas
                items={itemsForRender}
                loading={tableLoading}
                onItemClick={onItemClick}
                actionButtonText={actionButtonText}
                onActionClick={onActionClick}
                viewActionText={viewActionText}
                onViewClick={onViewClick}
                showViewCardButton={showViewCardButton}
                shouldShowViewCardButton={shouldShowViewCardButton}
                showEditButton={showEditCardButton}
                documentoMaxChars={cardsDocumentoMaxChars}
                shouldShowEditButton={shouldShowEditCardButton}
                emptyMessage={emptyMessage}
              />
            ) : undefined
          }
        />
      </div>
    </div>
  );
};
 
export default ListaPersonas;
