// shared.jsx  mock data + helpers + TurniContext (stato globale condiviso)

//  Avatar helpers 
const TU_AVATAR_COLORS = [
  '#F97A4D','#6366F1','#10B981','#E11D74',
  '#0EA5E9','#F59E0B','#8B5CF6','#EF4444',
  '#14B8A6','#A16207',
];
function tuInitials(name) {
  return name.split(' ').map(p => p[0]).slice(0,2).join('').toUpperCase();
}
function tuAvatarColor(name) {
  let h = 0;
  for (let i = 0; i < name.length; i++) h = (h * 31 + name.charCodeAt(i)) >>> 0;
  return TU_AVATAR_COLORS[h % TU_AVATAR_COLORS.length];
}
function TuAvatar({ name, size = 28 }) {
  const bg = tuAvatarColor(name);
  return (
    <div className="tu-avatar" style={{ width: size, height: size, fontSize: size * 0.42, background: bg }}>
      {tuInitials(name)}
    </div>
  );
}

//  Icon set 
const TuIcon = {
  home:    (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 11.5 12 4l9 7.5"/><path d="M5 10v9.5a.5.5 0 0 0 .5.5h4V14h5v6h4a.5.5 0 0 0 .5-.5V10"/></svg>,
  cal:     (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="3.5" y="5" width="17" height="15.5" rx="2.5"/><path d="M3.5 9.5h17M8 3v4M16 3v4"/></svg>,
  users:   (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="9" cy="8" r="3.5"/><path d="M3 20c.6-3.4 3.2-5 6-5s5.4 1.6 6 5"/><circle cx="17" cy="9" r="2.5"/><path d="M16 14.6c2.4 0 4.4 1.4 5 4.4"/></svg>,
  store:   (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M4 9 5.5 5h13L20 9"/><path d="M4 9v10h16V9"/><path d="M4 9c0 1.7 1.3 3 3 3s3-1.3 3-3M10 9c0 1.7 1.3 3 3 3s3-1.3 3-3M16 9c0 1.7 1.3 3 3 3s3-1.3 3-3" transform="translate(-2 0)"/><path d="M9 19v-5h6v5"/></svg>,
  inbox:   (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M4 13l2.5-7h11L20 13"/><path d="M4 13v6.5h16V13h-5l-1.5 2h-3L9 13H4Z"/></svg>,
  bell:    (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M6 10a6 6 0 1 1 12 0c0 4 1.5 5.5 2 6.5H4c.5-1 2-2.5 2-6.5Z"/><path d="M10 19.5a2 2 0 0 0 4 0"/></svg>,
  search:  (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="6.5"/><path d="m20 20-4-4"/></svg>,
  plus:    (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round"><path d="M12 5v14M5 12h14"/></svg>,
  arrowL:  (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="m14 6-6 6 6 6"/></svg>,
  arrowR:  (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="m10 6 6 6-6 6"/></svg>,
  check:   (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m5 12 5 5 9-11"/></svg>,
  x:       (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"><path d="M6 6l12 12M18 6 6 18"/></svg>,
  more:    (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><circle cx="6" cy="12" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="18" cy="12" r="1"/></svg>,
  filter:  (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M4 6h16M7 12h10M10 18h4"/></svg>,
  user:    (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="9" r="3.5"/><path d="M5 20c1-3.5 3.7-5 7-5s6 1.5 7 5"/></svg>,
  clock:   (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 2"/></svg>,
  pin:     (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M12 21c4.5-5 7-8 7-12a7 7 0 1 0-14 0c0 4 2.5 7 7 12Z"/><circle cx="12" cy="9" r="2.5"/></svg>,
  swap:    (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M4 8h13l-3-3M20 16H7l3 3"/></svg>,
  logout:  (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M9 4H5a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h4"/><path d="m16 8 4 4-4 4M9 12h11"/></svg>,
  grid:    (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="3.5" y="3.5" width="7" height="7" rx="1.6"/><rect x="13.5" y="3.5" width="7" height="7" rx="1.6"/><rect x="3.5" y="13.5" width="7" height="7" rx="1.6"/><rect x="13.5" y="13.5" width="7" height="7" rx="1.6"/></svg>,
  building:(p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 3v18M15 3v18M3 9h18M3 15h18"/></svg>,
  shield:  (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M12 2L4 6v6c0 5 3.5 9.5 8 11 4.5-1.5 8-6 8-11V6L12 2Z"/><path d="m9 12 2 2 4-4"/></svg>,
  trash:   (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6"/><path d="M10 11v5M14 11v5"/></svg>,
  edit:    (p) => <svg viewBox="0 0 24 24" width={p.size||18} height={p.size||18} fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5Z"/></svg>,
};

//  Shift kinds 
const TU_SHIFT_KINDS = {
  morning: { label: 'Mattina',    start: '08:00', end: '14:00', hours: 6,   cls: 'tu-shift-morning' },
  mid:     { label: 'Centrale',   start: '10:00', end: '16:00', hours: 6,   cls: 'tu-shift-mid' },
  evening: { label: 'Pomeriggio', start: '14:00', end: '20:00', hours: 6,   cls: 'tu-shift-evening' },
  close:   { label: 'Chiusura',   start: '16:00', end: '21:30', hours: 5.5, cls: 'tu-shift-close' },
  off:     { label: 'Riposo',     start: '',      end: '',      hours: 0,   cls: 'tu-shift-off' },
  ferie:   { label: 'Ferie',      start: '',      end: '',      hours: 0,   cls: 'tu-shift-ferie' },
};

//  Stati non lavorativi (oltre off/ferie) importati dai turni reali.
//  label = testo mostrato nella cella · cls = classe colore in styles.css
const TU_STATUS_KINDS = {
  off:        { label: 'Riposo',     cls: 'tu-shift-off' },
  riposo:     { label: 'Riposo',     cls: 'tu-shift-off' },
  ferie:      { label: 'Ferie',      cls: 'tu-shift-ferie' },
  chiuso:     { label: 'Chiuso',     cls: 'tu-shift-chiuso' },
  malattia:   { label: 'Malattia',   cls: 'tu-shift-malattia' },
  festivo:    { label: 'Festivo',    cls: 'tu-shift-festivo' },
  maternita:  { label: 'Maternità',  cls: 'tu-shift-maternita' },
  permesso:   { label: 'Permesso',   cls: 'tu-shift-permesso' },
  formazione: { label: 'Formazione', cls: 'tu-shift-formazione' },
  riunione:   { label: 'Riunione',   cls: 'tu-shift-riunione' },
  roll:       { label: 'Roll',       cls: 'tu-shift-roll' },
  recupero:   { label: 'Recupero',   cls: 'tu-shift-recupero' },
  altrove:    { label: 'Altro neg.', cls: 'tu-shift-altrove' },
};

//  Date / day helpers 
const TU_DAYS_SHORT = ['Lun','Mar','Mer','Gio','Ven','Sab','Dom'];
const TU_DAYS_LONG  = ['Lunedì','Martedì','Mercoledì','Giovedì','Venerdì','Sabato','Domenica'];
const TU_MONTHS     = ['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno','Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'];

function _computeCurrentWeek() {
  const today = new Date();
  const dow = today.getDay(); // 0=Dom 1=Lun … 6=Sab
  const diff = dow === 0 ? -6 : 1 - dow;
  const mon = new Date(today.getFullYear(), today.getMonth(), today.getDate() + diff);
  const dates = Array.from({ length: 7 }, (_, i) => {
    const d = new Date(mon.getFullYear(), mon.getMonth(), mon.getDate() + i);
    return d.getDate();
  });
  const sun = new Date(mon.getFullYear(), mon.getMonth(), mon.getDate() + 6);
  // ISO week number
  const thu = new Date(Date.UTC(today.getFullYear(), today.getMonth(), today.getDate() + (4 - (dow || 7))));
  const yearStart = new Date(Date.UTC(thu.getUTCFullYear(), 0, 1));
  const wn = Math.ceil(((thu - yearStart) / 864e5 + 1) / 7);
  const range = mon.getMonth() === sun.getMonth()
    ? `${mon.getDate()}-${sun.getDate()} ${TU_MONTHS[mon.getMonth()]} ${mon.getFullYear()}`
    : `${mon.getDate()} ${TU_MONTHS[mon.getMonth()]} - ${sun.getDate()} ${TU_MONTHS[sun.getMonth()]} ${sun.getFullYear()}`;
  const todayIndex = dow === 0 ? 6 : dow - 1; // Lun=0 … Dom=6
  return { dates, label: `Settimana ${wn} · ${range}`, todayIndex, monday: mon, today };
}
const _TU_WEEK = _computeCurrentWeek();
const TU_WEEK_DATES  = _TU_WEEK.dates;
const TU_WEEK_LABEL  = _TU_WEEK.label;
const TU_TODAY_INDEX = _TU_WEEK.todayIndex; // 0=Lun … 6=Dom; -1 se fuori dalla settimana corrente
const TU_TODAY       = _TU_WEEK.today;      // Date object (oggi)

//  Default / seed data 
// Holding in cima alla gerarchia: Maori Group · Brand · Società · Negozi · Addetti
const HOLDING_NAME = 'Maori Group';
const DEFAULT_BRANDS = [
  { id: 'b1', name: 'Maori Retail' },
  { id: 'b2', name: 'Maori Food' },
];
const DEFAULT_COMPANIES = [
  { id: 'c1', name: 'Maori Italia S.r.l.',      brandId: 'b1' },
  { id: 'c2', name: 'Nord Ovest Retail S.p.A.', brandId: 'b1' },
  { id: 'c3', name: 'Sud Italia S.r.l.',        brandId: 'b2' },
];
const DEFAULT_OPENING_HOURS = {
  mon: [{ start: '09:00', end: '13:00' }, { start: '15:00', end: '19:00' }],
  tue: [{ start: '09:00', end: '13:00' }, { start: '15:00', end: '19:00' }],
  wed: [{ start: '09:00', end: '13:00' }, { start: '15:00', end: '19:00' }],
  thu: [{ start: '09:00', end: '13:00' }, { start: '15:00', end: '19:00' }],
  fri: [{ start: '09:00', end: '13:00' }, { start: '15:00', end: '19:00' }],
  sat: [{ start: '09:00', end: '13:00' }, { start: '15:00', end: '19:00' }],
  sun: [],
};
const MALL_OPENING_HOURS = {
  mon: [{ start: '09:00', end: '20:00' }],
  tue: [{ start: '09:00', end: '20:00' }],
  wed: [{ start: '09:00', end: '20:00' }],
  thu: [{ start: '09:00', end: '20:00' }],
  fri: [{ start: '09:00', end: '20:00' }],
  sat: [{ start: '09:00', end: '20:00' }],
  sun: [{ start: '10:00', end: '20:00' }],
};
function defaultOpeningHours(type) {
  return type === 'mall' ? MALL_OPENING_HOURS : DEFAULT_OPENING_HOURS;
}
const DEFAULT_STORES = [
  { id: 's1', name: 'Milano · Duomo',    city: 'Milano',  short: 'MI-DUO', companyId: 'c1' },
  { id: 's2', name: 'Roma · Termini',    city: 'Roma',    short: 'RM-TER', companyId: 'c1' },
  { id: 's3', name: 'Torino · Lingotto', city: 'Torino',  short: 'TO-LIN', companyId: 'c2' },
  { id: 's4', name: 'Firenze · Centro',  city: 'Firenze', short: 'FI-CEN', companyId: 'c2' },
  { id: 's5', name: 'Napoli · Toledo',   city: 'Napoli',  short: 'NA-TOL', companyId: 'c3' },
];
const DEFAULT_TEAM = [
  { id: 'e1', name: 'Giulia Romano',   role: 'Addetta', hours: 38, contract: 'CTI 38h', storeId: 's1', email: 'giulia.romano@maori.it' },
  { id: 'e2', name: 'Marco Bianchi',   role: 'Addetto', hours: 24, contract: 'PT 24h',  storeId: 's1', email: 'marco.bianchi@maori.it' },
  { id: 'e3', name: 'Sofia Esposito',  role: 'Addetta', hours: 38, contract: 'CTI 38h', storeId: 's1', email: 'sofia.esposito@maori.it' },
  { id: 'e4', name: 'Luca Ferrari',    role: 'Addetto', hours: 30, contract: 'PT 30h',  storeId: 's1', email: 'luca.ferrari@maori.it' },
  { id: 'e5', name: 'Aisha Diallo',    role: 'Addetta', hours: 38, contract: 'CTI 38h', storeId: 's1', email: 'aisha.diallo@maori.it' },
  { id: 'e6', name: 'Davide Greco',    role: 'Addetto', hours: 20, contract: 'PT 20h',  storeId: 's1', email: 'davide.greco@maori.it' },
  { id: 'e7', name: 'Elena Conti',     role: 'Addetta', hours: 24, contract: 'PT 24h',  storeId: 's1', email: 'elena.conti@maori.it' },
];
const DEFAULT_SCHEDULE = {
  e1: ['morning','morning','off','evening','evening','close','close'],
  e2: ['off','mid','mid','off','morning','evening','off'],
  e3: ['evening','close','off','morning','off','morning','evening'],
  e4: ['mid','off','morning','morning','evening','off','evening'],
  e5: ['morning','evening','evening','close','off','off','morning'],
  e6: ['off','off','close','close','off','mid','mid'],
  e7: ['close','off','morning','off','close','close','off'],
};
// Pending Google/Nextcloud approvals  chi ha richiesto accesso e non · ancora stato approvato dal super admin
function emptyWeek() {
  return ['off','off','off','off','off','off','off'];
}
function normalizeWeek(days) {
  const next = Array.isArray(days) ? days.slice(0, 7) : [];
  while (next.length < 7) next.push('off');
  return next;
}

//  LocalStorage persistence helpers 
const LS_KEY = 'kairos_v4';
function lsLoad() {
  try {
    const raw = localStorage.getItem(LS_KEY);
    if (raw) return JSON.parse(raw);
  } catch {}
  return null;
}
function lsSave(state) {
  try {
    localStorage.setItem(LS_KEY, JSON.stringify(state));
  } catch {}
}

//  Client backend (se window.KAIROS_API · configurato) 
// Il desktop usa il backend come fonte dati (stato + mutazioni). Le modifiche ai turni
// fanno partire una Web Push all'addetto. Se il server · offline si ricade sullo stato
// locale (localStorage), così l'interfaccia resta disponibile in sviluppo.
const KAIROS_API = (typeof window !== 'undefined' && window.KAIROS_API) || '';
const KAIROS_DESKTOP_SESSION_KEY = 'kairos_desktop_session';
function kairosReadDesktopSession() {
  try { return JSON.parse(localStorage.getItem(KAIROS_DESKTOP_SESSION_KEY)); } catch { return null; }
}
function kairosSetDesktopSession(user, token) {
  const session = { user, token };
  try { localStorage.setItem(KAIROS_DESKTOP_SESSION_KEY, JSON.stringify(session)); } catch {}
  return session;
}
function kairosClearDesktopSession() {
  try { localStorage.removeItem(KAIROS_DESKTOP_SESSION_KEY); } catch {}
}
function kairosDesktopToken() {
  return kairosReadDesktopSession()?.token || '';
}
function kairosAuthHeaders(body) {
  const headers = body ? { 'Content-Type': 'application/json' } : {};
  const token = kairosDesktopToken();
  if (token) headers.Authorization = 'Bearer ' + token;
  return headers;
}
function kairosLogoutDesktop() {
  const token = kairosDesktopToken();
  kairosClearDesktopSession();
  if (KAIROS_API && token) {
    fetch(KAIROS_API + '/api/auth/logout', { method: 'POST', headers: { Authorization: 'Bearer ' + token } }).catch(() => {});
  }
}
function apiMirror(path, body) {
  if (!KAIROS_API) return;
  fetch(KAIROS_API + path, {
    method: 'POST',
    headers: kairosAuthHeaders(true),
    body: JSON.stringify(body),
  }).catch(() => {});
}
async function apiReq(path, method = 'GET', body) {
  const res = await fetch(KAIROS_API + path, {
    method,
    headers: kairosAuthHeaders(body),
    body: body ? JSON.stringify(body) : undefined,
  });
  if (!res.ok) throw new Error('api ' + res.status);
  return res.json().catch(() => null);
}

//  TurniContext 
const TurniContext = React.createContext(null);

function useTurni() {
  return React.useContext(TurniContext);
}

function TurniProvider({ children }) {
  const saved = lsLoad();
  const [brands,           setBrands]           = React.useState(saved?.brands           || DEFAULT_BRANDS);
  const [companies,        setCompanies]        = React.useState(saved?.companies        || DEFAULT_COMPANIES);
  const [stores,           setStores]           = React.useState(saved?.stores           || DEFAULT_STORES);
  const [team,             setTeam]             = React.useState(saved?.team             || DEFAULT_TEAM);
  const [schedule,         setSchedule]         = React.useState(saved?.schedule         || DEFAULT_SCHEDULE);
  const [currentStoreId,   setCurrentStoreId]   = React.useState(saved?.currentStoreId  || 's1');
  const [pendingApprovals, setPendingApprovals] = React.useState(saved?.pendingApprovals || []);
  const [online,           setOnline]           = React.useState(false);

  // Auto-save to localStorage on every state change
  React.useEffect(() => {
    lsSave({ brands, companies, stores, team, schedule, currentStoreId, pendingApprovals });
  }, [brands, companies, stores, team, schedule, currentStoreId, pendingApprovals]);

  // Carica lo stato dal backend (se configurato). Se il server · offline, si resta su localStorage.
  function applyState(s) {
    if (!s) return;
    const nextTeam = s.team || [];
    const nextSchedule = { ...(s.schedule || {}) };
    nextTeam.forEach(e => { nextSchedule[e.id] = normalizeWeek(nextSchedule[e.id]); });
    setBrands(s.brands); setCompanies(s.companies); setStores(s.stores);
    setTeam(nextTeam); setSchedule(nextSchedule);
    setPendingApprovals(s.pendingApprovals || []);
    setCurrentStoreId(prev => {
      const ids = (s.stores || []).map(st => st.id);
      return ids.length && !ids.includes(prev) ? (ids[0] || null) : prev;
    });
  }
  function refresh() {
    if (!KAIROS_API) return Promise.resolve();
    return apiReq('/api/state')
      .then(s => { applyState(s); setOnline(true); return s; })
      .catch(() => { setOnline(false); });
  }
  React.useEffect(() => {
    if (!KAIROS_API) return;
    refresh();
  }, []);

  //  Brand actions 
  function addBrand(name) {
    if (KAIROS_API) { apiReq('/api/brands', 'POST', { name: name.trim() }).then(refresh).catch(() => {}); return; }
    const id = 'b' + Date.now();
    setBrands(bs => [...bs, { id, name: name.trim() }]);
    return id;
  }
  function removeBrand(brandId) {
    if (KAIROS_API) { apiReq('/api/brands/' + brandId, 'DELETE').then(refresh).catch(() => {}); return; }
    const compIds = companies.filter(c => c.brandId === brandId).map(c => c.id);
    const storeIds = stores.filter(s => compIds.includes(s.companyId)).map(s => s.id);
    storeIds.forEach(sid => _removeStoreData(sid));
    setStores(ss => ss.filter(s => !storeIds.includes(s.id)));
    setCompanies(cs => cs.filter(c => c.brandId !== brandId));
    setBrands(bs => bs.filter(b => b.id !== brandId));
  }

  //  Company actions 
  function addCompany(name, brandId) {
    if (KAIROS_API) { apiReq('/api/companies', 'POST', { name: name.trim(), brandId: brandId || brands[0]?.id }).then(refresh).catch(() => {}); return; }
    const id = 'c' + Date.now();
    setCompanies(cs => [...cs, { id, name: name.trim(), brandId: brandId || brands[0]?.id }]);
    return id;
  }
  function removeCompany(companyId) {
    if (KAIROS_API) { apiReq('/api/companies/' + companyId, 'DELETE').then(refresh).catch(() => {}); return; }
    const storeIds = stores.filter(s => s.companyId === companyId).map(s => s.id);
    storeIds.forEach(sid => _removeStoreData(sid));
    setStores(ss => ss.filter(s => s.companyId !== companyId));
    setCompanies(cs => cs.filter(c => c.id !== companyId));
  }

  //  Store actions 
  function addStore(companyId, name, city, short, type = 'street', openingHours = defaultOpeningHours(type)) {
    if (KAIROS_API) { apiReq('/api/stores', 'POST', { companyId, name: name.trim(), city: city.trim(), short: (short || '').trim().toUpperCase(), type, openingHours }).then(refresh).catch(() => {}); return; }
    const id = 's' + Date.now();
    setStores(ss => [...ss, { id, companyId, name: name.trim(), city: city.trim(), short: (short || '').trim().toUpperCase(), type, openingHours }]);
    return id;
  }
  function updateStore(storeId, fields) {
    if (KAIROS_API) { apiReq('/api/stores/' + storeId, 'PUT', fields).then(refresh).catch(() => {}); return; }
    setStores(ss => ss.map(s => s.id === storeId ? { ...s, ...fields } : s));
  }
  function _removeStoreData(storeId) {
    const empIds = team.filter(e => e.storeId === storeId).map(e => e.id);
    setTeam(t => t.filter(e => e.storeId !== storeId));
    setSchedule(s => {
      const next = { ...s };
      empIds.forEach(id => delete next[id]);
      return next;
    });
  }
  function removeStore(storeId) {
    if (currentStoreId === storeId) {
      const remaining = stores.filter(s => s.id !== storeId);
      setCurrentStoreId(remaining[0]?.id || null);
    }
    if (KAIROS_API) { apiReq('/api/stores/' + storeId, 'DELETE').then(refresh).catch(() => {}); return; }
    _removeStoreData(storeId);
    setStores(ss => ss.filter(s => s.id !== storeId));
  }

  //  Employee actions 
  function addEmployee(nome, cognome, hours, email, companyId, storeId = currentStoreId) {
    if (KAIROS_API) { apiReq('/api/employees', 'POST', { nome, cognome, hours, email, storeId, companyId }).then(refresh).catch(() => {}); return; }
    const id = 'e' + Date.now();
    const h = parseInt(hours, 10) || 0;
    const contract = h >= 38 ? `CTI ${h}h` : `PT ${h}h`;
    const storeCompanyId = stores.find(s => s.id === storeId)?.companyId;
    const newEmp = {
      id,
      name: `${nome.trim()} ${cognome.trim()}`,
      role: 'Addetto/a',
      hours: h,
      contract,
      storeId,
      companyId: companyId || storeCompanyId,
      email: String(email || '').trim().toLowerCase(),
    };
    setTeam(t => [...t, newEmp]);
    setSchedule(s => ({ ...s, [id]: ['off','off','off','off','off','off','off'] }));
    return id;
  }
  function removeEmployee(empId) {
    if (KAIROS_API) { apiReq('/api/employees/' + empId, 'DELETE').then(refresh).catch(() => {}); return; }
    setTeam(t => t.filter(e => e.id !== empId));
    setSchedule(s => { const next = { ...s }; delete next[empId]; return next; });
  }
  function updateEmployee(empId, fields) {
    if (KAIROS_API) { apiReq('/api/employees/' + empId, 'PUT', fields).then(refresh).catch(() => {}); return; }
    setTeam(t => t.map(e => e.id === empId ? { ...e, ...fields } : e));
  }

  //  Shift actions 
  function updateShift(empId, dayIdx, shiftValue) {
    setSchedule(s => ({
      ...s,
      [empId]: normalizeWeek(s[empId] || emptyWeek()).map((k, i) => i === dayIdx ? shiftValue : k),
    }));
    // Rispecchia sul backend · notifica push all'addetto (se KAIROS_API · configurato)
    if (KAIROS_API) apiReq('/api/shift', 'POST', { empId, dayIdx, kind: shiftValue }).then(refresh).catch(() => refresh());
  }

  //  Pending approval actions (Super Admin) 
  function approvePendingUser(approvalId, assignedRole) {
    if (KAIROS_API) {
      return apiReq('/api/access-approvals/' + approvalId + '/approve', 'POST', { role: assignedRole }).then(refresh).catch(() => {});
    }
    setPendingApprovals(pa => pa.filter(a => a.id !== approvalId));
    return Promise.resolve();
  }
  function rejectPendingUser(approvalId) {
    if (KAIROS_API) {
      return apiReq('/api/access-approvals/' + approvalId, 'DELETE').then(refresh).catch(() => {});
    }
    setPendingApprovals(pa => pa.filter(a => a.id !== approvalId));
    return Promise.resolve();
  }

  function findEmployeeByEmail(email) {
    const clean = String(email || '').trim().toLowerCase();
    return team.find(e => e.email && e.email.toLowerCase() === clean) || null;
  }

  //  Scope / permessi (Holding · Brand · Società · Negozi) 
  // Capocanali: scoped alle Società assegnate (user.companyIds).
  // Store manager: vede e modifica i negozi assegnati (user.storeIds).
  function brandStoreIds(brandId) {
    const cIds = companies.filter(c => c.brandId === brandId).map(c => c.id);
    return stores.filter(s => cIds.includes(s.companyId)).map(s => s.id);
  }
  function companyStoreIds(companyIds) {
    return stores.filter(s => (companyIds || []).includes(s.companyId)).map(s => s.id);
  }
  function isSuperAdminRole(user) {
    return user?.role === 'super_admin';
  }
  function isAdminRole(user) {
    return !!user && (user.role === 'admin' || isSuperAdminRole(user));
  }
  function _managerStoreIds(user) {
    if (user.companyIds?.length) return companyStoreIds(user.companyIds);
    if (user.storeIds?.length) return user.storeIds;
    if (user.brandId) return companyStoreIds(companies.filter(c => c.brandId === user.brandId).map(c => c.id));
    return [];
  }
  function visibleStoreIds(user) {
    if (!user || isAdminRole(user)) return stores.map(s => s.id);
    if (user.role === 'capo')         return companyStoreIds(user.companyIds);
    if (user.role === 'manager')      return _managerStoreIds(user);
    if (user.role === 'store_manager') return user.storeIds || [];
    return [];
  }
  function editableStoreIds(user) {
    if (!user || isAdminRole(user)) return stores.map(s => s.id);
    if (user.role === 'capo')         return companyStoreIds(user.companyIds);
    if (user.role === 'manager')      return _managerStoreIds(user);
    if (user.role === 'store_manager') return user.storeIds || [];
    return [];
  }
  function canEditStore(user, storeId) {
    return editableStoreIds(user).includes(storeId);
  }
  function canManageStructure(user) {
    return !!user && (isAdminRole(user) || user.role === 'capo' || (user.role === 'manager' && !!user.companyIds?.length));
  }
  // Solo l'admin gestisce brand e Società (creazione/eliminazione); il capo gestisce i negozi delle sue Società.
  function canManageBrandsAndCompanies(user) {
    return isAdminRole(user);
  }
  function visibleCompanyIds(user) {
    if (!user || isAdminRole(user)) return companies.map(c => c.id);
    if (user.role === 'capo')    return user.companyIds || [];
    if (user.role === 'manager') return user.companyIds?.length ? user.companyIds : companies.filter(c => c.brandId === user.brandId).map(c => c.id);
    if (user.role === 'store_manager') {
      const cIds = new Set(stores.filter(s => (user.storeIds || []).includes(s.id)).map(s => s.companyId));
      return companies.map(c => c.id).filter(id => cIds.has(id));
    }
    return [];
  }
  function visibleBrandIds(user) {
    if (!user || isAdminRole(user)) return brands.map(b => b.id);
    const cIds = visibleCompanyIds(user);
    const bIds = new Set(companies.filter(c => cIds.includes(c.id)).map(c => c.brandId));
    if (user.role === 'manager' && user.brandId) bIds.add(user.brandId);
    return brands.map(b => b.id).filter(id => bIds.has(id));
  }
  function confirmWeek(storeId) {
    if (!KAIROS_API) return Promise.resolve({ ok: true, notified: 0 });
    return apiReq('/api/notify-week', 'POST', { storeId });
  }

  const ctx = {
    // State
    brands, companies, stores, team, schedule, currentStoreId, pendingApprovals,
    // Computed helpers
    currentStore: stores.find(s => s.id === currentStoreId) || null,
    currentTeam:  team.filter(e => e.storeId === currentStoreId),
    // Actions
    addBrand, removeBrand,
    addCompany, removeCompany,
    addStore, updateStore, removeStore,
    setCurrentStoreId,
    addEmployee, removeEmployee, updateEmployee,
    updateShift,
    approvePendingUser, rejectPendingUser,
    findEmployeeByEmail,
    online, refresh, confirmWeek, holding: HOLDING_NAME,
    // Scope / permissions
    visibleStoreIds, editableStoreIds, canEditStore,
    isSuperAdminRole, isAdminRole,
    canManageStructure, canManageBrandsAndCompanies,
    visibleCompanyIds, visibleBrandIds,
    defaultOpeningHours,
  };

  return (
    <TurniContext.Provider value={ctx}>
      {children}
    </TurniContext.Provider>
  );
}

//  Static seed used by code that still references TU_TEAM/TU_SCHEDULE 
const TU_TEAM     = DEFAULT_TEAM;
const TU_SCHEDULE = DEFAULT_SCHEDULE;
const TU_STORES   = DEFAULT_STORES;

Object.assign(window, {
  TuAvatar, TuIcon, tuInitials, tuAvatarColor,
  TU_SHIFT_KINDS, TU_STATUS_KINDS, TU_TEAM, TU_SCHEDULE, TU_STORES,
  DEFAULT_OPENING_HOURS, MALL_OPENING_HOURS,
  kairosReadDesktopSession, kairosSetDesktopSession, kairosClearDesktopSession, kairosLogoutDesktop, kairosDesktopToken, kairosAuthHeaders,
  TU_DAYS_SHORT, TU_DAYS_LONG, TU_MONTHS, TU_WEEK_DATES, TU_WEEK_LABEL, TU_TODAY_INDEX, TU_TODAY, TU_WEEK_MONDAY: _TU_WEEK.monday,
  TurniContext, TurniProvider, useTurni,
});
