/* Formulario crear/editar alumno — datos, foto, expediente documental */

const studentFieldLabel = {
  fontSize: 11, fontWeight: 600, letterSpacing: 0.6,
  textTransform: 'uppercase',
};

const PortalPasswordField = ({ theme, label, value, onChange }) => (
  <label style={{ display: 'grid', gap: 6 }}>
    <span style={{ ...studentFieldLabel, color: theme.textDim }}>{label}</span>
    <div
      style={{
        display: 'flex', alignItems: 'center',
        background: theme.bgInput,
        border: `1px solid ${theme.border}`,
        borderRadius: 10, padding: '0 12px', height: 42,
        transition: 'border-color .2s',
      }}
      onFocus={e => { e.currentTarget.style.borderColor = theme.primary; }}
      onBlur={e => { e.currentTarget.style.borderColor = theme.border; }}
    >
      <input
        type="text"
        autoComplete="off"
        autoCorrect="off"
        autoCapitalize="off"
        spellCheck={false}
        data-form-type="other"
        data-lpignore="true"
        data-1p-ignore="true"
        name="tecos-portal-temp-password"
        value={value || ''}
        onChange={onChange}
        style={{
          flex: 1, width: '100%', background: 'transparent', border: 'none', outline: 'none',
          color: theme.text, fontSize: 14, fontFamily: 'Inter, sans-serif', height: '100%',
        }}
      />
    </div>
  </label>
);

/** Cobro proporcional del mes de ingreso (solo al crear alumno, opcional). */
const StudentProrateFirstMonth = ({ theme, enabled, onEnabledChange, unit, onUnitChange, joinedAt, monthlyFee, settings }) => {
  const preview = React.useMemo(() => {
    if (!enabled || !joinedAt || typeof computeProratedFirstMonthAmount !== 'function') return null;
    const s = settings || { monthly_fee: monthlyFee };
    return computeProratedFirstMonthAmount(s, joinedAt, unit === 'week' ? 'week' : 'day');
  }, [enabled, joinedAt, unit, monthlyFee, settings]);

  const baseLabel = monthlyFee != null && monthlyFee !== ''
    ? `$${Number(monthlyFee).toLocaleString('es-MX')}`
    : 'tarifa configurada';

  return (
    <div style={{
      gridColumn: '1 / -1',
      padding: 16,
      borderRadius: 12,
      background: enabled ? `${theme.primary}10` : theme.bgInput,
      border: `1px solid ${enabled ? theme.primary : theme.border}`,
    }}>
      <label style={{ display: 'flex', alignItems: 'flex-start', gap: 12, cursor: 'pointer' }}>
        <input
          type="checkbox"
          checked={!!enabled}
          onChange={(e) => onEnabledChange(e.target.checked)}
          style={{ marginTop: 3 }}
        />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 14, fontWeight: 700, color: theme.text, fontFamily: 'Inter, sans-serif' }}>
            Cobrar proporcional el mes de ingreso
          </div>
          <p style={{ margin: '6px 0 0', fontSize: 12, color: theme.textDim, lineHeight: 1.55, fontFamily: 'Inter, sans-serif' }}>
            <strong>Sin activar (recomendado si cobras el mes completo):</strong> usa el calendario de abajo — marca el mes de ingreso como <strong>Pagado</strong> si ya cobró, o déjalo <strong>Pendiente</strong> para cobrar después ({baseLabel}).
            <br /><br />
            <strong>Con activar:</strong> el mes de ingreso se calcula solo por días o semanas restantes; en el calendario igual puedes marcarlo pagado o pendiente, pero con ese monto proporcional.
          </p>
        </div>
      </label>
      {enabled && (
        <div style={{ marginTop: 14, paddingTop: 14, borderTop: `1px solid ${theme.border}` }}>
          <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: 1, textTransform: 'uppercase', color: theme.textMute, marginBottom: 10, fontFamily: 'Inter, sans-serif' }}>
            Calcular proporcional por
          </div>
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginBottom: 14 }}>
            {[
              { id: 'day', label: 'Días del mes', hint: 'Ej. faltan 7 días → 7/31 de la mensualidad' },
              { id: 'week', label: 'Semanas del mes', hint: 'Ej. falta 1 semana → 1/5 de la mensualidad' },
            ].map((opt) => (
              <button
                key={opt.id}
                type="button"
                onClick={() => onUnitChange(opt.id)}
                style={{
                  flex: '1 1 200px',
                  padding: '12px 14px',
                  borderRadius: 10,
                  border: `2px solid ${unit === opt.id ? theme.primary : theme.border}`,
                  background: unit === opt.id ? `${theme.primary}14` : theme.bgCard,
                  cursor: 'pointer',
                  textAlign: 'left',
                }}
              >
                <div style={{ fontWeight: 700, fontSize: 13, color: theme.text, fontFamily: 'Inter, sans-serif' }}>{opt.label}</div>
                <div style={{ fontSize: 11, color: theme.textDim, marginTop: 4, fontFamily: 'Inter, sans-serif' }}>{opt.hint}</div>
              </button>
            ))}
          </div>
          {preview && (
            <div style={{
              padding: 14,
              borderRadius: 10,
              background: theme.bgCard,
              border: `1px solid ${theme.border}`,
            }}>
              <div style={{ fontSize: 11, fontWeight: 700, color: theme.primary, letterSpacing: 1, textTransform: 'uppercase', fontFamily: 'Inter, sans-serif' }}>
                Vista previa — mes de ingreso
              </div>
              <div style={{ fontFamily: 'Bebas Neue, sans-serif', fontSize: 32, color: theme.text, letterSpacing: 1, marginTop: 6 }}>
                ${typeof formatMoneyMX === 'function' ? formatMoneyMX(preview.amount) : preview.amount}
                <span style={{ fontSize: 14, color: theme.textDim, fontFamily: 'Inter, sans-serif', fontWeight: 600, marginLeft: 8 }}>
                  {preview.fullMonth ? 'mes completo' : 'proporcional'}
                </span>
              </div>
              <div style={{ fontSize: 12, color: theme.textDim, marginTop: 6, fontFamily: 'Inter, sans-serif' }}>{preview.formula}</div>
              {!preview.fullMonth && (
                <p style={{ fontSize: 11, color: theme.textMute, margin: '8px 0 0', fontFamily: 'Inter, sans-serif' }}>
                  Los recargos por día del mes (configuración → tarifas) se aplican aparte cuando registre o cobre el pago.
                </p>
              )}
            </div>
          )}
        </div>
      )}
    </div>
  );
};

const StudentPaidMonthsPicker = ({
  theme, year, selected, onChange, monthlyFee, joinedAt,
  prorateFirstMonth = false, prorateUnit = 'day', settings = null,
}) => {
  const labels = typeof MONTH_LABELS !== 'undefined'
    ? MONTH_LABELS
    : ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'];
  const now = new Date();
  const currentMonth = now.getMonth();
  const isCurrentYear = year === now.getFullYear();
  const firstBillable = typeof firstBillableMonthInYear === 'function'
    ? firstBillableMonthInYear(year, joinedAt)
    : 0;
  const noBillableYear = firstBillable >= 12;
  const beforeJoin = (idx) => noBillableYear || idx < firstBillable;
  const enrollmentIdx = (() => {
    if (!joinedAt || typeof isEnrollmentMonth !== 'function') return -1;
    const jd = typeof parseJoinDateLocal === 'function' ? parseJoinDateLocal(joinedAt) : new Date(joinedAt);
    if (!jd || jd.getFullYear() !== year) return -1;
    return isEnrollmentMonth(year, jd.getMonth(), joinedAt) ? jd.getMonth() : -1;
  })();
  const amountForMonth = (idx) => {
    const s = settings || { monthly_fee: monthlyFee };
    if (typeof paymentAmountAndConceptForSeedMonth !== 'function') {
      return Number(monthlyFee) || 0;
    }
    return paymentAmountAndConceptForSeedMonth(year, idx, joinedAt, s, {
      prorateFirstMonth: !!prorateFirstMonth,
      prorateUnit: prorateUnit === 'week' ? 'week' : 'day',
    }).amount;
  };
  const toggle = (idx) => {
    if (isCurrentYear && idx > currentMonth) return;
    if (beforeJoin(idx)) return;
    const next = new Set(selected);
    if (next.has(idx)) next.delete(idx);
    else next.add(idx);
    onChange(next);
  };
  const feeLabel = monthlyFee != null && monthlyFee !== ''
    ? `$${Number(monthlyFee).toLocaleString('es-MX')}`
    : 'tarifa configurada';
  const fmt = (n) => (typeof formatMoneyMX === 'function' ? formatMoneyMX(n) : Number(n).toLocaleString('es-MX'));
  return (
    <div style={{
      gridColumn: '1 / -1',
      padding: 14,
      borderRadius: 10,
      background: prorateFirstMonth ? `${theme.warning}08` : theme.bgInput,
      border: `1px solid ${prorateFirstMonth ? `${theme.warning}44` : theme.border}`,
    }}>
      <div style={{ ...studentFieldLabel, color: theme.textDim, marginBottom: 6 }}>
        ¿Qué meses ya pagó? — {year}
      </div>
      <p style={{ fontSize: 12, color: theme.textDim, margin: '0 0 12px', fontFamily: 'Inter, sans-serif', lineHeight: 1.55 }}>
        {prorateFirstMonth ? (
          <>
            Toca cada mes: <strong>Pagado</strong> = ya cobrado (en el mes de ingreso se guarda el monto proporcional).
            <strong> Pendiente</strong> = aún debe pagar en su portal.
          </>
        ) : (
          <>
            Toca cada mes desde su ingreso: <strong>Pagado</strong> = mensualidad completa ({feeLabel}) ya cobrada.
            <strong> Pendiente</strong> = se le genera adeudo en el portal para cobrar después.
            Si no marcas el mes de ingreso, quedará <strong>pendiente</strong> con la tarifa completa.
          </>
        )}
      </p>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)', gap: 8 }}>
        {labels.map((name, i) => {
          const on = selected.has(i);
          const future = isCurrentYear && i > currentMonth;
          const preJoin = beforeJoin(i);
          const disabled = future || preJoin;
          const isEnrollment = i === enrollmentIdx;
          const monthAmt = !preJoin && !disabled ? amountForMonth(i) : null;
          return (
            <button
              key={name}
              type="button"
              disabled={disabled}
              onClick={() => toggle(i)}
              style={{
                padding: '10px 8px',
                borderRadius: 8,
                border: `1.5px solid ${on ? theme.success : (isEnrollment ? theme.primary : theme.border)}`,
                background: on ? `${theme.success}18` : (isEnrollment ? `${theme.primary}10` : theme.bgCard),
                color: on ? theme.success : theme.text,
                cursor: disabled ? 'not-allowed' : 'pointer',
                opacity: disabled ? 0.35 : 1,
                fontFamily: 'Bebas Neue, sans-serif',
                fontSize: 16,
                letterSpacing: 0.5,
              }}
            >
              {name}
              {isEnrollment && (
                <div style={{ fontSize: 8, fontFamily: 'Inter, sans-serif', fontWeight: 700, color: theme.primary, marginTop: 2 }}>
                  INGRESO
                </div>
              )}
              <div style={{
                fontSize: 9,
                fontFamily: 'Inter, sans-serif',
                fontWeight: 700,
                marginTop: 4,
                textTransform: 'uppercase',
                color: on ? theme.success : theme.textMute,
              }}>
                {preJoin ? '—' : (on ? 'Pagado' : 'Pendiente')}
              </div>
              {!preJoin && !disabled && monthAmt != null && (
                <div style={{
                  fontSize: 9,
                  fontFamily: 'Inter, sans-serif',
                  fontWeight: 600,
                  marginTop: 3,
                  color: isEnrollment && prorateFirstMonth ? theme.primary : theme.textDim,
                }}>
                  ${fmt(monthAmt)}
                </div>
              )}
            </button>
          );
        })}
      </div>
    </div>
  );
};

const StudentFormModal = ({ open, onClose, theme, initial, onSaved }) => {
  const [tab, setTab] = React.useState('datos');
  const [form, setForm] = React.useState({});
  const [codeDigits, setCodeDigits] = React.useState('');
  const [ageDisplay, setAgeDisplay] = React.useState('');
  const [photoBlob, setPhotoBlob] = React.useState(null);
  const [docs, setDocs] = React.useState([]);
  const [docRequirements, setDocRequirements] = React.useState(() => (
    typeof mergeDocumentRequirements === 'function'
      ? mergeDocumentRequirements(initial?.document_requirements)
      : null
  ));
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState('');
  const [paidMonths, setPaidMonths] = React.useState(() => new Set());
  const [monthlyFee, setMonthlyFee] = React.useState(null);
  const [billingSettings, setBillingSettings] = React.useState(null);
  const [prorateFirstMonth, setProrateFirstMonth] = React.useState(false);
  const [prorateUnit, setProrateUnit] = React.useState('day');
  const billingYear = new Date().getFullYear();
  const isEdit = !!(initial && initial._uuid);

  const loadDocs = React.useCallback(async () => {
    if (!initial?._uuid) { setDocs([]); return; }
    try {
      const rows = await fetchStudentDocuments(initial._uuid);
      setDocs(rows || []);
    } catch (e) {
      console.warn('[Tecos] documentos alumno', e);
    }
  }, [initial?._uuid]);

  React.useEffect(() => {
    if (!open) return;
    setErr('');
    setTab('datos');
    setPhotoBlob(null);
    setProrateFirstMonth(false);
    setProrateUnit('day');
    setDocRequirements(typeof mergeDocumentRequirements === 'function'
      ? mergeDocumentRequirements(initial?.document_requirements)
      : (typeof defaultDocumentRequirements === 'function' ? defaultDocumentRequirements() : null));
    if (isEdit && initial?.id) {
      setCodeDigits(formatTecCodeDigits(String(initial.id).replace(/^TEC-?/i, '')));
    } else {
      setCodeDigits('');
      (async () => {
        try {
          const next = typeof fetchNextStudentCodeDigits === 'function'
            ? await fetchNextStudentCodeDigits()
            : '001';
          setCodeDigits(next || '001');
        } catch (e) {
          console.warn('[Tecos] siguiente ID alumno', e);
          setCodeDigits('001');
        }
      })();
    }
    const tutorPh = parsePhoneWithDial(initial?.phone !== '—' ? initial?.phone : '');
    const studentPh = parsePhoneWithDial(initial?.student_phone !== '—' ? initial?.student_phone : '');
    setForm({
      full_name: initial?.name || '',
      birth_date: initial?.birth_date ? String(initial.birth_date).slice(0, 10) : '',
      category: initial?.cat !== '—' ? initial?.cat : '',
      status: initial?.status === 'inactivo' ? 'inactivo' : 'activo',
      activo: initial?.status !== 'inactivo',
      joined_at: initial?.joined_at ? String(initial.joined_at).slice(0, 10) : new Date().toISOString().slice(0, 10),
      tutor_name: initial?.tutor !== '—' ? initial?.tutor : '',
      tutor_phone_dial: tutorPh.dial,
      tutor_phone_national: tutorPh.national,
      tutor_email: initial?.email !== '—' ? initial?.email : '',
      student_phone_dial: studentPh.dial,
      student_phone_national: studentPh.national,
      portal_password: '',
      notes: initial?.notes || '',
    });
    setAgeDisplay(initial?.birth_date ? String(ageFromBirthDate(initial.birth_date)) : '');
    loadDocs();
  }, [open, initial, isEdit, loadDocs]);

  React.useEffect(() => {
    if (!form.birth_date) { setAgeDisplay(''); return; }
    setAgeDisplay(String(ageFromBirthDate(form.birth_date)));
  }, [form.birth_date]);

  React.useEffect(() => {
    if (!open) return;
    fetchAcademySettings()
      .then((s) => {
        setBillingSettings(s);
        setMonthlyFee(s?.monthly_fee);
      })
      .catch(() => {
        setBillingSettings(null);
        setMonthlyFee(null);
      });
  }, [open]);

  React.useEffect(() => {
    if (!open || isEdit) return;
    setPaidMonths(new Set());
  }, [open, isEdit, form.joined_at, billingYear]);

  React.useEffect(() => {
    if (!open || isEdit || typeof firstBillableMonthInYear !== 'function') return;
    const first = firstBillableMonthInYear(billingYear, form.joined_at);
    if (first >= 12) {
      setPaidMonths(new Set());
      return;
    }
    const maxM = billingYear === new Date().getFullYear() ? new Date().getMonth() : 11;
    setPaidMonths((prev) => {
      const next = new Set([...prev].filter((i) => i >= first && i <= maxM));
      return next.size === prev.size ? prev : next;
    });
  }, [open, isEdit, form.joined_at, billingYear]);

  const antiguedad = computeSeniorityLabel(form.joined_at);
  const previewCode = isEdit ? (initial?.id || buildTecStudentCode(codeDigits)) : buildTecStudentCode(codeDigits);

  const set = (k) => (e) => setForm(f => ({ ...f, [k]: e.target.value }));

  const save = async () => {
    if (!form.full_name?.trim()) {
      setErr('El nombre completo es obligatorio.');
      return;
    }
    if (!isEdit && !codeDigits.trim()) {
      setErr('Escribe la numeración del ID (3 dígitos).');
      return;
    }
    if (!isEdit && !form.portal_password?.trim()) {
      setErr('Define una contraseña temporal para el portal del alumno.');
      return;
    }
    const portalPwd = form.portal_password?.trim() || '';
    if (!isEdit && portalPwd.length < 8) {
      setErr('La contraseña temporal debe tener al menos 8 caracteres.');
      return;
    }
    if (isEdit && portalPwd && portalPwd.length < 8) {
      setErr('La nueva contraseña debe tener al menos 8 caracteres.');
      return;
    }
    setSaving(true);
    setErr('');
    try {
      const payload = {
        ...form,
        code_digits: codeDigits,
        status: form.activo ? 'activo' : 'inactivo',
        student_phone: combinePhoneWithDial(form.student_phone_dial, form.student_phone_national),
        tutor_phone: combinePhoneWithDial(form.tutor_phone_dial, form.tutor_phone_national),
        paid_months: isEdit ? undefined : (() => {
          const first = typeof firstBillableMonthInYear === 'function'
            ? firstBillableMonthInYear(billingYear, form.joined_at)
            : 0;
          if (first >= 12) return [];
          return Array.from(paidMonths).filter((i) => i >= first);
        })(),
        prorate_first_month: !isEdit && prorateFirstMonth,
        prorate_unit: prorateUnit === 'week' ? 'week' : 'day',
      };
      delete payload.student_phone_dial;
      delete payload.student_phone_national;
      delete payload.tutor_phone_dial;
      delete payload.tutor_phone_national;
      let row;
      if (isEdit) row = await updateStudent(initial._uuid, payload);
      else row = await createStudent(payload);

      const code = row.code || previewCode;
      const studentUuid = row.id || initial?._uuid;
      if (photoBlob && code && studentUuid) {
        try {
          const file = new File([photoBlob], `${code}.jpg`, { type: 'image/jpeg' });
          const path = await uploadGalleryFile(file, `students/${code}`);
          await updateStudent(studentUuid, { ...payload, photo_path: path });
        } catch (photoErr) {
          onSaved?.();
          setErr(`Alumno ${code} guardado correctamente, pero la foto no se subió: ${photoErr.message || photoErr}`);
          setSaving(false);
          return;
        }
      }
      onSaved?.();
      onClose();
    } catch (e) {
      setErr(e.message || 'No se pudo guardar');
    }
    setSaving(false);
  };

  const fieldLabel = { ...studentFieldLabel, color: theme.textDim };

  const tabBtn = (id, label) => (
    <button type="button" key={id} onClick={() => setTab(id)} style={{
      padding: '12px 16px', border: 'none', background: 'transparent', cursor: 'pointer',
      fontFamily: 'Inter, sans-serif', fontSize: 12, fontWeight: 700, textTransform: 'uppercase',
      color: tab === id ? theme.primary : theme.textDim,
      borderBottom: `2px solid ${tab === id ? theme.primary : 'transparent'}`,
    }}>{label}</button>
  );

  return (
    <Modal open={open} onClose={onClose} theme={theme} width={960} innerScroll>
      <div style={{ padding: 20, borderBottom: `1px solid ${theme.border}`, display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexShrink: 0 }}>
        <h3 style={{ fontFamily: 'Bebas Neue, sans-serif', fontSize: 28, color: theme.text, margin: 0, letterSpacing: 1, fontWeight: 400 }}>
          {isEdit ? 'EDITAR ALUMNO' : 'NUEVO ALUMNO'}
        </h3>
        <button type="button" onClick={onClose} style={{ width: 36, height: 36, borderRadius: 8, background: theme.bgInput, border: `1px solid ${theme.border}`, color: theme.text, cursor: 'pointer', display: 'grid', placeItems: 'center' }}>
          <Icon name="x" size={16} />
        </button>
      </div>

      <div style={{ display: 'flex', borderBottom: `1px solid ${theme.border}`, padding: '0 20px' }}>
        {tabBtn('datos', 'Datos')}
        {tabBtn('expediente', 'Expediente / papelería')}
      </div>

      <div style={{ padding: 24, flex: 1, minHeight: 0, overflowY: 'auto' }}>
        {tab === 'datos' && (
          <div style={{ display: 'grid', gridTemplateColumns: '220px 1fr', gap: 24, alignItems: 'start' }}>
            <PhotoCropUploader theme={theme} initialUrl={initial?.photoUrl} onBlobReady={setPhotoBlob} size={200} />
            <div style={{
              display: 'grid',
              gridTemplateColumns: 'repeat(3, minmax(0, 1fr))',
              columnGap: 16,
              rowGap: 14,
              alignContent: 'start',
            }}>
              <div style={{ gridColumn: '1 / -1', minWidth: 0 }}>
                <Input theme={theme} label="Nombre completo" value={form.full_name} onChange={set('full_name')} icon="user" />
              </div>
              <div style={{ minWidth: 0 }}>
                <span style={fieldLabel}>ID alumno</span>
                <div style={{ display: 'flex', marginTop: 6, height: 42 }}>
                  <span style={{
                    display: 'flex', alignItems: 'center', padding: '0 14px',
                    background: theme.bgInput, border: `1px solid ${theme.border}`,
                    borderRadius: '10px 0 0 10px', fontFamily: 'Bebas Neue, sans-serif', fontSize: 20, color: theme.primary,
                  }}>TEC</span>
                  <input
                    value={codeDigits}
                    onChange={e => setCodeDigits(
                      typeof formatTecCodeDigitsInput === 'function'
                        ? formatTecCodeDigitsInput(e.target.value)
                        : e.target.value.replace(/\D/g, '').slice(0, 3)
                    )}
                    onBlur={e => setCodeDigits(formatTecCodeDigits(e.target.value))}
                    disabled={isEdit}
                    placeholder="001"
                    maxLength={3}
                    inputMode="numeric"
                    style={{
                      flex: 1, minWidth: 0, padding: '0 12px', border: `1px solid ${theme.border}`, borderLeft: 'none',
                      borderRadius: '0 10px 10px 0', background: isEdit ? theme.bgElev : theme.bgInput,
                      color: theme.text, fontFamily: 'Bebas Neue, sans-serif', fontSize: 22, letterSpacing: 2,
                      outline: 'none', height: '100%',
                    }}
                  />
                </div>
                <div style={{ fontSize: 11, color: theme.textDim, marginTop: 6, lineHeight: 1.4 }}>
                  Vista previa: <strong style={{ color: theme.primary }}>{previewCode || 'TEC___'}</strong>
                  {!isEdit && ' · Sin guion'}
                  <div style={{ marginTop: 4 }}>
                    Al crear, se propone el siguiente ID libre
                    {!isEdit && previewCode ? ` (${previewCode})` : ''}.
                    No puede repetirse mientras exista otro alumno con el mismo código.
                  </div>
                </div>
              </div>
              <div style={{ minWidth: 0 }}>
                <PortalPasswordField
                  theme={theme}
                  label={isEdit ? 'Nueva contraseña (opcional, mín. 8)' : 'Contraseña temporal (portal, mín. 8)'}
                  value={form.portal_password}
                  onChange={set('portal_password')}
                />
              </div>
              <div style={{ minWidth: 0 }}>
                <Input theme={theme} label="Fecha de nacimiento" type="date" value={form.birth_date} onChange={set('birth_date')} icon="cal" />
              </div>
              <div style={{ minWidth: 0 }}>
                <Input theme={theme} label="Edad" value={ageDisplay} readOnly />
              </div>
              <div style={{ minWidth: 0 }}>
                <Input theme={theme} label="Categoría" value={form.category} onChange={set('category')} icon="medal" />
              </div>
              <div style={{ minWidth: 0 }}>
                <Input theme={theme} label="Fecha de ingreso" type="date" value={form.joined_at} onChange={set('joined_at')} icon="cal" />
              </div>
              <div style={{ minWidth: 0 }}>
                <Input theme={theme} label="Antigüedad" value={antiguedad} readOnly />
              </div>
              {!isEdit && (
                <>
                  <StudentProrateFirstMonth
                    theme={theme}
                    enabled={prorateFirstMonth}
                    onEnabledChange={setProrateFirstMonth}
                    unit={prorateUnit}
                    onUnitChange={setProrateUnit}
                    joinedAt={form.joined_at}
                    monthlyFee={monthlyFee}
                    settings={billingSettings}
                  />
                  <StudentPaidMonthsPicker
                    theme={theme}
                    year={billingYear}
                    selected={paidMonths}
                    onChange={setPaidMonths}
                    monthlyFee={monthlyFee}
                    joinedAt={form.joined_at}
                    prorateFirstMonth={prorateFirstMonth}
                    prorateUnit={prorateUnit}
                    settings={billingSettings}
                  />
                </>
              )}
              <div style={{
                gridColumn: '1 / -1',
                display: 'grid',
                gridTemplateColumns: 'repeat(2, minmax(0, 1fr))',
                columnGap: 16,
                rowGap: 14,
                paddingTop: 12,
                marginTop: 4,
                borderTop: `1px solid ${theme.border}`,
              }}>
                <div style={{ gridColumn: '1 / -1', minWidth: 0 }}>
                  <Input theme={theme} label="Tutor / responsable" value={form.tutor_name} onChange={set('tutor_name')} icon="user" />
                </div>
                <div style={{ minWidth: 0 }}>
                  <PhoneInput
                    theme={theme}
                    label="Teléfono del alumno"
                    dial={form.student_phone_dial}
                    national={form.student_phone_national}
                    onDialChange={v => setForm(f => ({ ...f, student_phone_dial: v }))}
                    onNationalChange={v => setForm(f => ({ ...f, student_phone_national: v }))}
                  />
                </div>
                <div style={{ minWidth: 0 }}>
                  <PhoneInput
                    theme={theme}
                    label="Teléfono del tutor"
                    dial={form.tutor_phone_dial}
                    national={form.tutor_phone_national}
                    onDialChange={v => setForm(f => ({ ...f, tutor_phone_dial: v }))}
                    onNationalChange={v => setForm(f => ({ ...f, tutor_phone_national: v }))}
                  />
                </div>
                <div style={{ gridColumn: '1 / -1', minWidth: 0 }}>
                  <Input theme={theme} label="Correo electrónico" value={form.tutor_email} onChange={set('tutor_email')} />
                </div>
              </div>
              <label style={{
                gridColumn: '1 / -1', display: 'flex', alignItems: 'center', gap: 10,
                padding: 12, borderRadius: 8, background: theme.bgInput, border: `1px solid ${theme.border}`, cursor: 'pointer',
              }}>
                <input type="checkbox" checked={!!form.activo}
                  onChange={e => setForm(f => ({ ...f, activo: e.target.checked, status: e.target.checked ? 'activo' : 'inactivo' }))} />
                <span style={{ fontSize: 13, fontWeight: 600, color: theme.text, fontFamily: 'Inter, sans-serif' }}>Alumno activo</span>
              </label>
            </div>
          </div>
        )}

        {tab === 'expediente' && (
          <div style={{ display: 'grid', gap: 12 }}>
            {!isEdit && (
              <div style={{ padding: 12, borderRadius: 8, background: `${theme.warning}15`, border: `1px solid ${theme.warning}44`, fontSize: 13, color: theme.textDim }}>
                Guarda primero al alumno en la pestaña Datos; después podrás subir papelería aquí o desde el expediente.
              </div>
            )}
            {isEdit && (
              <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
                <Btn theme={theme} kind="soft" icon="doc" size="sm" onClick={async () => {
                  setSaving(true);
                  try {
                    const [payRes, settings] = await Promise.all([
                      fetchStudentPaymentsByUuid(initial._uuid),
                      fetchAcademySettings(),
                    ]);
                    await exportStudentExpedientePdf(initial, {
                      payments: payRes,
                      documents: docs,
                      documentRequirements: docRequirements,
                      settings,
                    });
                  } catch (e) { alert(e.message); }
                  setSaving(false);
                }}>
                  Descargar expediente PDF
                </Btn>
              </div>
            )}
            {isEdit && typeof StudentDocumentsChecklist === 'function' ? (
              <StudentDocumentsChecklist
                theme={theme}
                docs={docs}
                requirements={docRequirements}
                canUpload
                canRemove
                canEditRequirements
                studentId={initial._uuid}
                studentCode={initial.id || previewCode}
                onUploadFile={async (docType, file) => {
                  await uploadStudentDocument({
                    studentId: initial._uuid,
                    studentCode: initial.id || previewCode,
                    docType,
                    file,
                  });
                }}
                onRemoveDoc={async (doc) => {
                  await removeStudentDocument(doc.id);
                }}
                onUploaded={loadDocs}
                readOnlyHint="Marca «Aplica» en cada documento. El alumno solo sube los que aplican en Mi papelería."
              />
            ) : (
              <p style={{ fontSize: 12, color: theme.textDim, fontFamily: 'Inter, sans-serif', margin: 0 }}>
                Tras crear el alumno podrás subir papelería aquí o el alumno desde su portal.
              </p>
            )}
          </div>
        )}

        {err && <div style={{ marginTop: 12, color: theme.danger, fontSize: 13 }}>{err}</div>}
      </div>

      <div style={{ padding: '16px 24px', borderTop: `1px solid ${theme.border}`, display: 'flex', justifyContent: 'flex-end', gap: 10, flexShrink: 0 }}>
        <Btn theme={theme} kind="ghost" onClick={onClose}>Cancelar</Btn>
        {tab === 'datos' && (
          <Btn theme={theme} icon="check" onClick={save} disabled={saving}>
            {saving ? 'Guardando…' : (isEdit ? 'Guardar cambios' : 'Crear alumno y portal')}
          </Btn>
        )}
      </div>
    </Modal>
  );
};

Object.assign(window, { StudentFormModal });
