/* Bernard Health SeniorCare Enterprise V3.8.1
   Módulos Operativos Globales: Cocina, Miscelánea, Mantenimiento y Seguridad */
(()=>{
  'use strict';
  const VERSION='4.1.2';
  const TABLE='seniorcare_operational_tasks';
  const ATTENDANCE='attendance_records';
  const ALERTS='seniorcare_alerts';
  const ROLES={
    cook:{label:'Cocina',eyebrow:'PANEL DE COCINA',icon:'food',text:'Revise su horario, tareas asignadas, dietas e incidentes operativos.'},
    cleaning:{label:'Miscelánea',eyebrow:'PANEL DE MISCELÁNEA',icon:'check',text:'Revise su horario, complete tareas de limpieza y reporte novedades.'},
    maintenance:{label:'Mantenimiento',eyebrow:'PANEL DE MANTENIMIENTO',icon:'tool',text:'Atienda órdenes de trabajo, mantenimiento preventivo e incidentes.'},
    security:{label:'Seguridad',eyebrow:'PANEL DE SEGURIDAD',icon:'shield',text:'Revise su horario, rondas, accesos y reporte incidentes de seguridad.'}
  };
  const ROLE_ALIASES={
    cook:['cook','kitchen','cocina'],
    cleaning:['cleaning','miscellaneous','miscellany','limpieza','miscelanea','miscelánea','miscelaneo','misceláneo','aseo','servicios generales'],
    maintenance:['maintenance','mantenimiento'],
    security:['security','guard','guarda','guarda de seguridad','seguridad']
  };
  const TEMPLATES={
    cook:['Verificar dietas y restricciones','Preparar desayuno','Preparar almuerzo','Preparar cena','Entregar meriendas','Controlar temperatura de alimentos','Limpiar área de preparación','Revisar inventario básico'],
    cleaning:['Limpiar habitaciones asignadas','Desinfectar baños','Limpiar áreas comunes','Manejar residuos','Reponer insumos de higiene','Desinfectar comedor','Registrar falta de productos'],
    maintenance:['Revisar iluminación','Verificar camas y barandas','Revisar fugas de agua','Inspeccionar equipos eléctricos','Mantenimiento preventivo','Revisar agua y gas','Atender avería reportada'],
    security:['Ronda de acceso principal','Revisar puertas y portones','Controlar visitantes','Verificar salidas autorizadas','Realizar ronda nocturna','Revisar perímetro','Registrar novedad de seguridad']
  };
  let rows=[],operationalIncidents=[],channel=null,incidentChannel=null,busy=false,clockBusy=false,remoteStaffMember=null,subscribePromise=null,subscribedIdentity='',refreshTimer=null,visibilityHandlerBound=false,refreshInFlight=false,pendingVisualRefresh=false,lastOperationalSnapshot='',assignmentRepairDone=false;
  const db=()=>window.seniorcareSupabase||null;
  const me=()=>window.currentUser||null;
  const org=()=>me()?.organizationId||me()?.organization_id||null;
  const role=()=>String(me()?.role||'').toLowerCase();
  const isAdmin=()=>['admin','administrator'].includes(role());
  const isOperational=()=>!!ROLES[role()];
  const esc=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
  const norm=v=>String(v??'').normalize('NFD').replace(/[\u0300-\u036f]/g,'').trim().toLowerCase();
  const fmt=v=>{try{return v?new Date(v).toLocaleString('es-CR',{dateStyle:'medium',timeStyle:'short'}):'Sin fecha límite'}catch(_){return String(v||'')}};
  const today=()=>new Date().toLocaleDateString('en-CA',{timeZone:'America/Costa_Rica'});
  const toast=m=>window.showToast?.(m);
  const main=()=>document.getElementById('mainContent');
  const staff=()=>Array.isArray(window.staffMembers)?window.staffMembers:[];
  const attendance=()=>Array.isArray(window.attendanceLog)?window.attendanceLog:(window.attendanceLog=[]);
  const roleLabel=k=>ROLES[k]?.label||k;
  const icon=k=>window.svg?.[k]||window.svg?.check||'';
  const roleMatches=(value,target)=>{const n=norm(value);return (ROLE_ALIASES[target]||[target]).some(x=>n===norm(x)||n.includes(norm(x)))};
  const myName=()=>String(me()?.name||me()?.full_name||'').trim();
  const myUserIds=()=>[me()?.id,me()?.user_id,me()?.auth_user_id].filter(Boolean).map(String);
  const stableStaffKey=x=>String(x?.staff_key||x?.id||x?.data?.id||'');
  const myStaff=()=>{const uid=String(me()?.id||''),name=norm(myName());return remoteStaffMember||staff().find(x=>String(x.linkedUserId||x.linked_user_id||'')===uid)||staff().find(x=>norm(x.name)===name)||null};
  const myTodayLog=()=>{const uid=String(me()?.id||''),key=`user:${uid}`;return [...attendance()].reverse().find(x=>String(x.date)===today()&&(String(x.userId||'')===uid||String(x.staffId||'')===key))||null};

  function normalizeStaffRecord(row){
    const d=row?.data||row||{};
    return {
      ...d,
      id:d.id??row?.staff_key??row?.id,
      linkedUserId:d.linkedUserId||d.linked_user_id||null,
      shiftName:d.shiftName||d.shift_name||'',
      startTime:d.startTime||d.start_time||'',
      endTime:d.endTime||d.end_time||'',
      workDays:Array.isArray(d.workDays)?d.workDays:(Array.isArray(d.work_days)?d.work_days:[]),
      assignment:d.assignment||d.primary_assignment||''
    };
  }
  async function pullMyStaffProfile(){
    if(!db()||!org()||!me()?.id)return null;
    const {data,error}=await db().from('seniorcare_staff_records').select('id,staff_key,data,active,updated_at').eq('organization_id',org()).eq('active',true).order('updated_at',{ascending:false}).limit(500);
    if(error)throw error;
    const all=(data||[]).map(normalizeStaffRecord);
    const uid=String(me().id),name=norm(myName());
    remoteStaffMember=all.find(x=>String(x.linkedUserId||x.linked_user_id||'')===uid)||all.find(x=>norm(x.name)===name&&roleMatches(x.role||x.position,role()))||all.find(x=>norm(x.name)===name)||null;
    if(remoteStaffMember){
      const local=staff(),idx=local.findIndex(x=>String(x.id)===String(remoteStaffMember.id)||String(x.linkedUserId||x.linked_user_id||'')===uid||norm(x.name)===name);
      if(idx>=0)local[idx]={...local[idx],...remoteStaffMember};else local.push(remoteStaffMember);
      try{localStorage.setItem('seniorcare-staff',JSON.stringify(local))}catch(_){ }
    }
    return remoteStaffMember;
  }
  function repairOperationalNav(){
    const n=document.getElementById('bottomNav');if(!n||!isOperational())return;
    n.classList.add('operational-nav');
    const expected=role()==='cook'?['home','operationalTasks','nutrition','operationalIncidents']:['home','operationalTasks','operationalIncidents','operationalAlerts'];
    const seen=new Set();
    [...n.querySelectorAll('[data-nav]')].forEach(btn=>{const k=String(btn.dataset.nav||'');if(!expected.includes(k)||seen.has(k))btn.remove();else seen.add(k)});
    if(n.querySelectorAll('[data-nav]').length!==expected.length&&typeof window.renderNav==='function')window.renderNav();
  }

  const taskVisible=t=>{
    if(isAdmin())return true;
    if(!roleMatches(t.role_name,role()))return false;
    const assigned=String(t.assigned_user_id||t.data?.assigned_user_id||'');
    const assignedStaffKey=String(t.assigned_staff_key||t.data?.assigned_staff_key||'');
    const assignedName=norm(t.assigned_name||t.data?.assigned_name||'');
    if(!assigned&&!assignedStaffKey&&!assignedName)return true;
    const ids=myUserIds();
    const staffKey=stableStaffKey(myStaff());
    return ids.includes(assigned)||Boolean(staffKey&&assignedStaffKey===staffKey)||assignedName===norm(myName())||assignedName===norm(myStaff()?.name||'');
  };
  const normalize=r=>({...r,data:r.data||{}});
  const persistAttendance=()=>{try{localStorage.setItem('seniorcare-attendance-log',JSON.stringify(attendance()))}catch(_){}};
  function mergeAttendance(row){
    const incoming={id:row.client_id||Date.parse(row.updated_at)||Date.now(),remoteId:row.id,staffId:row.staff_key,userId:row.user_id||null,name:row.staff_name,role:row.role_name,date:row.work_date,clockIn:row.clock_in,clockOut:row.clock_out};
    const target=attendance();
    const idx=target.findIndex(x=>String(x.date)===String(incoming.date)&&(String(x.userId||'')===String(incoming.userId||'')||String(x.staffId||'')===String(incoming.staffId||'')));
    if(idx<0)target.push(incoming);else target[idx]={...target[idx],...incoming};
    persistAttendance();
  }
  async function pullMyAttendance(render=false){
    if(!db()||!org()||!me()?.id)return null;
    const ids=myUserIds();
    const profile=myStaff()||await pullMyStaffProfile();
    const staffKey=stableStaffKey(profile);
    const found=[];
    for(const uid of ids){
      const q=await db().from(ATTENDANCE).select('*').eq('organization_id',org()).eq('user_id',uid).eq('work_date',today()).order('updated_at',{ascending:false}).limit(5);
      if(q.error)throw q.error;
      found.push(...(q.data||[]));
    }
    if(staffKey){
      const q=await db().from(ATTENDANCE).select('*').eq('organization_id',org()).eq('staff_key',staffKey).eq('work_date',today()).order('updated_at',{ascending:false}).limit(5);
      if(q.error)throw q.error;
      found.push(...(q.data||[]));
    }
    const unique=[...new Map(found.map(r=>[String(r.id||r.client_id||`${r.staff_key}:${r.work_date}`),r])).values()];
    unique.forEach(mergeAttendance);
    if(render&&String(window.activeScreen||'')==='home')renderHome();
    return unique.sort((a,b)=>String(b.updated_at||'').localeCompare(String(a.updated_at||'')))[0]||null;
  }
  async function saveClock(action){
    if(clockBusy||!db()||!org()||!me()?.id)return;
    clockBusy=true;
    try{
      await pullMyStaffProfile();
      const profile=myStaff();
      const realStaffKey=String(profile?.id||profile?.staff_key||`user:${me().id}`);
      const realStaffName=String(profile?.name||myName()||ROLES[role()].label);
      const realRoleName=ROLES[role()]?.label||String(profile?.role||profile?.position||role());
      const ids=myUserIds();
      const collected=[];
      for(const uid of ids){
        const q=await db().from(ATTENDANCE).select('*').eq('organization_id',org()).eq('user_id',uid).eq('work_date',today()).order('updated_at',{ascending:false});
        if(q.error)throw q.error;
        collected.push(...(q.data||[]));
      }
      if(realStaffKey){
        const q=await db().from(ATTENDANCE).select('*').eq('organization_id',org()).eq('staff_key',realStaffKey).eq('work_date',today()).order('updated_at',{ascending:false});
        if(q.error)throw q.error;
        collected.push(...(q.data||[]));
      }
      const data=[...new Map(collected.map(r=>[String(r.id||r.client_id||`${r.staff_key}:${r.work_date}`),r])).values()];
      const open=data.find(r=>r.clock_in&&!r.clock_out),closed=data.find(r=>r.clock_in&&r.clock_out),now=new Date().toISOString();
      const existing=open||closed||null;
      if(existing&&String(existing.staff_key||'')!==realStaffKey){
        const fix=await db().from(ATTENDANCE).update({staff_key:realStaffKey,staff_name:realStaffName,role_name:realRoleName,updated_at:now}).eq('id',existing.id);
        if(fix.error&&String(fix.error.code||'')!=='23505')throw fix.error;
        existing.staff_key=realStaffKey;existing.staff_name=realStaffName;existing.role_name=realRoleName;existing.updated_at=now;
      }
      if(action==='in'){
        if(open||closed){(data||[]).forEach(mergeAttendance);toast(closed?'La jornada de hoy ya está cerrada.':'La entrada ya está registrada.');renderHome();return;}
        const payload={organization_id:org(),user_id:me().id,staff_key:realStaffKey,staff_name:realStaffName,role_name:realRoleName,work_date:today(),clock_in:now,clock_out:null,client_id:Date.now(),updated_at:now};
        const q=await db().from(ATTENDANCE).upsert(payload,{onConflict:'organization_id,staff_key,work_date'});if(q.error)throw q.error;
      }else{
        if(closed&&!open){(data||[]).forEach(mergeAttendance);toast('La jornada de hoy ya está cerrada.');renderHome();return;}
        if(!open)throw new Error('No existe una entrada abierta para registrar la salida.');
        const q=await db().from(ATTENDANCE).update({clock_out:now,staff_key:realStaffKey,staff_name:realStaffName,role_name:realRoleName,updated_at:now}).eq('id',open.id);if(q.error)throw q.error;
      }
      await pullMyAttendance(false);
      await window.syncSeniorCareAttendanceGlobal?.();
      renderHome();
      toast(action==='in'?'Entrada registrada y sincronizada.':'Salida registrada y sincronizada.');
    }catch(e){console.error('[Operational attendance]',e);toast(`No se guardó la marca: ${e.message||e}`)}finally{clockBusy=false}
  }
  function staffRoleMatches(person,targetRole){
    return !!person&&roleMatches(person.role||person.position||person.job_title||'',targetRole);
  }
  async function repairInvalidTaskAssignments(){
    if(assignmentRepairDone||!isAdmin()||!db()||!org())return;
    assignmentRepairDone=true;
    const allStaff=staff();
    const fixes=[];
    for(const t of rows){
      const uid=String(t.assigned_user_id||t.data?.assigned_user_id||'');
      const assignedName=norm(t.assigned_name||t.data?.assigned_name||'');
      if(!uid&&!assignedName)continue;
      const current=allStaff.find(x=>uid&&String(x.linkedUserId||x.linked_user_id||'')===uid)||allStaff.find(x=>assignedName&&norm(x.name)===assignedName);
      if(current&&staffRoleMatches(current,t.role_name))continue;
      const candidates=allStaff.filter(x=>staffRoleMatches(x,t.role_name)&&String(x.linkedUserId||x.linked_user_id||''));
      const replacement=candidates.length===1?candidates[0]:null;
      const replacementUid=String(replacement?.linkedUserId||replacement?.linked_user_id||'');
      const replacementKey=stableStaffKey(replacement);
      const patch={
        assigned_user_id:replacementUid||null,
        assigned_name:replacement?.name||null,
        data:{...(t.data||{}),assigned_user_id:replacementUid,assigned_name:replacement?.name||'',assigned_staff_key:replacementKey},
        updated_at:new Date().toISOString(),
        updated_by:me()?.id||null
      };
      fixes.push(db().from(TABLE).update(patch).eq('organization_id',org()).eq('task_key',t.task_key));
    }
    if(fixes.length){
      const results=await Promise.all(fixes);
      const failed=results.find(x=>x.error);
      if(failed?.error)throw failed.error;
      const q=await db().from(TABLE).select('*').eq('organization_id',org()).eq('active',true).order('created_at',{ascending:false}).limit(600);
      if(q.error)throw q.error;
      rows=(q.data||[]).map(normalize);window.operationalGlobalTasks=rows;
      toast('Se corrigieron asignaciones de tareas que no coincidían con el puesto.');
    }
  }
  async function pull(render=true){
    if(!db()||!org())return [];
    const {data,error}=await db().from(TABLE).select('*').eq('organization_id',org()).eq('active',true).order('created_at',{ascending:false}).limit(600);
    if(error)throw error;
    rows=(data||[]).map(normalize);window.operationalGlobalTasks=rows;
    await repairInvalidTaskAssignments();
    if(render&&String(window.activeScreen||'')==='operationalTasks')renderTasks();
    if(render&&String(window.activeScreen||'')==='operationalAlerts')renderNotices();
    if(render&&String(window.activeScreen||'')==='home'&&isOperational())renderHome();
    return rows;
  }
  function incidentBelongsToCurrentWorker(r){
    if(isAdmin())return true;
    const d=r?.data||{};
    const currentId=String(me()?.id||'');
    const currentName=norm(myName()||myStaff()?.name||'');
    const reportRole=String(d.authorRole||d.author_role||d.role||r.role_name||'');
    if(reportRole&&!roleMatches(reportRole,role()))return false;
    const ids=[r.updated_by,d.authorId,d.author_id,d.userId,d.user_id,d.createdBy,d.created_by].filter(Boolean).map(String);
    if(ids.length)return ids.includes(currentId);
    const reportAuthor=norm(d.author||d.authorName||d.author_name||r.author_name||'');
    return !!reportAuthor&&!!currentName&&reportAuthor===currentName&&(!reportRole||roleMatches(reportRole,role()));
  }
  async function pullOperationalIncidents(render=false){
    if(!db()||!org()||!me()?.id)return [];
    const {data,error}=await db().from(ALERTS).select('*').eq('organization_id',org()).eq('active',true).eq('alert_type','operational_incident').order('created_at',{ascending:false}).limit(200);
    if(error)throw error;
    operationalIncidents=(data||[]).filter(incidentBelongsToCurrentWorker);
    if(render&&String(window.activeScreen||'')==='operationalIncidents')renderIncidentScreen();
    return operationalIncidents;
  }
  async function removeOperationalChannels(){
    const client=db();
    if(!client)return;
    const existing=typeof client.getChannels==='function'?client.getChannels():[];
    for(const ch of existing){
      const topic=String(ch?.topic||'');
      if(topic.includes('bhsc-operational-v381-')||topic.includes('bhsc-operational-incidents-v381-')||topic.includes('bhsc-operational-v404-')){
        try{await client.removeChannel(ch)}catch(_){ }
      }
    }
    channel=null;
    incidentChannel=null;
    subscribedIdentity='';
  }
  function operationalSnapshot(){
    const log=myTodayLog()||{};
    const profile=myStaff()||{};
    return JSON.stringify({
      role:role(),screen:String(window.activeScreen||''),
      tasks:myTasks().map(t=>[t.task_key,t.status,t.priority,t.due_at,t.updated_at,t.assigned_user_id,t.assigned_name]),
      incidents:operationalIncidents.map(r=>[r.alert_key,r.status,r.priority,r.updated_at]),
      attendance:[log.remoteId||log.id,log.clockIn,log.clockOut,log.staffId,log.userId],
      schedule:[profile.id,profile.shiftName,profile.startTime,profile.endTime,profile.workDays,profile.assignment]
    });
  }
  function userIsEditing(){
    const el=document.activeElement;
    return !!(el&&/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName))||!!document.querySelector('dialog[open],.modal:not(.hidden),.sheet:not(.hidden)');
  }
  function renderCurrentOperationalScreen(){
    if(!isOperational())return;
    if(userIsEditing()){pendingVisualRefresh=true;return;}
    const y=window.scrollY;
    const screen=String(window.activeScreen||'');
    if(screen==='home')renderHome();
    else if(screen==='operationalTasks')renderTasks();
    else if(screen==='operationalAlerts')renderNotices();
    else if(screen==='operationalIncidents')renderIncidentScreen();
    requestAnimationFrame(()=>window.scrollTo({top:y,left:0,behavior:'auto'}));
    pendingVisualRefresh=false;
  }
  async function refreshOperationalData({forceRender=false}={}){
    if(refreshInFlight||document.hidden||!isOperational())return;
    refreshInFlight=true;
    try{
      const before=lastOperationalSnapshot||operationalSnapshot();
      await Promise.all([pull(false),pullOperationalIncidents(false),pullMyAttendance(false),pullMyStaffProfile()]);
      const after=operationalSnapshot();
      lastOperationalSnapshot=after;
      if(forceRender||before!==after||pendingVisualRefresh)renderCurrentOperationalScreen();
    }catch(e){console.warn('[Operational refresh]',e);}
    finally{refreshInFlight=false;}
  }
  async function subscribe(){
    const client=db();
    if(!client||!org()||!me()?.id)return;
    const identity=`${org()}:${me().id}`;
    if(subscribedIdentity===identity&&refreshTimer)return;
    if(subscribePromise)return subscribePromise;
    subscribePromise=(async()=>{
      await removeOperationalChannels();
      if(refreshTimer){clearInterval(refreshTimer);refreshTimer=null;}
      lastOperationalSnapshot=operationalSnapshot();
      refreshTimer=setInterval(()=>refreshOperationalData(),30000);
      if(!visibilityHandlerBound){
        document.addEventListener('visibilitychange',()=>{if(!document.hidden&&isOperational())refreshOperationalData();});
        window.addEventListener('focus',()=>{if(isOperational())refreshOperationalData();});
        document.addEventListener('focusout',()=>{if(pendingVisualRefresh)setTimeout(()=>refreshOperationalData({forceRender:true}),120);});
        visibilityHandlerBound=true;
      }
      subscribedIdentity=identity;
    })().finally(()=>{subscribePromise=null});
    return subscribePromise;
  }
  function scheduleCard(){
    const s=myStaff(),start=s?.startTime||s?.start_time||'',end=s?.endTime||s?.end_time||'',shiftName=s?.shiftName||s?.shift_name||'',shift=shiftName?`${shiftName} · ${start||'--:--'}–${end||'--:--'}`:(s?.shift||(start||end?`${start||'--:--'}–${end||'--:--'}`:'Sin turno asignado')),days=Array.isArray(s?.workDays)&&s.workDays.length?s.workDays.join(', '):(Array.isArray(s?.work_days)&&s.work_days.length?s.work_days.join(', '):'Sin días definidos'),log=myTodayLog();
    return `<section class="op-self-card"><div><span>HORARIO Y ASISTENCIA</span><strong>${esc(shift)}</strong><small>${esc(days)}${s?.assignment?` · ${esc(s.assignment)}`:''}</small></div><div class="op-clock-state"><small>${log?.clockIn?`Entrada ${new Date(log.clockIn).toLocaleTimeString('es-CR',{hour:'2-digit',minute:'2-digit'})}`:'Entrada no registrada'}${log?.clockOut?` · Salida ${new Date(log.clockOut).toLocaleTimeString('es-CR',{hour:'2-digit',minute:'2-digit'})}`:''}</small>${!log?.clockIn?'<button class="clock-btn clock-in" id="opClockIn">Marcar entrada</button>':!log.clockOut?'<button class="clock-btn clock-out" id="opClockOut">Marcar salida</button>':'<span class="status ok">Jornada cerrada</span>'}</div></section>`;
  }
  const myTasks=()=>rows.filter(taskVisible);
  const noticeRows=()=>myTasks().filter(t=>t.status!=='completed').sort((a,b)=>(a.priority==='Alta'?-2:a.priority==='Media'?-1:0)-(b.priority==='Alta'?-2:b.priority==='Media'?-1:0));
  function renderHome(){
    if(!isOperational())return false;
    const cfg=ROLES[role()],mine=myTasks(),pending=mine.filter(x=>x.status!=='completed').length,done=mine.filter(x=>x.status==='completed'&&String(x.completed_at||'').slice(0,10)===today()).length,incidentCount=operationalIncidents.filter(x=>x.status!=='Resuelta'&&x.status!=='Archivada').length;
    main().innerHTML=`<section class="admin-welcome role-welcome op-welcome"><div><span class="eyebrow">${cfg.eyebrow}</span><h2>${typeof window.greeting==='function'?window.greeting():'Bienvenido'}, ${esc((myName().split(' ')[0])||cfg.label)}</h2><p>${cfg.text}</p></div><div class="admin-mark">${icon(cfg.icon)}</div></section>${scheduleCard()}<section class="operational-metrics op-global-metrics"><button class="admin-stat" data-go="operationalTasks"><span class="stat-icon mint">${icon('check')}</span><div><small>Tareas pendientes</small><strong>${pending}</strong><p>Asignadas por Administración</p></div><span class="chevron">›</span></button><button class="admin-stat" data-go="operationalTasks"><span class="stat-icon blue">${icon('check')}</span><div><small>Completadas hoy</small><strong>${done}</strong><p>Trabajo registrado</p></div><span class="chevron">›</span></button><button class="admin-stat" data-go="operationalIncidents"><span class="stat-icon rose">${icon('alert')}</span><div><small>Reportes abiertos</small><strong>${incidentCount}</strong><p>Solo sus reportes operativos</p></div><span class="chevron">›</span></button></section><section class="quick-section"><div class="quick-heading"><h2>Acciones del puesto</h2></div><div class="quick-grid"><button class="quick-card" data-go="operationalTasks"><span class="quick-icon mint">${icon('check')}</span><div><strong>Mis tareas</strong><small>Revisar y completar asignaciones</small></div></button>${role()==='cook'?`<button class="quick-card" data-go="nutrition"><span class="quick-icon amber">${icon('food')}</span><div><strong>Dietas</strong><small>Consultar planes nutricionales</small></div></button>`:''}<button class="quick-card" data-go="operationalIncidents"><span class="quick-icon rose">${icon('alert')}</span><div><strong>Reportar incidente</strong><small>Registrar una novedad de su puesto</small></div></button><button class="quick-card" data-go="operationalAlerts"><span class="quick-icon blue">${icon('bell')}</span><div><strong>Avisos de tareas</strong><small>Prioridades y vencimientos asignados</small></div></button></div></section>`;
    repairOperationalNav();window.updateAlertButton?.();return true;
  }
  function staffOptions(selectedRole){
    return staff().filter(x=>roleMatches(x.role,selectedRole)).map(x=>`<option value="${esc(x.linkedUserId||x.linked_user_id||'')}" ${x.linkedUserId||x.linked_user_id?'':'disabled'}>${esc(x.name)}${x.linkedUserId||x.linked_user_id?'':' · sin cuenta vinculada'}</option>`).join('');
  }
  function card(t){
    const assigned=t.assigned_name||t.data?.assigned_name||'Todo el puesto',done=t.status==='completed';
    return `<article class="op-task-card ${done?'done':''}" data-opg-id="${esc(t.task_key)}"><div class="op-task-top"><span class="status ${t.priority==='Alta'?'danger':t.priority==='Media'?'warn':'ok'}">${esc(t.priority||'Normal')}</span><small>${esc(roleLabel(t.role_name))} · ${esc(assigned)}</small></div><strong>${esc(t.title)}</strong><p>${esc(t.detail||'Sin detalle')}</p><div class="op-task-meta"><span>${t.due_at?`Límite: ${esc(fmt(t.due_at))}`:'Sin fecha límite'}</span><span>${done?`Completada ${esc(fmt(t.completed_at))}`:'Pendiente'}</span></div>${t.completion_note?`<div class="op-completion-note"><span>Observación</span><p>${esc(t.completion_note)}</p></div>`:''}<div class="op-task-actions">${!isAdmin()?`<button class="${done?'secondary-btn':'primary-btn'}" data-opg-toggle="${esc(t.task_key)}">${done?'Reabrir':'Completar tarea'}</button>`:`<button class="mini-btn" data-opg-edit="${esc(t.task_key)}">Editar</button><button class="mini-btn" data-opg-archive="${esc(t.task_key)}">Archivar</button><button class="icon-delete" data-opg-delete="${esc(t.task_key)}">×</button>`}</div></article>`;
  }
  function renderTasks(){
    const list=isAdmin()?rows:myTasks();
    const adminForm=isAdmin()?`<form class="form-card op-global-form" id="opGlobalTaskForm"><input type="hidden" name="taskKey"><div class="form-grid"><label>Puesto<select name="role" id="opgRole"><option value="cook">Cocina</option><option value="cleaning">Miscelánea</option><option value="maintenance">Mantenimiento</option><option value="security">Seguridad</option></select></label><label>Asignar a<select name="assignedUser" id="opgAssigned"><option value="">Todo el puesto</option>${staffOptions('cook')}</select></label><label>Prioridad<select name="priority"><option>Normal</option><option>Media</option><option>Alta</option></select></label><label>Fecha límite<input type="datetime-local" name="due"></label><label class="wide">Tarea<input name="title" required></label><label class="wide">Detalle / precaución<textarea name="detail" rows="3"></textarea></label></div><div class="op-template-box"><span>PLANTILLAS DEL PUESTO</span><div id="opgTemplates">${TEMPLATES.cook.map(x=>`<button type="button" class="filter-chip" data-opg-template="${esc(x)}">${esc(x)}</button>`).join('')}</div></div><div class="form-actions"><button type="button" class="secondary-btn hidden" id="opgCancelEdit">Cancelar edición</button><button class="primary-btn">Guardar tarea</button></div></form>`:'';
    main().innerHTML=window.pageHeader?.('OPERACIÓN DEL HOGAR',isAdmin()?'Tareas operativas':'Mis tareas',isAdmin()?'Asignaciones para Cocina, Miscelánea, Mantenimiento y Seguridad':'Solo las tareas asignadas a su puesto y cuenta')+adminForm+`<section class="op-task-summary"><article><span>Pendientes</span><strong>${list.filter(x=>x.status!=='completed').length}</strong></article><article><span>Completadas</span><strong>${list.filter(x=>x.status==='completed').length}</strong></article><article><span>Alta prioridad</span><strong>${list.filter(x=>x.status!=='completed'&&x.priority==='Alta').length}</strong></article></section><section class="operational-task-list op-global-task-list">${list.length?list.map(card).join(''):window.empty?.('No hay tareas asignadas.')||'<div class="empty-state">No hay tareas asignadas.</div>'}</section>`;
  }
  function renderNotices(){
    const list=noticeRows();
    main().innerHTML=window.pageHeader?.('AVISOS DEL PUESTO','Prioridades de trabajo','Solo avisos derivados de las tareas que Administración le asignó')+`<section class="op-task-summary"><article><span>Pendientes</span><strong>${list.length}</strong></article><article><span>Alta prioridad</span><strong>${list.filter(x=>x.priority==='Alta').length}</strong></article><article><span>Con fecha límite</span><strong>${list.filter(x=>x.due_at).length}</strong></article></section><section class="operational-task-list op-global-task-list">${list.length?list.map(card).join(''):window.empty?.('No tiene avisos de tareas pendientes.')||'<div class="empty-state">No tiene avisos de tareas pendientes.</div>'}</section>`;
  }
  function incidentCard(r){const d=r.data||{};return `<article class="op-task-card"><div class="op-task-top"><span class="status ${r.priority==='Alta'?'danger':'warn'}">${esc(r.priority||'Pendiente')}</span><small>${esc(fmt(r.created_at))}</small></div><strong>${esc(d.incidentType||r.title||'Incidente operativo')}</strong><p>${esc(r.detail||'Sin detalle')}</p><div class="op-task-meta"><span>${esc(r.status||'Nueva')}</span><span>${esc(d.area||ROLES[role()]?.label||'Área')}</span></div></article>`}
  function renderIncidentScreen(){
    const mine=operationalIncidents;
    main().innerHTML=window.pageHeader?.('REPORTE OPERATIVO','Incidentes de mi puesto','Reporte averías, riesgos, faltantes o situaciones relacionadas con su trabajo')+`<form class="form-card" id="opIncidentForm"><div class="form-grid"><label>Tipo<select name="type"><option>Avería</option><option>Riesgo de seguridad</option><option>Falta de insumos</option><option>Daño en instalaciones</option><option>Situación operativa</option><option>Otro</option></select></label><label>Prioridad<select name="priority"><option>Pendiente</option><option>Alta</option><option>Informativa</option></select></label><label class="wide">Área o ubicación<input name="area" placeholder="Ej. lavandería, portón principal, cocina"></label><label class="wide">Descripción<textarea name="detail" rows="4" required placeholder="Describa lo ocurrido y cualquier acción realizada"></textarea></label></div><div class="form-actions"><button class="primary-btn">Enviar reporte</button></div></form><section class="history-card"><h3>Mis reportes</h3><div class="operational-task-list">${mine.length?mine.map(incidentCard).join(''):window.empty?.('Todavía no ha enviado reportes operativos.')||'<p>Sin reportes.</p>'}</div></section>`;
  }
  async function saveIncident(form){
    const fd=new FormData(form),key=`operational:${crypto.randomUUID()}`,type=String(fd.get('type')||'Incidente'),priority=String(fd.get('priority')||'Pendiente'),area=String(fd.get('area')||'').trim(),detail=String(fd.get('detail')||'').trim();
    const payload={organization_id:org(),alert_key:key,source_key:key,title:`${type} · ${ROLES[role()].label}`,detail,priority,status:'Nueva',alert_type:'operational_incident',resident_key:null,target_screen:null,created_at:new Date().toISOString(),data:{id:key,type:'operational_incident',category:'staff',authorId:me().id,author_id:me().id,user_id:me().id,author:myName(),authorRole:role(),author_role:role(),incidentType:type,area,detail,priority,created:new Date().toISOString()},active:true,updated_at:new Date().toISOString(),updated_by:me().id};
    const {error}=await db().from(ALERTS).upsert(payload,{onConflict:'organization_id,alert_key'});if(error)throw error;
  }
  async function saveTask(form){
    const fd=new FormData(form),key=String(fd.get('taskKey')||crypto.randomUUID()),r=String(fd.get('role')||''),uid=String(fd.get('assignedUser')||''),person=staff().find(x=>String(x.linkedUserId||x.linked_user_id||'')===uid),existing=rows.find(x=>String(x.task_key)===key);
    if(uid&&!person)throw new Error('La persona seleccionada ya no está disponible. Selecciónela nuevamente.');
    if(person&&!staffRoleMatches(person,r))throw new Error(`${person.name} no pertenece al puesto ${roleLabel(r)}. Seleccione una persona del puesto correcto.`);
    const assignedStaffKey=stableStaffKey(person);
    const payload={organization_id:org(),task_key:key,role_name:r,assigned_user_id:uid||null,assigned_name:person?.name||null,title:String(fd.get('title')||'').trim(),detail:String(fd.get('detail')||'').trim(),priority:String(fd.get('priority')||'Normal'),due_at:fd.get('due')?new Date(String(fd.get('due'))).toISOString():null,status:existing?.status||'pending',completion_note:existing?.completion_note||null,completed_at:existing?.completed_at||null,completed_by:existing?.completed_by||null,data:{assigned_name:person?.name||'',assigned_user_id:uid||'',assigned_staff_key:assignedStaffKey,created_by_name:myName()||'Administración'},active:true,updated_at:new Date().toISOString(),updated_by:me()?.id||null};
    const {error}=await db().from(TABLE).upsert(payload,{onConflict:'organization_id,task_key'});if(error)throw error;
  }
  async function toggleTask(key){const t=rows.find(x=>String(x.task_key)===String(key));if(!t)return;const done=t.status==='completed';let note=t.completion_note||'';if(!done)note=prompt('Observación del trabajo realizado (opcional):',note)||'';const patch=done?{status:'pending',completion_note:null,completed_at:null,completed_by:null}:{status:'completed',completion_note:note,completed_at:new Date().toISOString(),completed_by:me()?.id||null};const {error}=await db().from(TABLE).update({...patch,updated_at:new Date().toISOString(),updated_by:me()?.id||null}).eq('organization_id',org()).eq('task_key',key);if(error)throw error}
  async function archiveTask(key,hard=false){const q=hard?db().from(TABLE).delete().eq('organization_id',org()).eq('task_key',key):db().from(TABLE).update({active:false,updated_at:new Date().toISOString(),updated_by:me()?.id||null}).eq('organization_id',org()).eq('task_key',key);const {error}=await q;if(error)throw error}
  function editTask(key){const t=rows.find(x=>String(x.task_key)===String(key)),f=document.getElementById('opGlobalTaskForm');if(!t||!f)return;f.elements.taskKey.value=t.task_key;f.elements.role.value=t.role_name;updateAssigned(t.role_name,t.assigned_user_id);f.elements.priority.value=t.priority||'Normal';f.elements.due.value=t.due_at?new Date(t.due_at).toISOString().slice(0,16):'';f.elements.title.value=t.title||'';f.elements.detail.value=t.detail||'';document.getElementById('opgCancelEdit')?.classList.remove('hidden');f.scrollIntoView({behavior:'smooth'})}
  function updateAssigned(r,selected=''){const s=document.getElementById('opgAssigned');if(s)s.innerHTML=`<option value="">Todo el puesto</option>${staffOptions(r)}`;if(s&&selected)s.value=selected;const box=document.getElementById('opgTemplates');if(box)box.innerHTML=(TEMPLATES[r]||[]).map(x=>`<button type="button" class="filter-chip" data-opg-template="${esc(x)}">${esc(x)}</button>`).join('')}
  async function start(){if(!db()||!org())return;try{await Promise.all([pull(false),pullOperationalIncidents(false),pullMyAttendance(false),pullMyStaffProfile()]);await subscribe();window.SENIORCARE_OPERATIONAL_GLOBAL_VERSION='4.1.2';lastOperationalSnapshot=operationalSnapshot();if(isOperational()&&String(window.activeScreen||'')==='home')renderHome()}catch(e){console.error('[Operational Global]',e);toast(`Módulo operativo pendiente: ${e.message}`)}}
  document.addEventListener('submit',e=>{
    if(e.target?.id==='opGlobalTaskForm'){e.preventDefault();e.stopImmediatePropagation();if(busy)return;busy=true;saveTask(e.target).then(()=>{toast('Tarea guardada y sincronizada.');e.target.reset();document.getElementById('opgCancelEdit')?.classList.add('hidden');return pull(true)}).catch(x=>toast(x.message)).finally(()=>busy=false);return}
    if(e.target?.id==='opIncidentForm'){e.preventDefault();e.stopImmediatePropagation();if(busy)return;busy=true;saveIncident(e.target).then(()=>{toast('Reporte enviado a Administración.');e.target.reset();return pullOperationalIncidents(true)}).catch(x=>toast(x.message)).finally(()=>busy=false)}
  },true);
  document.addEventListener('change',e=>{if(e.target?.id==='opgRole')updateAssigned(e.target.value,'')},true);
  document.addEventListener('click',e=>{
    const clock=e.target.closest?.('#opClockIn,#opClockOut');if(clock){e.preventDefault();e.stopImmediatePropagation();saveClock(clock.id==='opClockOut'?'out':'in');return}
    const tpl=e.target.closest?.('[data-opg-template]');if(tpl){e.preventDefault();document.querySelector('#opGlobalTaskForm [name="title"]').value=tpl.dataset.opgTemplate;return}
    const can=e.target.closest?.('#opgCancelEdit');if(can){e.preventDefault();const f=document.getElementById('opGlobalTaskForm');f?.reset();if(f)f.elements.taskKey.value='';can.classList.add('hidden');updateAssigned('cook');return}
    const tog=e.target.closest?.('[data-opg-toggle]');if(tog){e.preventDefault();e.stopImmediatePropagation();toggleTask(tog.dataset.opgToggle).then(()=>pull(true)).catch(x=>toast(x.message));return}
    const edit=e.target.closest?.('[data-opg-edit]');if(edit){e.preventDefault();editTask(edit.dataset.opgEdit);return}
    const arc=e.target.closest?.('[data-opg-archive]');if(arc){e.preventDefault();if(confirm('¿Archivar esta tarea?'))archiveTask(arc.dataset.opgArchive,false).then(()=>pull(true)).catch(x=>toast(x.message));return}
    const del=e.target.closest?.('[data-opg-delete]');if(del){e.preventDefault();if(confirm('¿Eliminar definitivamente esta tarea?'))archiveTask(del.dataset.opgDelete,true).then(()=>pull(true)).catch(x=>toast(x.message));return}
  },true);
  window.renderOperationalTasksGlobal=renderTasks;
  window.renderOperationalGlobalHome=renderHome;
  window.renderOperationalAlertsGlobal=renderNotices;
  window.renderOperationalIncidentsGlobal=renderIncidentScreen;
  window.refreshOperationalGlobal=pull;
  window.getOperationalNoticeCount=()=>noticeRows().length;
  window.addEventListener('seniorcare:user-ready',()=>{channel=null;incidentChannel=null;start()});
  if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',()=>setTimeout(start,900),{once:true});else setTimeout(start,900);
  console.info(`Operational Global ${VERSION} listo`);
})();
