// ============================================================
// Módulo Conversión
// ============================================================
const CONVERSION_FORMATS = [
  { key: 'jpg', label: 'JPG', folder: '1.JPG', accept: 'image/jpeg,.jpg,.jpeg', extensions: ['jpg', 'jpeg'], multiple: true, help: 'Imágenes JPG o JPEG' },
  { key: 'tiff', label: 'TIFF', folder: '2.TIFF', accept: 'image/tiff,.tif,.tiff', extensions: ['tif', 'tiff'], multiple: true, help: 'Imágenes TIFF o TIF' },
  { key: 'pdf_color', label: 'PDF Color', folder: '3. PDF COLOR', accept: 'application/pdf,.pdf', extensions: ['pdf'], multiple: false, help: 'Un archivo PDF a color' },
  { key: 'pdf_bw', label: 'PDF B&N', folder: '4. PDF BYN', accept: 'application/pdf,.pdf', extensions: ['pdf'], multiple: false, help: 'Un archivo PDF en blanco y negro' },
  { key: 'epub', label: 'E-PUB', folder: '5.E-PUB', accept: 'application/x-msdownload,application/octet-stream,.exe', extensions: ['exe'], multiple: false, help: 'Un archivo ejecutable EXE para E-PUB' },
  { key: 'pdf_optimized', label: 'PDF optimizado', folder: '6.PDF OPTIMIZADO', accept: 'application/pdf,.pdf', extensions: ['pdf'], multiple: false, help: 'Un archivo PDF optimizado' },
];

const CONVERSION_UPLOAD_BATCH_SIZE = 50;

const conversionFileExtension = fileName => {
  const parts = String(fileName || '').toLowerCase().split('.');
  return parts.length > 1 ? parts.pop() : '';
};

const formatConversionDate = (value) => {
  if (!value) return '—';
  const date = new Date(String(value).replace(' ', 'T'));
  if (Number.isNaN(date.getTime())) return String(value);
  return date.toLocaleDateString('es-MX');
};

const ConversionLocal = ({ libros, currentUser, onUpdate, onSelectBook }) => {
  const FORMATOS = [
    { key: 'edicionJpg', label: 'Edición JPG', abrev: 'JPG' },
    { key: 'conversionTiff', label: 'Conversión TIFF', abrev: 'TIFF' },
    { key: 'pdfColor', label: 'PDF Color', abrev: 'PDF-C' },
    { key: 'pdfBn', label: 'PDF Blanco y Negro', abrev: 'PDF-BN' },
    { key: 'epub', label: 'E-PUB', abrev: 'EPUB' },
  ];
  const [convirtiendo, setConvirtiendo] = useState(null);
  const [formatos, setFormatos] = useState({});
  const pendientes = libros.filter(l => l.estatus === 'aceptado');
  const enCurso = libros.filter(l => l.estatus === 'en_conversion');
  const finalizados = libros.filter(l => l.estatus === 'finalizado');
  const iniciarConversion = libro => onUpdate(libro.cons, { estatus: 'en_conversion', fechaConversion: '2026-08-02' });
  const abrirConversion = libro => { setConvirtiendo(libro); setFormatos(Object.fromEntries(FORMATOS.map(f => [f.key, Boolean(libro[f.key])]))); };
  const guardarFormatos = () => {
    if (!convirtiendo) return;
    const todos = FORMATOS.every(f => formatos[f.key]);
    onUpdate(convirtiendo.cons, { ...formatos, fechaConversion: convirtiendo.fechaConversion || '2026-08-02', estatus: todos ? 'finalizado' : 'en_conversion', statusFinal: todos ? 'FINALIZADO' : null });
    setConvirtiendo(null);
  };
  return (
    <div className="stack">
      <div className="kpi-grid" style={{ gridTemplateColumns: 'repeat(3, 1fr)' }}>
        <KPI label="Pendientes de iniciar" value={pendientes.length} sub="Aceptados en CC" tone="primary"/>
        <KPI label="En conversión" value={enCurso.length} sub="Con formatos parciales" tone="amber"/>
        <KPI label="Finalizados" value={finalizados.length} sub="Todos los formatos completos" tone="success"/>
      </div>
      <div className="card"><div className="card-header"><Icon name="convert"/><div><div className="card-title">Libros en conversión</div></div></div><div className="table-wrap"><table className="data"><tbody>{pendientes.map(l=><tr key={l.cons}><td>#{l.cons}</td><td>{l.titulo}</td><td><button className="btn btn-primary btn-sm" onClick={()=>iniciarConversion(l)}>Tomar</button></td></tr>)}{enCurso.map(l=><tr key={l.cons}><td>#{l.cons}</td><td>{l.titulo}</td><td><button className="btn btn-primary btn-sm" onClick={()=>abrirConversion(l)}>Subir formatos</button></td></tr>)}</tbody></table></div></div>
      <Modal open={!!convirtiendo} onClose={()=>setConvirtiendo(null)} title="Actualizar formatos" footer={<><button className="btn" onClick={()=>setConvirtiendo(null)}>Cancelar</button><button className="btn btn-primary" onClick={guardarFormatos}>Guardar</button></>}>
        <div className="stack">{FORMATOS.map(f=><label key={f.key}><input type="checkbox" checked={Boolean(formatos[f.key])} onChange={()=>setFormatos({...formatos,[f.key]:!formatos[f.key]})}/> {f.label}</label>)}</div>
      </Modal>
    </div>
  );
};

const ConversionServer = ({ currentUser, onSessionExpired }) => {
  const [state, setState] = useState({ status: 'loading', error: '', available: [], inProgress: [], finished: [], stats: {} });
  const [reloadToken, setReloadToken] = useState(0);
  const [feedback, setFeedback] = useState(null);
  const [claimBook, setClaimBook] = useState(null);
  const [uploadItem, setUploadItem] = useState(null);
  const [files, setFiles] = useState({});
  const [uploadedFormats, setUploadedFormats] = useState({});
  const [formatSaving, setFormatSaving] = useState({});
  const [uploadProgress, setUploadProgress] = useState({});
  const [saving, setSaving] = useState(false);
  const conversionFilesRef = useRef({});

  useEffect(() => {
    let active = true;
    const controller = new AbortController();
    const load = async () => {
      setState(previous => ({ ...previous, status: 'loading', error: '' }));
      try {
        const response = await window.apiRequest('conversion/dashboard.php', { signal: controller.signal });
        if (!active) return;
        const data = response?.data || {};
        setState({ status: 'loaded', error: '', available: data.available || [], inProgress: data.in_progress || [], finished: data.finished || [], stats: data.stats || {} });
      } catch (error) {
        if (!active) return;
        if (error?.status === 401) return onSessionExpired();
        setState(previous => ({ ...previous, status: 'error', error: error?.message || 'No fue posible cargar Conversión.' }));
      }
    };
    load();
    return () => { active = false; controller.abort(); };
  }, [reloadToken, onSessionExpired]);

  const refresh = () => setReloadToken(value => value + 1);

  const downloadZip = async (assignmentId) => {
    const base = window.APP_CONFIG.API_BASE_URL.replace(/\/+$/, '');
    const response = await fetch(`${base}/conversion/download.php?assignment_id=${encodeURIComponent(assignmentId)}`, { credentials: 'include' });
    if (!response.ok) {
      let message = `No fue posible descargar el ZIP. HTTP ${response.status}`;
      try { const payload = await response.json(); message = payload.message || message; } catch (error) {}
      throw new Error(message);
    }
    const blob = await response.blob();
    const disposition = response.headers.get('content-disposition') || '';
    const match = disposition.match(/filename\*=UTF-8''([^;]+)/i) || disposition.match(/filename="?([^";]+)"?/i);
    const name = match ? decodeURIComponent(match[1]) : 'INPI_2026_CONVERSION.zip';
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url; link.download = name; document.body.appendChild(link); link.click(); link.remove();
    window.setTimeout(() => URL.revokeObjectURL(url), 1000);
  };

  const claimAndDownload = async () => {
    if (!claimBook) return;
    setSaving(true); setFeedback(null);
    let assignmentId = null;
    try {
      const response = await window.apiRequest('conversion/claim.php', { method: 'POST', body: { book_id: Number(claimBook.book_id) } });
      assignmentId = Number(response?.data?.assignment_id);
      await downloadZip(assignmentId);
      setClaimBook(null);
      setFeedback({ tone: 'success', message: 'Libro tomado y ZIP descargado desde REVISION.' });
      refresh();
    } catch (error) {
      if (assignmentId) {
        try { await window.apiRequest('conversion/release.php', { method: 'POST', body: { assignment_id: assignmentId } }); } catch (releaseError) {}
      }
      if (error?.status === 401) return onSessionExpired();
      setFeedback({ tone: 'error', message: error?.message || 'No fue posible tomar y descargar el libro.' });
      refresh();
    } finally { setSaving(false); }
  };

  const openUpload = item => {
    const currentUploaded = {};
    CONVERSION_FORMATS.forEach(format => {
      currentUploaded[format.key] = Number(item[`${format.key}_count`] || 0);
    });
    setUploadItem(item);
    conversionFilesRef.current = {};
    setFiles({});
    setUploadedFormats(currentUploaded);
    setFormatSaving({});
    setUploadProgress({});
    setFeedback(null);
  };

  const selectedFilesFor = formatKey => {
    const selected = conversionFilesRef.current[formatKey];
    return Array.isArray(selected) ? selected : [];
  };

  const validateFormatFiles = format => {
    const selectedFiles = selectedFilesFor(format.key);
    if (selectedFiles.length === 0) {
      throw new Error(`Selecciona ${format.help.toLowerCase()} para ${format.label}.`);
    }
    const invalidFile = selectedFiles.find(file => !format.extensions.includes(conversionFileExtension(file.name)));
    if (invalidFile) {
      throw new Error(`${invalidFile.name} no corresponde al formato ${format.label}.`);
    }
    if (!format.multiple && selectedFiles.length > 1) {
      throw new Error(`Para ${format.label} selecciona solamente un archivo.`);
    }
    return selectedFiles;
  };

  const uploadSingleFormat = async format => {
    if (!uploadItem) return;
    let selectedFiles = [];
    try {
      selectedFiles = validateFormatFiles(format);
    } catch (error) {
      setFeedback({ tone: 'error', message: error.message });
      return;
    }

    const batches = [];
    for (let index = 0; index < selectedFiles.length; index += CONVERSION_UPLOAD_BATCH_SIZE) {
      batches.push(selectedFiles.slice(index, index + CONVERSION_UPLOAD_BATCH_SIZE));
    }

    const uploadSessionId = `${uploadItem.assignment_id}-${format.key}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
    setFormatSaving(previous => ({ ...previous, [format.key]: true }));
    setUploadProgress(previous => ({
      ...previous,
      [format.key]: { currentBatch: 0, totalBatches: batches.length, uploadedFiles: 0, totalFiles: selectedFiles.length }
    }));
    setFeedback(null);

    try {
      let resultingCount = 0;
      let uploadedFiles = 0;

      for (let batchIndex = 0; batchIndex < batches.length; batchIndex += 1) {
        const batch = batches[batchIndex];
        const formData = new FormData();
        formData.append('assignment_id', String(uploadItem.assignment_id));
        formData.append('format_key', format.key);
        formData.append('upload_session_id', uploadSessionId);
        formData.append('batch_index', String(batchIndex));
        formData.append('total_batches', String(batches.length));
        formData.append('total_files', String(selectedFiles.length));
        batch.forEach(file => formData.append('files[]', file, file.name));

        const base = window.APP_CONFIG.API_BASE_URL.replace(/\/+$/, '');
        const rawResponse = await fetch(`${base}/conversion/upload-format-v2.php`, {
          method: 'POST',
          credentials: 'include',
          body: formData,
          cache: 'no-store'
        });
        let response;
        try {
          response = await rawResponse.json();
        } catch (parseError) {
          throw Object.assign(new Error(`Respuesta inválida del servidor. HTTP ${rawResponse.status}`), {
            status: rawResponse.status
          });
        }
        if (!rawResponse.ok || response?.success === false) {
          throw Object.assign(new Error(response?.message || `No fue posible subir el lote. HTTP ${rawResponse.status}`), {
            status: rawResponse.status
          });
        }

        uploadedFiles += batch.length;
        resultingCount = Number(response?.data?.count || uploadedFiles);
        setUploadProgress(previous => ({
          ...previous,
          [format.key]: {
            currentBatch: batchIndex + 1,
            totalBatches: batches.length,
            uploadedFiles,
            totalFiles: selectedFiles.length
          }
        }));
      }

      setUploadedFormats(previous => ({ ...previous, [format.key]: resultingCount }));
      delete conversionFilesRef.current[format.key];
      setFiles(previous => {
        const next = { ...previous };
        delete next[format.key];
        return next;
      });
      setFeedback({ tone: 'success', message: `${format.label} subido correctamente (${resultingCount} archivo${resultingCount === 1 ? '' : 's'}).` });
      setUploadItem(previous => previous ? { ...previous, [`${format.key}_count`]: resultingCount } : previous);
      refresh();
    } catch (error) {
      if (error?.status === 401) return onSessionExpired();
      setFeedback({ tone: 'error', message: error?.message || `No fue posible subir ${format.label}. La carga puede reintentarse completa.` });
    } finally {
      setFormatSaving(previous => ({ ...previous, [format.key]: false }));
    }
  };

  const allFormatsUploaded = CONVERSION_FORMATS.every(format => Number(uploadedFormats[format.key] || 0) > 0);

  const saveOrFinalize = async () => {
    if (!uploadItem) return;

    if (!allFormatsUploaded) {
      setUploadItem(null);
      setFiles({});
      setFeedback({ tone: 'success', message: 'Cambios guardados. Puedes continuar subiendo los formatos después.' });
      refresh();
      return;
    }

    setSaving(true);
    setFeedback(null);
    try {
      await window.apiRequest('conversion/finalize.php', {
        method: 'POST',
        body: { assignment_id: Number(uploadItem.assignment_id) }
      });
      setUploadItem(null);
      setFiles({});
      setUploadedFormats({});
      setFeedback({ tone: 'success', message: 'Todos los formatos se guardaron y el libro fue finalizado correctamente.' });
      refresh();
    } catch (error) {
      if (error?.status === 401) return onSessionExpired();
      setFeedback({ tone: 'error', message: error?.message || 'No fue posible finalizar la Conversión.' });
    } finally {
      setSaving(false);
    }
  };

  return (
    <div className="stack">
      {feedback && <div role={feedback.tone==='success'?'status':'alert'} style={{padding:'12px 14px',borderRadius:6,background:feedback.tone==='success'?'#f0fdf4':'#fef2f2',color:feedback.tone==='success'?'#166534':'#991b1b'}}>{feedback.message}</div>}
      <div className="kpi-grid" style={{ gridTemplateColumns: 'repeat(3, 1fr)' }}>
        <KPI label="Pendientes de iniciar" value={state.stats.available || 0} sub="Validados en Control de Calidad" tone="primary"/>
        <KPI label="En conversión" value={state.stats.in_progress || 0} sub="Tomados por mí" tone="amber"/>
        <KPI label="Finalizados" value={state.stats.finished || 0} sub="Todos los formatos cargados" tone="success"/>
      </div>

      <div className="card">
        <div className="card-header"><Icon name="convert" size={16}/><div><div className="card-title">Libros validados disponibles</div><div className="card-subtitle">Aprobados por Control de calidad y disponibles para tomar</div></div></div>
        <div className="table-wrap" style={{border:'none',borderRadius:0}}><table className="data"><thead><tr><th>Núm.</th><th>Serie / Título</th><th>Autor</th><th>Fecha aprobación</th><th style={{textAlign:'right'}}>Acción</th></tr></thead><tbody>
          {state.status==='loading'&&<tr><td colSpan="5"><Empty icon="convert" title="Cargando" subtitle="Consultando libros validados…"/></td></tr>}
          {state.status==='loaded'&&state.available.length===0&&<tr><td colSpan="5"><Empty icon="convert" title="Sin libros disponibles" subtitle="Los libros aprobados en Control de calidad aparecerán aquí"/></td></tr>}
          {state.available.map(item=><tr key={item.book_id}><td><span className="cons">#{item.inventory_number||item.book_id}</span></td><td className="title-cell"><div className="text-xs text-3">{item.series_collection||'Sin serie'}</div><div className="title-line">{item.title}</div></td><td>{item.author||'—'}</td><td>{formatConversionDate(item.approved_at)}</td><td style={{textAlign:'right'}}><button className="btn btn-primary btn-sm" onClick={()=>setClaimBook(item)}>Tomar</button></td></tr>)}
        </tbody></table></div>
      </div>

      <div className="card">
        <div className="card-header"><Icon name="convert" size={16}/><div><div className="card-title">Libros en conversión</div><div className="card-subtitle">Descargados desde REVISION · Sube los seis formatos al terminar</div></div></div>
        <div className="table-wrap" style={{border:'none',borderRadius:0}}><table className="data"><thead><tr><th>Núm.</th><th>Serie / Título</th><th>Fecha</th><th>Estado</th><th style={{textAlign:'right'}}>Acción</th></tr></thead><tbody>
          {state.inProgress.length===0&&<tr><td colSpan="5"><Empty icon="convert" title="No hay libros en conversión" subtitle="Toma un libro validado para comenzar"/></td></tr>}
          {state.inProgress.map(item=><tr key={item.assignment_id}><td><span className="cons">#{item.inventory_number||item.book_id}</span></td><td className="title-cell"><div className="text-xs text-3">{item.series_collection||'Sin serie'}</div><div className="title-line">{item.title}</div></td><td>{formatConversionDate(item.started_at||item.assigned_at)}</td><td><span className="status-pill" style={{background:'#dbeafe',color:'#1e40af'}}>En conversión</span></td><td style={{textAlign:'right'}}><button className="btn btn-primary btn-sm" onClick={()=>openUpload(item)}>Subir formatos</button></td></tr>)}
        </tbody></table></div>
      </div>

      <div className="card">
        <div className="card-header"><Icon name="check" size={16} style={{color:'var(--success)'}}/><div><div className="card-title">Libros finalizados ({state.finished.length})</div><div className="card-subtitle">Guardados en INPI 2026\FINALIZADO</div></div></div>
        <div className="table-wrap" style={{border:'none',borderRadius:0}}><table className="data"><thead><tr><th>Núm.</th><th>Serie</th><th>Título</th><th>Fecha finalización</th><th>Status</th></tr></thead><tbody>
          {state.finished.map(item=><tr key={item.assignment_id}><td>#{item.inventory_number||item.book_id}</td><td>{item.series_collection||'—'}</td><td>{item.title}</td><td>{formatConversionDate(item.completed_at)}</td><td><span className="status-pill" style={{background:'#dcfce7',color:'#166534'}}>Finalizado</span></td></tr>)}
        </tbody></table></div>
      </div>

      <Modal open={!!claimBook} onClose={()=>!saving&&setClaimBook(null)} title="Tomar libro para Conversión" maxWidth={560} footer={<><button className="btn btn-ghost" disabled={saving} onClick={()=>setClaimBook(null)}>Cancelar</button><button className="btn btn-primary" disabled={saving} onClick={claimAndDownload}>{saving?'Preparando…':'Aceptar y descargar'}</button></>}>
        {claimBook&&<div className="stack"><div style={{padding:12,background:'var(--surface-2)',borderRadius:6}}><div className="text-xs text-3">#{claimBook.inventory_number||claimBook.book_id}</div><div style={{fontWeight:600,fontSize:17}}>{claimBook.title}</div><div className="text-sm text-2">{claimBook.series_collection||'Sin serie'}</div></div><div style={{padding:14,background:'#fffbeb',color:'#92400e',borderRadius:6}}><strong>Antes de descargar</strong><br/>Crea esta estructura de carpeta para mantener el control:<br/><span className="text-mono">Documentos\INPI 2026\CONVERSION\</span><br/><br/>El ZIP se descargará desde la carpeta REVISION y comenzará desde Serie\Título\1.JPG.</div></div>}
      </Modal>

      <Modal
        open={!!uploadItem}
        onClose={()=>!saving&&!Object.values(formatSaving).some(Boolean)&&setUploadItem(null)}
        title="Subir formatos"
        maxWidth={700}
        footer={<>
          <button
            className="btn btn-ghost"
            type="button"
            disabled={saving || Object.values(formatSaving).some(Boolean)}
            onClick={()=>setUploadItem(null)}
          >
            Cancelar
          </button>
          <button
            className="btn btn-primary"
            type="button"
            disabled={saving || Object.values(formatSaving).some(Boolean)}
            onClick={saveOrFinalize}
          >
            {saving ? 'Finalizando…' : (allFormatsUploaded ? 'Guardar y finalizar' : 'Guardar cambios')}
          </button>
        </>}
      >
        {uploadItem&&<div>
          <div style={{padding:12,background:'var(--surface-2)',borderRadius:6,marginBottom:16}}>
            <div className="text-xs text-3">#{uploadItem.inventory_number||uploadItem.book_id}</div>
            <div style={{fontWeight:600,fontSize:17}}>{uploadItem.title}</div>
            <div className="text-sm text-2">{uploadItem.series_collection||'Sin serie'} · {uploadItem.author||'Sin autor'}</div>
            <div className="text-xs" style={{marginTop:6,color:'#2563eb',fontWeight:700}}>Carga aislada por formato · endpoint v2</div>
          </div>

          <div className="field">
            <label className="field-label">Fecha de subida</label>
            <input className="input" value={new Date().toLocaleDateString('es-MX')} readOnly/>
          </div>

          <div style={{display:'grid',gap:14}}>
            {CONVERSION_FORMATS.map(format=>{
              const uploadedCount=Number(uploadedFormats[format.key]||0);
              const isUploaded=uploadedCount>0;
              const isUploading=Boolean(formatSaving[format.key]);
              const selectedCount=selectedFilesFor(format.key).length;
              const progress=uploadProgress[format.key]||null;
              return <div key={format.key} style={{border:'1px solid var(--border)',borderRadius:8,padding:14,background:isUploaded?'#f0fdf4':'var(--surface-1)'}}>
                <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',gap:12,marginBottom:isUploaded?0:10}}>
                  <div>
                    <div className="field-label" style={{marginBottom:4}}>{format.label} → {format.folder}</div>
                    <div className="text-xs text-3">{format.help}</div>
                  </div>
                  {isUploaded&&<span style={{display:'inline-flex',alignItems:'center',gap:6,color:'#166534',fontWeight:600}}>
                    <span>✓</span> {format.label} subido correctamente{uploadedCount>1?` (${uploadedCount} archivos)`:''}
                  </span>}
                </div>

                {!isUploaded&&<>
                  <input
                    key={`${format.key}-${uploadedCount}-${selectedCount}`}
                    className="input"
                    type="file"
                    accept={format.accept}
                    multiple={format.multiple}
                    disabled={isUploading}
                    onChange={event=>{
                      const selected = Array.from(event.currentTarget.files || []);
                      conversionFilesRef.current[format.key] = selected;
                      setFiles(previous=>({
                        ...previous,
                        [format.key]: selected.map(file=>({
                          name:file.name,
                          size:file.size,
                          type:file.type,
                          lastModified:file.lastModified
                        }))
                      }));
                    }}
                  />
                  <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',gap:12,marginTop:8}}>
                    <div className="field-help" style={{margin:0}}>
                      Se guardará en INPI 2026\FINALIZADO\Serie\Título\{format.folder}\
                      {selectedCount>0?` · ${selectedCount} seleccionado${selectedCount===1?'':'s'}`:''}
                      {isUploading&&progress?` · Lote ${progress.currentBatch} de ${progress.totalBatches} · ${progress.uploadedFiles} de ${progress.totalFiles} archivos`:''}
                      {selectedCount>0&&<div style={{marginTop:4,fontWeight:600}}>
                        Selección actual: {selectedFilesFor(format.key).slice(0,3).map(file=>file.name).join(', ')}
                        {selectedCount>3?` y ${selectedCount-3} más`:''}
                      </div>}
                    </div>
                    <button
                      className="btn btn-primary btn-sm"
                      type="button"
                      disabled={isUploading || selectedCount===0}
                      onClick={()=>uploadSingleFormat(format)}
                    >
                      {isUploading?'Subiendo…':'Subir'}
                    </button>
                  </div>
                </>}
              </div>;
            })}
          </div>

          <div style={{marginTop:16,padding:12,borderRadius:6,background:allFormatsUploaded?'#ecfdf5':'#fffbeb',color:allFormatsUploaded?'#166534':'#92400e'}}>
            {allFormatsUploaded
              ? 'Todos los formatos fueron subidos. Ya puedes guardar y finalizar.'
              : `${CONVERSION_FORMATS.filter(format=>Number(uploadedFormats[format.key]||0)>0).length} de ${CONVERSION_FORMATS.length} formatos subidos. Puedes guardar cambios y continuar después.`}
          </div>
        </div>}
      </Modal>
    </div>
  );
};

const Conversion = (props) => {
  const serverMode = window.APP_CONFIG.AUTH.MODE === 'server';
  if (serverMode) return <ConversionServer currentUser={props.currentUser} onSessionExpired={props.onSessionExpired}/>;
  return <ConversionLocal {...props}/>;
};

Object.assign(window, { Conversion });
