// ============================================================
// Cronómetro Tablet — App principal
// API_BASE vacío = modo demo (sin backend)
// API_BASE con URL = modo real (Cloudflare Worker)
// ============================================================

// ── Configuración ─────────────────────────────────────────────
const API_BASE   = 'https://dina-actividades-worker.fl-059.workers.dev';
const SYNC_MS    = 5000; // polling al backend en modo real

// Grupo desde URL: ?grupo=g-01  (sin parámetro → pantalla de selección)
const params   = new URLSearchParams(location.search);
const GRUPO_ID = params.get('grupo') || null;

// ── Datos mock ────────────────────────────────────────────────
const GRUPOS_MOCK = {
  'g-01': { nombre: 'GRUPO 01' },
  'g-02': { nombre: 'GRUPO 02' },
  'g-03': { nombre: 'GRUPO 03' },
  'g-04': { nombre: 'GRUPO 04' },
  'g-05': { nombre: 'GRUPO 05' },
};

const GRUPOS_LIST = [
  { id:'g-01', num:'01', nombre:'GRUPO 01' },
  { id:'g-02', num:'02', nombre:'GRUPO 02' },
  { id:'g-03', num:'03', nombre:'GRUPO 03' },
  { id:'g-04', num:'04', nombre:'GRUPO 04' },
  { id:'g-05', num:'05', nombre:'GRUPO 05' },
];

const OPERARIOS_MOCK = {
  'g-01': [
    { id:'i-0001', nombre:'Diego Cocha',     rol:'jefe',     estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
    { id:'i-0005', nombre:'Enzo Furci',       rol:'operario', estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
    { id:'i-0006', nombre:'Brian Aguirre',    rol:'operario', estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
    { id:'i-0007', nombre:'Ezequiel Luna',    rol:'operario', estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
  ],
  'g-02': [
    { id:'i-0002', nombre:'Lucas Luna',       rol:'jefe',     estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
    { id:'i-0008', nombre:'Diego Saverio',    rol:'operario', estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
    { id:'i-0009', nombre:'Matias Morales',   rol:'operario', estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
    { id:'i-0010', nombre:'Santiago Arevalo', rol:'operario', estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
  ],
  'g-03': [
    { id:'i-0003', nombre:'Enzo Saavedra',    rol:'jefe',     estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
    { id:'i-0011', nombre:'Eduardo Lazarte',  rol:'operario', estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
    { id:'i-0012', nombre:'Daniel Marcial',   rol:'operario', estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
  ],
  'g-04': [
    { id:'i-0004', nombre:'Matias Patauner',  rol:'jefe',     estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
  ],
  'g-05': [
    { id:'i-0017', nombre:'Rodrigo Alamino',  rol:'jefe',     estado:'idle', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null },
  ],
};

// Slots iniciales: API mode → 4 vacíos, demo mode → mocks del grupo
function makeInitialSlots() {
  const LIBRE = (n) => ({ slot_num:n, id:null, nombre:null, estado:'libre', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null });
  if (API_BASE) return [1,2,3,4].map(LIBRE);
  const mocks = OPERARIOS_MOCK[GRUPO_ID] || [];
  return [1,2,3,4].map((n, i) => mocks[i] ? { ...mocks[i], slot_num: n } : LIBRE(n));
}

const CATALOGS_MOCK = {
  areas: [
    { id:'ensamble',             label:'Ensamble',                      isProduction:true  },
    { id:'operaciones',          label:'Operaciones',                   isProduction:false },
    { id:'instalacion',          label:'Instalación de Pantalla',       isProduction:false },
    { id:'servicio_tecnico',     label:'Servicio Técnico',              isProduction:false },
    { id:'despacho_recepciones', label:'Despacho y Recepciones',        isProduction:false },
    { id:'logistica',            label:'Logística',                     isProduction:false },
    { id:'varios_produccion',    label:'Actividades Varias Producción', isProduction:false },
  ],
  subtipos: {
    ensamble:             [
      { id:'gabinetes', label:'Ensamble de Gabinetes',          needsPitchTamano:true  },
      { id:'modulos',   label:'Colocación de Módulos',          needsPitchTamano:true  },
      { id:'fuentes',   label:'Armar Fuentes',                  needsPitchTamano:false },
      { id:'cables',    label:'Hacer Cables (Tensión / Datos)', needsPitchTamano:false },
      { id:'rcg_fw',    label:'Configuración RCG / FW',         needsPitchTamano:true  },
      { id:'test',      label:'Test de Encendido / Verificación',needsPitchTamano:true },
      { id:'embalaje',  label:'Embalaje',                       needsPitchTamano:false },
      { id:'reparacion',label:'Reparación de Gabinete',         needsPitchTamano:true  },
    ],
    operaciones:          [{ id:'coordinacion',label:'Coordinación / Reuniones' },{id:'pedidos',label:'Gestión de Pedidos'},{id:'proveedores',label:'Control de Proveedores'},{id:'documentacion',label:'Documentación / Informes'},{id:'control_stock',label:'Control de Stock'},{id:'otra',label:'Otra (aclarar)'}],
    instalacion:          [{ id:'preparacion_material',label:'Preparación de Material y Herramientas' },{id:'instalacion_sitio',label:'Instalación en sitio'},{id:'instalacion_showroom',label:'Instalación en Showroom'},{id:'relevamiento',label:'Relevamiento previo'},{id:'desinstalacion',label:'Desinstalación'}],
    servicio_tecnico:     [{ id:'configuracion',label:'Configuración' },{id:'reparacion_pantalla',label:'Reparación / Control de Pantalla'},{id:'remoto',label:'Servicio Técnico Remoto'},{id:'campo',label:'Servicio Técnico de Campo'}],
    despacho_recepciones: [{ id:'despacho',label:'Despacho de Pedidos' },{id:'recepcion',label:'Recepción de Mercadería'},{id:'carga',label:'Carga'},{id:'descarga',label:'Descarga'},{id:'control_stock',label:'Control de Stock'}],
    logistica:            [{ id:'traslado',label:'Traslado de Mercadería' },{id:'flete',label:'Flete a Cliente'},{id:'traslado_deposito',label:'Traslado entre Depósitos'},{id:'encomiendas',label:'Envío de Encomiendas'}],
    varios_produccion:    [{ id:'orden_limpieza',label:'Orden y Limpieza' },{id:'pintura',label:'Pintura'},{id:'herreria',label:'Armado Estructura Herrería'},{id:'relevamiento',label:'Relevamiento'},{id:'otra',label:'Otra (aclarar)'}],
  },
  pitches:         ['P 1.5','P 1.56','P 1.8','P 1.86','P 2.5','P 2.9','P 3.9','P 4','P 4.44','P 4.8','P 5','P 5.9','P 6','P 6.25','P 6.66','P 6.67','P 7','P 8','P 10','P 16','P 20'],
  tamanos_gabinete:['172x1032','320x160','500x1000','500x500','640x1920','640x480','640x640','960x1440','960x960'],
  tipos_gabinete:  ['45° Outdoor','Curvo Indoor','Curvo Outdoor','Fix','Fix Indoor','Floor','GOB Indoor','Poster','Poster Indoor','Recto Indoor','Recto Outdoor','Superflex'],
  partidas_mock:   ['HJ03','HJ06','HJ07','HJ08','HJ09','HJ10','HJ11','HJ13','HJ14','HJ15','HJ16','HJ17','HJ18','HJ21','HJ22','HJ23','HJ24','HJ25','HJ26','HJ27','HJ29','HJ30','HJ31','HJ32','HJ33','HJ35','HJ36','HJ39','HJ41','HJ42','HJ43','HJ44','HJ45','HJ48','HJ49','HJ50','HJ53','HJ55','HJ57','HJ59','HJ61','HJ63','HJ66','HJ72','HJ74','HJ75','HJ78','HJ83','HJ84','UNI01','UNI02','UNI08','UNI30','DC07','DC09','DC13','DC17','DC19','DC20','DC22','LY01','LY02','LY03','LY04','LY05','LY06','LY07','LY08','LY09','LY10','LY11','LY12','LY13','LY14','LY15','UN20','UN30','UN35','UN39','HJ67'],
};

// ── API helpers ───────────────────────────────────────────────
async function apiGet(path) {
  try {
    const r = await fetch(API_BASE + path);
    return r.json();
  } catch { return { ok: false }; }
}
async function apiPost(path, body) {
  try {
    const r = await fetch(API_BASE + path, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });
    return r.json();
  } catch { return { ok: false }; }
}

// ── Modal Cantidad ────────────────────────────────────────────
function ModalCantidad({ tareaLabel, mode, onConfirm, onSaltar }) {
  const [val, setVal] = React.useState('');
  function submit() {
    const n = parseInt(val, 10);
    onConfirm(n > 0 ? n : null);
  }
  return (
    <div className="overlay" onClick={onSaltar}>
      <div className="modal" onClick={e => e.stopPropagation()}>
        <div className="modal-title">¿Cuántos terminaste?</div>
        <div className="modal-sub" style={{textTransform:'uppercase',letterSpacing:'0.05em'}}>{tareaLabel}</div>
        <input
          type="number"
          min="0"
          placeholder="0"
          value={val}
          onChange={e => setVal(e.target.value)}
          onKeyDown={e => e.key === 'Enter' && submit()}
          autoFocus
          style={{
            fontSize: '2.2rem', fontWeight: 800, textAlign: 'center',
            width: '100%', padding: '12px 0', marginTop: 12, marginBottom: 8,
            background: 'var(--bg-card)', color: 'var(--text)',
            border: '2px solid var(--border)', borderRadius: 8, outline: 'none',
          }}
        />
        <div className="modal-btns" style={{marginTop: 8}}>
          <button className="mbtn mbtn-cancel" onClick={onSaltar}>Saltar</button>
          <button className="mbtn mbtn-ok" onClick={submit}>Confirmar</button>
        </div>
      </div>
    </div>
  );
}

// ── Selector de grupo ─────────────────────────────────────────
function GroupSelector() {
  return (
    <div className="group-selector">
      <div className="gs-brand">
        <img className="gs-logo" src="../assets/dina-logo-horizontal-white.png" alt="Dinalight" />
        <div className="gs-title">Seleccioná tu grupo</div>
      </div>
      <div className="gs-grid">
        {GRUPOS_LIST.map(g => (
          <div key={g.id} className="gs-tile" onClick={() => location.href = '?grupo=' + g.id}>
            <div className="gs-num">{g.num}</div>
            <div className="gs-name">{g.nombre}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ── App ───────────────────────────────────────────────────────
function App() {
  if (!GRUPO_ID) return <GroupSelector />;

  const [ops, setOps]                 = React.useState(makeInitialSlots);
  const [tareaGrupal, setTareaGrupal] = React.useState(null);
  const [catalogs, setCatalogs]       = React.useState(CATALOGS_MOCK);
  const [partidas, setPartidas]       = React.useState(null);
  const [grupoNombre, setGrupoNombre] = React.useState(GRUPOS_MOCK[GRUPO_ID]?.nombre || GRUPO_ID);
  const [turnoId, setTurnoId]         = React.useState(null);
  const [slotPickFor, setSlotPickFor] = React.useState(null);   // slot_num | null
  const [disponibles, setDisponibles] = React.useState([]);

  const [pickFor, setPickFor]   = React.useState(null); // null | 'grupal' | op.id
  const [corteFor, setCorteFor] = React.useState(null); // null | op.id
  const [volverFor, setVolverFor] = React.useState(null); // null | op.id — modal post-corte
  const [cantidadFor, setCantidadFor] = React.useState(null); // null | { opId, mode: 'cambio'|'fin' }
  const cantidadPendiente = React.useRef(null);
  const [toast, setToast]       = React.useState('');
  const [now, setNow]           = React.useState(new Date());
  const [showHelp, setShowHelp] = React.useState(false);

  // Lock por tiempo: opId → timestamp hasta el cual el sync no pisa estado local
  // Más robusto que Set: cubre el caso donde el sync ya empezó su fetch antes de que la acción comenzara
  const lockedUntil = React.useRef(new Map());

  // Timer — tick segundos para running
  React.useEffect(() => {
    const t = setInterval(() => {
      setNow(new Date());
      setOps(prev => prev.map(o => o.estado === 'running' ? { ...o, secs: (o.secs || 0) + 1 } : o));
    }, 1000);
    return () => clearInterval(t);
  }, []);

  // Cargar turno real del día (silencioso — crea uno si no existe)
  React.useEffect(() => {
    if (!API_BASE) return;
    apiGet(`/api/grupos/${GRUPO_ID}/turno/hoy`).then(d => {
      if (d.ok && d.turno?.id) setTurnoId(d.turno.id);
    });
  }, []);

  // Cargar catalogs y partidas desde API (si está disponible)
  React.useEffect(() => {
    if (!API_BASE) return;
    apiGet('/api/catalogs').then(d => { if (d.ok) setCatalogs(d.catalogs); });
    apiGet('/api/partidas').then(d => { if (d.ok) setPartidas(d.partidas); });
  }, []);

  // Sync estado desde API cada SYNC_MS
  React.useEffect(() => {
    if (!API_BASE) return;
    const sync = async () => {
      const d = await apiGet(`/api/grupos/${GRUPO_ID}/sesion`);
      if (!d.ok) return;
      setGrupoNombre(d.grupo.nombre);
      if (d.grupo.tarea_grupal?.label) setTareaGrupal(d.grupo.tarea_grupal);
      setOps(prev => d.operadores.map(remoto => {
        // Slot vacío: devolver tal cual
        if (remoto.estado === 'libre') return remoto;
        // Match por slot_num para preservar estado local
        const local = prev.find(o => o.slot_num === remoto.slot_num) || {};
        const lock  = local.id ? lockedUntil.current.get(local.id) : null;
        if (lock && Date.now() < lock) return local;
        if (local.id) lockedUntil.current.delete(local.id);
        let secs;
        if (remoto.estado === 'running') {
          if (local.estado === 'running') {
            secs = local.secs || 0;
          } else if (remoto.inicio_estado) {
            secs = Math.max(0, Math.floor((Date.now() - new Date(remoto.inicio_estado).getTime()) / 1000));
          } else {
            secs = 0;
          }
        } else if (remoto.estado === 'idle' && local.estado === 'idle') {
          secs = local.secs || 0;
        } else {
          secs = 0;
        }
        return { ...remoto, secs, secs_ante_corte: local.secs_ante_corte };
      }));
    };
    sync();
    const t = setInterval(sync, SYNC_MS);
    return () => clearInterval(t);
  }, []);

  const showToast = msg => { setToast(msg); setTimeout(() => setToast(''), 2000); };
  const upd = (id, patch) => setOps(prev => prev.map(o => o.id === id ? { ...o, ...patch } : o));

  // ── Slot picker ──────────────────────────────────────────────
  async function handleSlotPick(slotNum) {
    setSlotPickFor(slotNum);
    if (API_BASE && turnoId) {
      const d = await apiGet(`/api/grupos/${GRUPO_ID}/operarios-disponibles?turno_id=${turnoId}`);
      if (d.ok) setDisponibles(d.operarios || []);
    } else if (!API_BASE) {
      const assignedIds = new Set(ops.filter(o => o.id).map(o => o.id));
      setDisponibles(Object.values(OPERARIOS_MOCK).flat().filter(o => !assignedIds.has(o.id)));
    }
  }

  async function handleSlotAsignar(slotNum, integrante) {
    const LIBRE = { id:null, nombre:null, estado:'libre', secs:0, hoy_min:0, hoy_cortes:0, hoy_gab:0, cortes:[], tarea_area:null, tarea_subtipo:null, tarea_partida:null, tarea_pitch:null, tarea_tamano:null, tarea_tipo_gab:null };
    // Optimistic update
    setOps(prev => prev.map(o => o.slot_num === slotNum
      ? { ...LIBRE, slot_num: slotNum, id: integrante.id, nombre: integrante.nombre, rol: integrante.rol, estado: 'idle' }
      : o
    ));
    if (API_BASE) {
      let tid = turnoId;
      if (!tid) {
        const d = await apiGet(`/api/grupos/${GRUPO_ID}/turno/hoy`);
        if (d.ok && d.turno?.id) { tid = d.turno.id; setTurnoId(tid); }
      }
      if (tid) {
        try {
          await apiPost(`/api/turnos/${tid}/slots`, { slot_num: slotNum, integrante_id: integrante.id });
        } catch (e) {
          setOps(prev => prev.map(o => o.slot_num === slotNum ? { ...LIBRE, slot_num: slotNum } : o));
          showToast('Error al asignar operario');
          setSlotPickFor(null); setDisponibles([]); return;
        }
      }
    }
    setSlotPickFor(null); setDisponibles([]);
    showToast(`${integrante.nombre} — REGISTRADO`);
  }

  // ── Acciones ──────────────────────────────────────────────────

  async function handleIniciar(opId) {
    const op = ops.find(o => o.id === opId);
    if (!op || op.estado === 'done') return;

    // Si no tiene tarea, abrir picker primero
    if (!op.tarea_area && op.estado === 'idle') {
      setPickFor(opId);
      return;
    }

    upd(opId, { estado: 'running', secs: 0, corte_motivo: null });
    if (API_BASE) {
      lockedUntil.current.set(opId, Date.now() + 10000);
      await apiPost(`/api/operadores/${opId}/iniciar`, { turno_id: turnoId });
    }
    showToast(`${op.nombre} — INICIADO`);
  }

  async function handleDetener(opId) {
    const op = ops.find(o => o.id === opId);
    if (!op) return;
    const minutos = Math.floor((op.secs || 0) / 60);
    // secs se preserva (no se resetea) para que el último tiempo quede visible en la card
    upd(opId, { estado: 'idle', hoy_min: (op.hoy_min || 0) + minutos });
    if (API_BASE) {
      lockedUntil.current.set(opId, Date.now() + 10000);
      await apiPost(`/api/operadores/${opId}/detener`, { turno_id: turnoId });
    }
    showToast(`${op.nombre} — DETENIDO`);
  }

  async function handleCorte(opId, motivo) {
    const op = ops.find(o => o.id === opId);
    if (!op) return;
    const minutos = Math.floor((op.secs || 0) / 60);
    upd(opId, {
      estado: 'corte',
      secs: 0,
      secs_ante_corte: op.secs || 0,  // para restaurar al volver
      corte_motivo: motivo.toUpperCase(),
      hoy_cortes: (op.hoy_cortes || 0) + 1,
      hoy_min: (op.hoy_min || 0) + minutos,
    });
    if (API_BASE) {
      lockedUntil.current.set(opId, Date.now() + 10000);
      await apiPost(`/api/operadores/${opId}/corte`, { turno_id: turnoId, motivo });
    }
    showToast(`${op.nombre} — CORTE: ${motivo}`);
    setCorteFor(null);
  }

  async function ejecutarFin(opId, cantidad) {
    const op = ops.find(o => o.id === opId);
    if (!op) return;
    upd(opId, { estado: 'done', secs: 0 });
    if (API_BASE) {
      lockedUntil.current.set(opId, Date.now() + 10000);
      await apiPost(`/api/operadores/${opId}/fin`, { turno_id: turnoId, cantidad: cantidad || null });
    }
    showToast(`${op.nombre} — FIN DÍA`);
  }

  function handleFin(opId) {
    const op = ops.find(o => o.id === opId);
    if (!op) return;
    if (op.tarea_area) {
      setCantidadFor({ opId, mode: 'fin' });
    } else {
      ejecutarFin(opId, null);
    }
  }

  async function handleTareaConfirm(tarea) {
    const esGrupal = pickFor === 'grupal';
    if (esGrupal) {
      setTareaGrupal(tarea);
      if (API_BASE) await apiPost(`/api/grupos/${GRUPO_ID}/tarea`, tarea);
      showToast('Tarea grupal actualizada');
    } else {
      const pid = pickFor;
      const cantidad = cantidadPendiente.current;
      cantidadPendiente.current = null;
      upd(pid, {
        tarea_area: tarea.area, tarea_subtipo: tarea.subtipo,
        tarea_partida: tarea.partida, tarea_pitch: tarea.pitch,
        tarea_tamano: tarea.tamano, tarea_tipo_gab: tarea.tipo_gab,
        estado: 'running', secs: 0,
      });
      if (API_BASE) {
        lockedUntil.current.set(pid, Date.now() + 10000);
        // Cerrar tarea anterior (graba registro con cantidad) antes de iniciar la nueva
        await apiPost(`/api/operadores/${pid}/detener`, { turno_id: turnoId, cantidad: cantidad || null });
        await apiPost(`/api/operadores/${pid}/iniciar`, { turno_id: turnoId, ...tarea });
      }
      showToast('Tarea asignada — INICIADO');
    }
    setPickFor(null);
  }

  // Tap en card → pedir cantidad si ya tiene tarea, luego picker
  function handleCardTap(opId) {
    const op = ops.find(o => o.id === opId);
    if (!op || op.estado === 'done') return;
    if (op.tarea_area) {
      setCantidadFor({ opId, mode: 'cambio' });
    } else {
      setPickFor(opId);
    }
  }

  function handleCantidadConfirm(cantidad) {
    const { opId, mode } = cantidadFor;
    cantidadPendiente.current = cantidad;
    setCantidadFor(null);
    if (mode === 'cambio') {
      setPickFor(opId);
    } else {
      ejecutarFin(opId, cantidad);
    }
  }

  async function handleVolverContinuar(opId) {
    const op = ops.find(o => o.id === opId);
    if (!op) return;
    const secsRestore = op.secs_ante_corte || 0;
    upd(opId, { estado: 'running', secs: secsRestore, corte_motivo: null });
    if (API_BASE) {
      lockedUntil.current.set(opId, Date.now() + 10000);
      await apiPost(`/api/operadores/${opId}/iniciar`, {
        turno_id: turnoId,
        area: op.tarea_area, subtipo: op.tarea_subtipo,
        partida: op.tarea_partida, pitch: op.tarea_pitch,
        tamano: op.tarea_tamano, tipo_gab: op.tarea_tipo_gab,
        label: op.tarea_label,
      });
    }
    setVolverFor(null);
    showToast(`${op.nombre} — CONTINUANDO`);
  }

  function handleVolverNueva(opId) {
    setVolverFor(null);
    setPickFor(opId);
  }

  // Toggle INICIAR/DETENER
  function handleToggle(opId) {
    const op = ops.find(o => o.id === opId);
    if (!op) return;
    if (op.estado === 'running') handleDetener(opId);
    else if (op.estado === 'corte') setVolverFor(opId); // modal: continuar o nueva tarea
    else if (op.estado === 'idle') handleIniciar(opId);
  }

  const clockText = now.toLocaleTimeString('es-AR', { hour:'2-digit', minute:'2-digit', second:'2-digit' });
  const fechaText = now.toLocaleDateString('es-AR',  { weekday:'long', day:'numeric', month:'short' });
  const turnoLabel = 'TURNO DÍA';

  return (
    <div className="app">
      <Topbar grupo={grupoNombre} fecha={fechaText} turno={turnoLabel} clockText={clockText} />
      <TareaGlobalBar tarea={tareaGrupal} onCambiar={() => setPickFor('grupal')} />
      <div className="crono-grid">
        {ops.map(op => (
          <OperatorCard
            key={op.slot_num}
            op={op}
            onToggleRun={() => op.id && handleToggle(op.id)}
            onCorte={() => op.id && setCorteFor(op.id)}
            onFin={() => op.id && handleFin(op.id)}
            onPickTask={() => op.id && handleCardTap(op.id)}
            onPickSlot={() => handleSlotPick(op.slot_num)}
          />
        ))}
      </div>
      <BottomBar onNotas={() => showToast('Notas — próximamente')} onHelp={() => window.open('../manual/#operador', '_blank')} />

      {pickFor && (
        <TaskPicker
          esGrupal={pickFor === 'grupal'}
          catalogs={catalogs}
          partidas={partidas || catalogs.partidas_mock}
          onConfirm={handleTareaConfirm}
          onClose={() => setPickFor(null)}
        />
      )}

      {corteFor && (
        <ModalCorte
          onPick={motivo => handleCorte(corteFor, motivo)}
          onClose={() => setCorteFor(null)}
        />
      )}

      {volverFor && (
        <ModalVolverCorte
          op={ops.find(o => o.id === volverFor) || {}}
          onContinuar={() => handleVolverContinuar(volverFor)}
          onNueva={() => handleVolverNueva(volverFor)}
          onClose={() => setVolverFor(null)}
        />
      )}

      {cantidadFor && (() => {
        const op = ops.find(o => o.id === cantidadFor.opId) || {};
        const subLabel = op.tarea_subtipo ? op.tarea_subtipo.replace(/_/g,' ') : (op.tarea_area || 'tarea');
        return (
          <ModalCantidad
            tareaLabel={subLabel}
            mode={cantidadFor.mode}
            onConfirm={handleCantidadConfirm}
            onSaltar={() => { cantidadPendiente.current = null; handleCantidadConfirm(null); }}
          />
        );
      })()}

      {slotPickFor !== null && (
        <div className="overlay" onClick={() => { setSlotPickFor(null); setDisponibles([]); }}>
          <div className="modal" onClick={e => e.stopPropagation()}>
            <div className="modal-title">¿Quién sos?</div>
            <div className="modal-sub">Slot {slotPickFor} · elegí tu nombre para este turno</div>
            <div className="task-opts" style={{maxHeight:'55vh',overflowY:'auto'}}>
              {disponibles.map(op => (
                <div key={op.id} className="task-opt" onClick={() => handleSlotAsignar(slotPickFor, op)}>
                  <div style={{fontWeight:800}}>{op.nombre}</div>
                  {op.grupo_nombre && op.grupo_id !== GRUPO_ID &&
                    <div style={{fontSize:12,color:'var(--soft)',marginTop:2}}>{op.grupo_nombre}</div>}
                </div>
              ))}
              {disponibles.length === 0 &&
                <div style={{color:'var(--muted)',fontSize:13,textAlign:'center',padding:'16px 0'}}>Sin operarios disponibles</div>}
            </div>
            <div className="modal-btns">
              <button className="mbtn mbtn-cancel" onClick={() => { setSlotPickFor(null); setDisponibles([]); }}>Cancelar</button>
            </div>
          </div>
        </div>
      )}

      <div className={'toast' + (toast ? ' show' : '')}>{toast}</div>

      {showHelp && (
        <div className="modal-overlay" onClick={() => setShowHelp(false)}>
          <div className="modal-box" onClick={e => e.stopPropagation()} style={{maxWidth:480,maxHeight:'80vh',overflowY:'auto'}}>
            <div className="modal-title" style={{marginBottom:16}}>¿Cómo usar el Cronómetro?</div>
            <div style={{fontSize:13,lineHeight:1.7,color:'var(--text)'}}>
              <div style={{fontFamily:'var(--font-display)',fontWeight:800,fontSize:11,letterSpacing:'0.1em',color:'var(--muted)',textTransform:'uppercase',marginBottom:6}}>Operario</div>
              <ul style={{paddingLeft:16,marginBottom:16}}>
                <li>Tocá una tarjeta <b>LIBRE</b> y elegí tu nombre para unirte al turno.</li>
                <li>Tocá tu tarjeta para asignar una tarea y arrancar el cronómetro.</li>
                <li>Usá <b>Corte</b> para pausas — indicá el motivo.</li>
                <li>Tocá <b>Fin</b> al terminar tu jornada.</li>
              </ul>
              <div style={{fontFamily:'var(--font-display)',fontWeight:800,fontSize:11,letterSpacing:'0.1em',color:'var(--muted)',textTransform:'uppercase',marginBottom:6}}>Jefe de Grupo</div>
              <ul style={{paddingLeft:16,marginBottom:8}}>
                <li>Configurá la <b>Tarea Grupal</b> antes de que arranque el equipo.</li>
                <li>Al finalizar el turno, andá al <b>Wizard de Cierre</b> desde el menú principal.</li>
                <li>El turno se abre automáticamente cuando el primer operario se une.</li>
              </ul>
            </div>
            <div className="modal-btns" style={{marginTop:16}}>
              <button className="mbtn mbtn-cancel" onClick={() => setShowHelp(false)}>Cerrar</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
