/* ============================================================
   APP — routing, shell, modals, toast, persistence
   ============================================================ */

const LS = 'smartfleet_session_v1';
function loadState(){ try { return JSON.parse(localStorage.getItem(LS)) || {}; } catch { return {}; } }
function saveState(s){ try { localStorage.setItem(LS, JSON.stringify(s)); } catch {} }

const TITLES = {
  dashboard:    { t:'Dashboard',          s:'Panoramica della flotta' },
  catalogo:     { t:'Catalogo',           s:'Tutti i mezzi disponibili' },
  prenotazioni: { t:'Prenotazioni',       s:'Gestione prenotazioni e scadenze' },
  noleggi:      { t:'Noleggi in corso',   s:'Mezzi attualmente a noleggio · date di rientro' },
  archivio:     { t:'Archivio prenotazioni', s:'Prenotazioni liberate e confermate' },
  anagrafica:   { t:'Anagrafica clienti', s:'Elenco clienti — ragione sociale, zona, categoria' },
  notifiche:    { t:'Notifiche',          s:'Scegli cosa ricevere e come' },
  attivita:     { t:'Log attività',       s:'Storico azioni commerciali' },
  admin:        { t:'Console Admin',      s:'Controllo completo della piattaforma' },
};

function Toast({ msg }) {
  if(!msg) return null;
  return (
    <div className="no-print" style={{ position:'fixed', bottom:26, left:'50%', transform:'translateX(-50%)', zIndex:200,
      display:'flex', alignItems:'center', gap:11, padding:'13px 20px', background:'#15171c', color:'#fff',
      borderRadius:99, boxShadow:'var(--sh-3)', fontSize:14, fontWeight:600, animation:'floatIn .25s cubic-bezier(.2,.7,.3,1)' }}>
      <span style={{ width:22, height:22, borderRadius:99, background:'var(--st-disponibile)', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
        <Icon name="check" size={14} stroke={3} style={{ color:'#fff' }} />
      </span>
      {msg}
    </div>
  );
}

// ============================================================
// Mapping bidirezionale tra schema DB Supabase (snake_case)
// e modello in-app (camelCase)
// ============================================================
function productFromDb(row) {
  if (!row) return row;
  return {
    ...row,
    cat: row.category_id || null,
    sub: row.sottocategoria || '',
    stato: row.status,
    prezzoConsigliato: row.prezzo_consigliato,
    prezzoMinimo: row.prezzo_minimo,
    prezzoGiorno: row.prezzo_giorno,
    prezzoMese: row.prezzo_mese,
    attr: row.attr || {},
    liste: row.liste || [],
    dest: (row.liste && row.liste[0]) || 'Vendita',
  };
}
function productToDb(p) {
  return {
    matricola: p.matricola,
    marca: p.marca || null,
    modello: p.modello || null,
    nome: p.nome,
    category_id: p.cat || null,
    sottocategoria: p.sub || null,
    status: p.stato,
    nuovo: !!p.nuovo,
    posizione: p.posizione || null,
    prezzo_consigliato: p.prezzoConsigliato ?? null,
    prezzo_minimo: p.prezzoMinimo ?? null,
    prezzo_giorno: p.prezzoGiorno ?? null,
    prezzo_mese: p.prezzoMese ?? null,
    liste: p.liste || [],
    attr: p.attr || {},
  };
}

// ============================================================
// Mapping bookings: state app (camelCase, Date objects) ↔ DB (snake_case, ISO dates)
// ============================================================
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
const isUuid = (v) => typeof v === 'string' && UUID_RE.test(v);
const toIsoDate = (d) => {
  if (!d) return null;
  const date = (d instanceof Date) ? d : new Date(d);
  if (isNaN(date.getTime())) return null;
  return date.toISOString().slice(0, 10);
};

function bookingFromDb(row) {
  if (!row) return row;
  return {
    ...row,
    inizio: row.data_inizio ? new Date(row.data_inizio) : null,
    fine: row.data_fine ? new Date(row.data_fine) : null,
    prodId: row.product_id,
    commerciale: row.commerciale_nome,
    batteriaNuova: row.batteria_nuova,
    stato: row.status,
  };
}
function bookingToDb(b) {
  return {
    id: b.id,
    product_id: isUuid(b.prodId) ? b.prodId : null,
    cliente: b.cliente || '',
    cliente_id: isUuid(b.cliente_id) ? b.cliente_id : (isUuid(b.selectedCliente?.id) ? b.selectedCliente.id : null),
    commerciale_id: isUuid(b.commerciale_id) ? b.commerciale_id : null,
    commerciale_nome: b.commerciale || null,
    tipo: b.tipo,
    data_inizio: toIsoDate(b.inizio),
    data_fine: toIsoDate(b.fine),
    note: b.note || null,
    probabilita: b.probabilita ?? null,
    status: b.stato || 'attiva',
    zona_id: isUuid(b.zonaId) ? b.zonaId : (isUuid(b.zona_id) ? b.zona_id : null),
    batteria_nuova: !!b.batteriaNuova,
    client_category_id: isUuid(b.catId) ? b.catId : (isUuid(b.client_category_id) ? b.client_category_id : null),
    proroghe: b.proroghe ?? 0,
  };
}

function archiveFromDb(row) {
  if (!row) return row;
  return {
    ...row,
    inizio: row.data_inizio ? new Date(row.data_inizio) : null,
    fine: row.data_fine ? new Date(row.data_fine) : null,
    prodId: row.product_id,
    commerciale: row.commerciale_nome,
    chiusoIl: row.chiuso_il ? new Date(row.chiuso_il) : null,
    numeroPreventivo: row.numero_preventivo,
    prezzoPattuito: row.prezzo_pattuito,
    tempoNoleggio: row.tempo_noleggio,
    dataConsegna: row.data_consegna ? new Date(row.data_consegna) : null,
    dataRientro: row.data_rientro ? new Date(row.data_rientro) : null,
    // Nuovi campi noleggio esteso
    prezzo_tipo: row.prezzo_tipo,
    prezzo_giornaliero_calc: row.prezzo_giornaliero_calc,
    prezzo_mensile_calc: row.prezzo_mensile_calc,
    interrotto: !!row.interrotto,
    data_interruzione: row.data_interruzione ? new Date(row.data_interruzione) : null,
    interruzione_reason_id: row.interruzione_reason_id,
    interruzione_note: row.interruzione_note,
  };
}
function archiveToDb(b) {
  return {
    id: b.id,
    product_id: isUuid(b.prodId) ? b.prodId : null,
    cliente: b.cliente || '',
    cliente_id: isUuid(b.cliente_id) ? b.cliente_id : null,
    commerciale_id: isUuid(b.commerciale_id) ? b.commerciale_id : null,
    commerciale_nome: b.commerciale || null,
    tipo: b.tipo,
    data_inizio: toIsoDate(b.inizio),
    data_fine: toIsoDate(b.fine),
    note: b.note || null,
    esito: b.esito,
    chiuso_il: b.chiusoIl ? (b.chiusoIl instanceof Date ? b.chiusoIl.toISOString() : b.chiusoIl) : new Date().toISOString(),
    zona_id: isUuid(b.zona_id) ? b.zona_id : (isUuid(b.zonaId) ? b.zonaId : null),
    client_category_id: isUuid(b.client_category_id) ? b.client_category_id : (isUuid(b.catId) ? b.catId : null),
    numero_preventivo: b.numeroPreventivo || null,
    prezzo_pattuito: b.prezzoPattuito ?? null,
    tempo_noleggio: b.tempoNoleggio || null,
    data_consegna: toIsoDate(b.dataConsegna),
    data_rientro: toIsoDate(b.dataRientro),
    rientrato: !!b.rientrato,
    // Nuovi campi noleggio esteso
    prezzo_tipo: b.prezzoTipo || b.prezzo_tipo || null,
    prezzo_giornaliero_calc: b.prezzoGiornalieroCalc ?? b.prezzo_giornaliero_calc ?? null,
    prezzo_mensile_calc: b.prezzoMensileCalc ?? b.prezzo_mensile_calc ?? null,
    interrotto: !!b.interrotto,
    data_interruzione: toIsoDate(b.data_interruzione),
    interruzione_reason_id: isUuid(b.interruzione_reason_id) ? b.interruzione_reason_id : null,
    interruzione_note: b.interruzione_note || null,
  };
}

function App() {
  const init = loadState();
  const [session, setSession] = useState(null);
  const [currentUser, setCurrentUser] = useState(null);
  const [view, setView] = useState(init.view || 'dashboard');
  const [selected, setSelected] = useState(null);
  const [catFilter, setCatFilter] = useState(init.catFilter || null);
  const [modal, setModal] = useState(null);
  const [editor, setEditor] = useState(null);
  const [adminTab, setAdminTab] = useState('attributi');
  const [toastMsg, setToastMsg] = useState('');
  const [attributi, setAttributi] = useState([]);
  const [listino, setListino] = useState({});
  const [zone, setZone] = useState([]);
  const [strListino, setStrListino] = useState([]);
  const [users, setUsers] = useState([]);
  const [products, setProducts] = useState([]);
  const [bookings, setBookings] = useState([]);
  const [clienteCat, setClienteCat] = useState([]);
  const [usuraCoeff, setUsuraCoeff] = useState([]);
  const [archive, setArchive] = useState([]);
  const [clienti, setClienti] = useState([]);
  const [interruptionReasons, setInterruptionReasons] = useState([]);
  const [rentalExtensions, setRentalExtensions] = useState([]);
  const [selBooking, setSelBooking] = useState(null);
  const [bookingOrigin, setBookingOrigin] = useState('prenotazioni');
  const [theme, setTheme] = useState(init.theme || 'light');
  const [drawerOpen, setDrawerOpen] = useState(false);
  const vp = useViewport();
  const toastTimer = useRef();

  useEffect(() => {
    if (!window.SF_CONFIG.useSupabase) return;
    const sb = window.DataAPI;

    // FIX mobile: aspetta che la sessione Supabase Auth sia ripristinata PRIMA
    // di caricare i dati, altrimenti le query RLS girano senza utente autenticato
    // e ritornano vuoto (su mobile la rete è più lenta e il timing peggiora).
    const loadAll = async () => {
      // 1) Ripristina sessione e attendila
      try {
        const res = await window.AuthAPI.getCurrentSession();
        if (res?.profile) {
          window.CURRENT_USER = res.profile;
          setCurrentUser(res.profile);
          setSession(res.profile.role || res.profile.ruolo);
        }
      } catch (e) { console.error('restore session', e); }

      // 2) Solo ora carico i dati (la sessione RLS è attiva)
      loadDataRef.current();
    };

    loadAll();
  }, []);

  // Caricamento dati separato dalla sessione, richiamabile dopo il login
  const loadDataRef = useRef(null);
  loadDataRef.current = () => {
    if (!window.SF_CONFIG.useSupabase) return;
    const sb = window.DataAPI;
    Promise.all([
      sb.list('attributes'),
      sb.list('attribute_categories'),
    ]).then(([attrs, links]) => {
      const byAttr = {};
      (links || []).forEach(l => {
        (byAttr[l.attribute_id] ||= []).push(l.category_id);
      });
      const merged = (attrs || []).map(a => ({
        ...a,
        tipi: byAttr[a.id] || [],
        multiplo: !!a.multiplo,
        sede: !!a.sede,
      }));
      merged.sort((a, b) => {
        if (!!a.rilievo !== !!b.rilievo) return a.rilievo ? -1 : 1;
        return (a.ordine ?? 999) - (b.ordine ?? 999);
      });
      setAttributi(merged);
    });
    sb.list('battery_prices').then(data => {
      const map = {};
      (data || []).forEach(r => { map[r.voltaggio + '|' + r.amperaggio] = r.su_richiesta ? 'SR' : r.prezzo; });
      setListino(map);
    });
    sb.list('delivery_zones').then(data => {
      const mapped = (data || []).map(z => ({
        ...z,
        tariffa: z.su_richiesta ? SR : z.tariffa,
      }));
      setZone(mapped);
    });
    sb.list('str_groups').then(async groups => {
      const prices = await sb.list('str_prices');
      const merged = [];
      (groups || []).sort((a,b) => a.ordine - b.ordine).forEach(g => {
        merged.push({ id: g.id, tipo: 'gruppo', nome: g.nome });
        (prices || []).filter(p => p.group_id === g.id).sort((a,b) => a.ordine - b.ordine)
          .forEach(p => merged.push({
            id: p.id, nome: p.nome,
            giorno: p.giorno_sr ? 'SR' : p.giorno,
            mese: p.mese_sr ? 'SR' : p.mese
          }));
      });
      setStrListino(merged);
    });
    sb.list('client_categories').then(data => {
      const mapped = (data || []).map(c => ({ ...c, usura: c.usura_pct }));
      setClienteCat(mapped);
    });
    sb.list('wear_coefficients').then(data => {
      const mapped = (data || []).map(c => ({
        ...c, min: c.min_pct, max: c.max_pct, aumento: c.aumento_pct,
      }));
      setUsuraCoeff(mapped);
    });
    sb.list('users').then(data => setUsers(data || []));
    sb.list('products').then(data => {
      const mapped = (data || []).map(productFromDb);
      setProducts(mapped);
    });
    sb.list('bookings').then(data => setBookings((data || []).map(bookingFromDb)));
    sb.list('bookings_archive').then(data => setArchive((data || []).map(archiveFromDb)));
    sb.list('clienti').then(data => setClienti(data || []));
    sb.list('interruption_reasons').then(data => setInterruptionReasons(data || []));
    sb.list('rental_extensions').then(data => setRentalExtensions(data || []));
  };

  useEffect(()=>{ saveState({ session, view, selId:selected?.id, catFilter, theme }); }, [session, view, selected, catFilter, theme]);

  const toast = (msg) => { setToastMsg(msg); clearTimeout(toastTimer.current); toastTimer.current=setTimeout(()=>setToastMsg(''), 3200); };
  const nav = (v) => { setView(v); };
  const openProduct = (p) => { setSelected(p); setView('prodotto'); };
  const onPrenota = (p) => setModal({ type:'booking', product:p, booking:null });
  const onPDF = (p, opts) => setModal({ type:'pdf', product:p, ...(opts||{}) });
  const openStr = () => setModal({ type:'str' });
  const openStorico = (p) => setModal({ type:'storico', product:p });

  const logout = async () => {
    await window.AuthAPI.signOut();
    window.CURRENT_USER = null;
    setSession(null); setCurrentUser(null); setView('dashboard'); setSelected(null);
  };

  const handleLogin = (role) => {
    setCurrentUser(window.CURRENT_USER || null);
    setSession(role); setView('dashboard');
    // FIX mobile: al primo login i dati non erano ancora stati caricati
    // (loadAll era girato a vuoto pre-login). Ricarico ora che la sessione è attiva.
    if (loadDataRef.current) loadDataRef.current();
  };

  const myName = () => currentUser?.nome || null;

  // Permessi: admin/backoffice tutto, commerciale solo le sue
  const canFreeBooking = (b) => session==='admin' || session==='backoffice' || (session==='commerciale' && b.commerciale===myName());
  const canConfirmBooking = (b) => session==='admin' || session==='backoffice' || (session==='commerciale' && b.commerciale===myName());

  const openBooking = (b, origin) => { setSelBooking(b); setBookingOrigin(origin||'prenotazioni'); setView('prenotazione'); };
  const editBooking = (b) => setModal({ type:'booking', product: products.find(p=>p.id===b.prodId)||null, booking:b });

  const bookingAction = async (b, action) => {
    if (action==='libera' && !canFreeBooking(b)) { toast('Non puoi liberare una prenotazione di un altro commerciale'); return; }
    if (action==='conferma') {
      if (!canConfirmBooking(b)) { toast('Non puoi confermare una prenotazione di un altro commerciale'); return; }
      setModal({ type:'conferma', booking:b }); return;
    }
    if (action==='libera') {
      const archived = { ...b, esito:'liberata', chiusoIl: new Date() };

      if (window.SF_CONFIG.useSupabase) {
        try {
          // 1) Upsert in bookings_archive (evita duplicate key 23505 se già archiviata)
          await window.DataAPI.upsert('bookings_archive', archiveToDb(archived), 'id');
          // 2) Delete da bookings
          await window.DataAPI.remove('bookings', b.id);
          // 3) FIX CRITICO: se il prodotto era 'PRENOTATO', torna a 'DISPONIBILE'
          const prod = products.find(p => p.id === b.prodId);
          if (prod && prod.stato === 'PRENOTATO' && isUuid(b.prodId)) {
            try { await window.DataAPI.update('products', b.prodId, { status: 'DISPONIBILE' }); }
            catch(pe) { console.error('reset stato prodotto (libera)', pe); }
          }
        } catch (e) {
          console.error('libera', e);
          toast('Errore: ' + (e?.message || 'sconosciuto'));
          return;
        }
      }

      // Aggiorna stato prodotto localmente (solo se era PRENOTATO)
      setProducts(prev => prev.map(p => (p.id === b.prodId && p.stato === 'PRENOTATO') ? { ...p, stato: 'DISPONIBILE' } : p));
      setArchive(prev => [archived, ...prev.filter(x=>x.id!==b.id)]);
      setBookings(prev => prev.filter(x=>x.id!==b.id));
      setView('prenotazioni'); setSelBooking(null);
      toast('Mezzo liberato — prenotazione spostata in archivio');
      window.LogAPI?.logEvent('booking.freed', {
        entity_type: 'booking', entity_id: b.id,
        title: 'Prenotazione liberata',
        description: `${b.prodLabel} → ${b.cliente}`,
        metadata: { commerciale_nome: b.commerciale, cliente: b.cliente, prod_label: b.prodLabel, tipo: b.tipo, prod_id: b.prodId },
      });
      // Notifica watchers (tieni d'occhio)
      window.WatchAPI?.notifyWatchers?.(b.prodId, 'liberato', {
        booking_id: b.id,
        commerciale: b.commerciale,
        cliente: b.cliente,
      });
      return;
    }

    // proroga / riprenota: aggiorna data_fine + stato
    const newFine = daysFromNow(14);
    const newProroghe = action==='proroga' ? (b.proroghe||0)+1 : (b.proroghe||0);
    const updated = { ...b, stato:'attiva', fine: newFine, proroghe: newProroghe };

    if (window.SF_CONFIG.useSupabase) {
      try {
        await window.DataAPI.update('bookings', b.id, {
          status: 'attiva',
          data_fine: toIsoDate(newFine),
          proroghe: newProroghe,
        });
      } catch (e) {
        console.error('proroga/riprenota', e);
        toast('Errore: ' + (e?.message || 'sconosciuto'));
        return;
      }
    }

    setBookings(prev => prev.map(x => x.id!==b.id ? x : updated));
    if (selBooking && selBooking.id===b.id) setSelBooking(updated);
    toast(action==='riprenota'?'Mezzo riprenotato per 2 settimane':'Prenotazione prorogata di 2 settimane');
    window.LogAPI?.logEvent('booking.extended', {
      entity_type: 'booking', entity_id: b.id,
      title: action==='riprenota' ? 'Prenotazione riprenotata' : 'Prenotazione prorogata',
      description: `${b.prodLabel} → ${b.cliente} · +2 settimane`,
      metadata: { commerciale_nome: b.commerciale, cliente: b.cliente, prod_label: b.prodLabel, tipo: b.tipo, action },
    });
  };

  // Conferma prenotazione: cambia stato prodotto, salva date, archivia
  const confirmBooking = async (b, data) => {
    const isVendita = b.tipo === 'Vendita';
    const isNoleggio = b.tipo === 'STR' || b.tipo === 'LTR';
    const newProductStato = isVendita ? 'VENDUTO' : isNoleggio ? 'NOLEGGIATO' : null;

    // 1) Aggiorna stato prodotto (status nel DB)
    if (newProductStato) {
      setProducts(prev => prev.map(p => p.id === b.prodId ? { ...p, stato: newProductStato } : p));
      if (window.SF_CONFIG.useSupabase && isUuid(b.prodId)) {
        try { await window.DataAPI.update('products', b.prodId, { status: newProductStato }); }
        catch(e) { console.error('Errore update stato prodotto', e); }
      }
    }

    // 2) Costruisci record archivio
    const archiveRecord = {
      ...b,
      esito: 'confermata',
      chiusoIl: new Date(),
      numeroPreventivo: data.numeroPreventivo,
      prezzoPattuito: data.prezzoPattuito,
      prezzoTipo: data.prezzoTipo || null,
      prezzoGiornalieroCalc: data.prezzoGiornalieroCalc ?? null,
      prezzoMensileCalc: data.prezzoMensileCalc ?? null,
    };
    if (isNoleggio && data.dataConsegna && data.dataRientro) {
      archiveRecord.dataConsegna = new Date(data.dataConsegna);
      archiveRecord.dataRientro = new Date(data.dataRientro);
      archiveRecord.rientrato = false;
      archiveRecord.inizio = new Date(data.dataConsegna);
      archiveRecord.fine = new Date(data.dataRientro);
    }

    // 3) Upsert su bookings_archive + delete da bookings
    if (window.SF_CONFIG.useSupabase) {
      try {
        await window.DataAPI.upsert('bookings_archive', archiveToDb(archiveRecord), 'id');
        await window.DataAPI.remove('bookings', b.id);
      } catch (e) {
        console.error('confirmBooking', e);
        toast('Errore conferma: ' + (e?.message || 'sconosciuto'));
        return;
      }
    }

    setArchive(prev => [archiveRecord, ...prev.filter(x => x.id !== b.id)]);
    setBookings(prev => prev.filter(x => x.id !== b.id));
    setModal(null);
    setView(bookingOrigin === 'archivio' ? 'archivio' : 'prenotazioni');
    setSelBooking(null);

    if (isVendita) toast('Vendita confermata · mezzo passato a VENDUTO');
    else if (isNoleggio) toast('Noleggio confermato · mezzo in "Noleggi in corso"');
    else toast('Prenotazione confermata');

    // Notifica watchers (tieni d'occhio) — venduto o noleggiato
    if (newProductStato) {
      window.WatchAPI?.notifyWatchers?.(b.prodId, newProductStato.toLowerCase(), {
        booking_id: b.id,
        commerciale: b.commerciale,
        cliente: b.cliente,
      });
    }

    const description = isNoleggio && data.dataConsegna && data.dataRientro
      ? `${b.prodLabel} → ${b.cliente} · ${new Date(data.dataConsegna).toLocaleDateString('it-IT')} → ${new Date(data.dataRientro).toLocaleDateString('it-IT')}`
      : `${b.prodLabel} → ${b.cliente}`;
    window.LogAPI?.logEvent('booking.confirmed', {
      entity_type: 'booking', entity_id: b.id,
      title: isVendita ? 'Vendita confermata' : isNoleggio ? `Noleggio ${b.tipo} confermato` : 'Prenotazione confermata',
      description,
      metadata: {
        commerciale_nome: b.commerciale, cliente: b.cliente,
        prod_id: b.prodId, prod_label: b.prodLabel, tipo: b.tipo,
        data_consegna: data.dataConsegna, data_rientro: data.dataRientro,
        numero_preventivo: data.numeroPreventivo, prezzo_pattuito: data.prezzoPattuito,
      },
    });
  };

  const saveContractData = async (b, data) => {
    if (window.SF_CONFIG.useSupabase) {
      try {
        const patch = {};
        if ('numeroPreventivo' in data) patch.numero_preventivo = data.numeroPreventivo;
        if ('prezzoPattuito' in data) patch.prezzo_pattuito = data.prezzoPattuito;
        if ('tempoNoleggio' in data) patch.tempo_noleggio = data.tempoNoleggio;
        if ('dataConsegna' in data) patch.data_consegna = toIsoDate(data.dataConsegna);
        if ('dataRientro' in data) patch.data_rientro = toIsoDate(data.dataRientro);
        if ('rientrato' in data) patch.rientrato = !!data.rientrato;
        if (Object.keys(patch).length) await window.DataAPI.update('bookings_archive', b.id, patch);
      } catch (e) {
        console.error('saveContractData', e);
        toast('Errore aggiornamento: ' + (e?.message || 'sconosciuto'));
        return;
      }
    }
    setArchive(prev => prev.map(x=>x.id===b.id?{ ...x, ...data }:x));
    if (selBooking && selBooking.id===b.id) setSelBooking(s=>({ ...s, ...data }));
    setModal(null);
    toast('Dati contratto aggiornati');
  };

  const saveBooking = async (data, isEdit) => {
    // FIX CRITICO: se è una NUOVA prenotazione, verifica che il prodotto sia libero.
    // Impedisce che 2 commerciali prenotino la stessa macchina simultaneamente.
    if (!isEdit) {
      const currentProd = products.find(p => p.id === data.prodId);
      if (!currentProd) {
        toast('Prodotto non trovato');
        return;
      }
      if (currentProd.stato === 'PRENOTATO' || currentProd.stato === 'NOLEGGIATO' || currentProd.stato === 'VENDUTO') {
        const conflict = bookings.find(b => b.prodId === data.prodId && b.stato === 'attiva');
        const statoLabel = STATI[currentProd.stato]?.label || currentProd.stato;
        toast(`Prodotto già ${statoLabel}${conflict ? ` da ${conflict.commerciale}` : ''}. Aggiorna il catalogo.`);
        return;
      }
    }

    if (window.SF_CONFIG.useSupabase) {
      try {
        const dbRow = bookingToDb(data);
        if (isEdit) {
          await window.DataAPI.update('bookings', data.id, dbRow);
        } else {
          // Genera id text se non c'è
          if (!data.id) data.id = 'b' + Date.now();
          dbRow.id = data.id;
          await window.DataAPI.insert('bookings', dbRow);
          // FIX CRITICO: aggiorna stato prodotto → 'PRENOTATO'
          // Solo se prodId è un UUID valido (i mock hanno id non-UUID)
          if (isUuid(data.prodId)) {
            try {
              await window.DataAPI.update('products', data.prodId, { status: 'PRENOTATO' });
            } catch (pe) {
              console.error('Update product state failed', pe);
              // Rollback prenotazione
              await window.DataAPI.remove('bookings', data.id).catch(()=>{});
              toast('Errore: impossibile aggiornare stato prodotto. Riprova.');
              return;
            }
          }
        }
      } catch (e) {
        console.error('saveBooking', e);
        toast('Errore salvataggio prenotazione: ' + (e?.message || 'sconosciuto'));
        return;
      }
    }

    if (isEdit) {
      setBookings(prev=>prev.map(b=>b.id===data.id?data:b));
      if(selBooking&&selBooking.id===data.id) setSelBooking(data);
      toast('Prenotazione aggiornata');
      window.LogAPI?.logEvent('booking.modified', {
        entity_type: 'booking', entity_id: data.id,
        title: 'Prenotazione modificata',
        description: `${data.prodLabel} → ${data.cliente}`,
        metadata: { commerciale_nome: data.commerciale, cliente: data.cliente, prod_label: data.prodLabel, tipo: data.tipo },
      });
    } else {
      // Aggiorna stato prodotto localmente (UPPERCASE come nel resto del sistema)
      setProducts(prev => prev.map(p => p.id === data.prodId ? { ...p, stato: 'PRENOTATO' } : p));
      setBookings(prev=>[data, ...prev]);
      toast(`Prenotazione creata per ${data.cliente}`);
      window.LogAPI?.logEvent('booking.created', {
        entity_type: 'booking', entity_id: data.id,
        title: 'Nuova prenotazione',
        description: `${data.prodLabel} → ${data.cliente}`,
        metadata: { commerciale_nome: data.commerciale, cliente: data.cliente, prod_label: data.prodLabel, tipo: data.tipo, prod_id: data.prodId },
      });
      // Notifica i watcher del prodotto (tieni d'occhio)
      window.WatchAPI?.notifyWatchers?.(data.prodId, 'prenotato', {
        booking_id: data.id,
        commerciale: data.commerciale,
        cliente: data.cliente,
      });
    }
    setModal(null);
  };

  // ============================================================
  // NOLEGGIO: proroga, interruzione, modifica data inizio
  // ============================================================
  const extendRental = async (booking, ext) => {
    if (!window.SF_CONFIG.useSupabase) { toast('Supabase non attivo'); return; }
    try {
      // Calcola numero progressivo (max+1 tra le proroghe di questo noleggio)
      const existing = rentalExtensions.filter(e => e.archive_id === booking.id);
      const nextNum = existing.length === 0 ? 1 : Math.max(...existing.map(e => e.numero || 0)) + 1;

      const row = await window.DataAPI.insert('rental_extensions', {
        archive_id: booking.id,
        numero: nextNum,
        data_inizio_proroga: ext.data_inizio_proroga,
        data_fine_proroga: ext.data_fine_proroga,
        numero_preventivo: ext.numero_preventivo,
        prezzo_pattuito: ext.prezzo_pattuito,
        prezzo_tipo: ext.prezzo_tipo,
        prezzo_giornaliero_calc: ext.prezzo_giornaliero_calc,
        prezzo_mensile_calc: ext.prezzo_mensile_calc,
        note: ext.note,
        created_by_id: currentUser?.id || null,
        created_by_nome: currentUser?.nome || null,
      });

      // Aggiorna data_rientro su bookings_archive alla nuova scadenza
      await window.DataAPI.update('bookings_archive', booking.id, {
        data_rientro: ext.data_fine_proroga,
      });

      // State updates
      setRentalExtensions(prev => [...prev, row]);
      setArchive(prev => prev.map(b => b.id === booking.id ? {
        ...b,
        dataRientro: new Date(ext.data_fine_proroga),
        fine: new Date(ext.data_fine_proroga),
      } : b));
      if (selBooking && selBooking.id === booking.id) {
        setSelBooking(s => ({ ...s, dataRientro: new Date(ext.data_fine_proroga), fine: new Date(ext.data_fine_proroga) }));
      }
      setModal(null);
      toast('Noleggio prorogato');

      window.LogAPI?.logEvent('rental.extended_with_quote', {
        entity_type: 'booking', entity_id: booking.id,
        title: `Noleggio prorogato #${nextNum}`,
        description: `${booking.prodLabel} → ${booking.cliente} · nuova scadenza ${new Date(ext.data_fine_proroga).toLocaleDateString('it-IT')}`,
        metadata: {
          commerciale_nome: booking.commerciale, cliente: booking.cliente,
          prod_label: booking.prodLabel, tipo: booking.tipo,
          extension_number: nextNum,
          data_inizio_proroga: ext.data_inizio_proroga,
          data_fine_proroga: ext.data_fine_proroga,
          numero_preventivo: ext.numero_preventivo,
          prezzo_pattuito: ext.prezzo_pattuito,
          prezzo_tipo: ext.prezzo_tipo,
        },
      });
    } catch (e) {
      console.error('extendRental', e);
      toast('Errore proroga: ' + (e?.message || 'sconosciuto'));
    }
  };

  const interruptRental = async (booking, data) => {
    if (!window.SF_CONFIG.useSupabase) { toast('Supabase non attivo'); return; }
    try {
      // 1) Update bookings_archive con dati interruzione
      await window.DataAPI.update('bookings_archive', booking.id, {
        interrotto: true,
        data_interruzione: data.data_interruzione,
        interruzione_reason_id: data.interruzione_reason_id,
        interruzione_note: data.interruzione_note,
      });
      // 2) Update prodotto → IN_ARRIVO
      if (isUuid(booking.prodId)) {
        try { await window.DataAPI.update('products', booking.prodId, { status: 'IN_ARRIVO' }); }
        catch(e) { console.error('update product stato', e); }
      }

      const reason = interruptionReasons.find(r => r.id === data.interruzione_reason_id);
      const updatedBooking = {
        ...booking,
        interrotto: true,
        data_interruzione: new Date(data.data_interruzione),
        interruzione_reason_id: data.interruzione_reason_id,
        interruzione_note: data.interruzione_note,
      };
      setArchive(prev => prev.map(b => b.id === booking.id ? updatedBooking : b));
      setProducts(prev => prev.map(p => p.id === booking.prodId ? { ...p, stato: 'IN_ARRIVO' } : p));
      if (selBooking && selBooking.id === booking.id) setSelBooking(updatedBooking);

      setModal(null);
      toast(`Noleggio interrotto · ${reason?.label || ''}`);

      window.LogAPI?.logEvent('rental.interrupted', {
        entity_type: 'booking', entity_id: booking.id,
        title: 'Noleggio interrotto',
        description: `${booking.prodLabel} → ${booking.cliente} · ${reason?.label || ''}`,
        metadata: {
          commerciale_nome: booking.commerciale, cliente: booking.cliente,
          prod_label: booking.prodLabel, tipo: booking.tipo,
          reason_id: data.interruzione_reason_id,
          reason_label: reason?.label,
          data_interruzione: data.data_interruzione,
          note: data.interruzione_note,
        },
      });
    } catch (e) {
      console.error('interruptRental', e);
      toast('Errore interruzione: ' + (e?.message || 'sconosciuto'));
    }
  };

  const changeStartDate = async (booking, newStartIso) => {
    if (!window.SF_CONFIG.useSupabase) { toast('Supabase non attivo'); return; }
    const today = new Date(); today.setHours(0,0,0,0);
    const currentStart = booking.dataConsegna ? new Date(booking.dataConsegna) : null;
    if (!currentStart || currentStart <= today) {
      toast('Non puoi modificare la data inizio se il noleggio è già iniziato');
      return;
    }
    try {
      await window.DataAPI.update('bookings_archive', booking.id, {
        data_consegna: newStartIso,
        data_inizio: newStartIso,
      });
      const updated = { ...booking, dataConsegna: new Date(newStartIso), inizio: new Date(newStartIso) };
      setArchive(prev => prev.map(b => b.id === booking.id ? updated : b));
      if (selBooking && selBooking.id === booking.id) setSelBooking(updated);

      setModal(null);
      toast('Data di consegna aggiornata');

      window.LogAPI?.logEvent('rental.start_date_changed', {
        entity_type: 'booking', entity_id: booking.id,
        title: 'Data inizio noleggio modificata',
        description: `${booking.prodLabel} → ${booking.cliente} · nuova consegna ${new Date(newStartIso).toLocaleDateString('it-IT')}`,
        metadata: {
          commerciale_nome: booking.commerciale, cliente: booking.cliente,
          prod_label: booking.prodLabel,
          old_date: currentStart.toISOString(),
          new_date: newStartIso,
        },
      });
    } catch (e) {
      console.error('changeStartDate', e);
      toast('Errore: ' + (e?.message || 'sconosciuto'));
    }
  };

  const openEditor = (mode, src) => { setEditor({ mode, source: src }); setView('prodotto-editor'); };
  // ============================================================
  // Mapping bidirezionale tra schema DB (snake_case) e state app (camelCase)
  // ============================================================
  // (productFromDb è definita più sopra come reference)

  const saveProduct = async (out, mode) => {
    const isEdit = mode==='edit';
    const isDuplicate = mode==='duplicate';
    const sourceId = isDuplicate ? out.sourceId : null;   // ProductEditor in duplicate mode passa l'id originale
    const dbRow = productToDb(out);

    if (window.SF_CONFIG.useSupabase) {
      try {
        if (isEdit) {
          const updated = await window.DataAPI.update('products', out.id, dbRow);
          out = { ...out, ...productFromDb(updated) };
        } else {
          const inserted = await window.DataAPI.insert('products', dbRow);
          out = { ...out, ...productFromDb(inserted) };

          // Duplicazione: copia le foto del prodotto originale sul nuovo
          if (isDuplicate && sourceId && window.R2) {
            try {
              const copiedMedia = await window.R2.copyMediaForDuplicate(sourceId, out.id);
              if (copiedMedia.length > 0) {
                toast(`Prodotto duplicato con ${copiedMedia.length} foto`);
              }
            } catch(e) {
              console.warn('Copia foto duplicato fallita:', e?.message || e);
              toast('Prodotto duplicato (foto non copiate per errore)');
            }
          }
        }
      } catch(e) {
        console.error('saveProduct error', e);
        toast('Errore salvataggio: ' + (e?.message || 'sconosciuto'));
        return;
      }
    }

    setProducts(prev => isEdit ? prev.map(p=>p.id===out.id?out:p) : [out, ...prev]);
    setEditor(null); setAdminTab('prodotti'); setView('admin');
    if (!isDuplicate) toast(isEdit ? `Prodotto "${out.marca} ${out.modello}" aggiornato` : `Prodotto "${out.marca} ${out.modello}" creato`);
    window.LogAPI?.logEvent(isEdit ? 'product.modified' : isDuplicate ? 'product.duplicated' : 'product.created', {
      entity_type: 'product', entity_id: out.id,
      title: isEdit ? 'Prodotto modificato' : isDuplicate ? 'Prodotto duplicato' : 'Nuovo prodotto',
      description: `${out.marca} ${out.modello} · matricola ${out.matricola||out.id}`,
      metadata: { matricola: out.matricola||out.id, marca: out.marca, modello: out.modello, cat: out.cat, stato: out.stato, source_id: sourceId },
    });
  };

  // Eliminazione prodotto con cleanup foto R2
  const deleteProduct = async (product) => {
    if (!product?.id) return;
    let mediaCount = 0;
    try {
      const list = await window.DataAPI.list('product_media', { eq:['product_id', product.id] }) || [];
      mediaCount = list.length;
    } catch(e) { /* ignore */ }

    const msg = mediaCount > 0
      ? `Vuoi davvero eliminare "${product.marca} ${product.modello}"?\n\nVerranno cancellate anche ${mediaCount} foto da R2.\nL'operazione è irreversibile.`
      : `Vuoi davvero eliminare "${product.marca} ${product.modello}"?\nL'operazione è irreversibile.`;
    if (!confirm(msg)) return;

    if (window.SF_CONFIG.useSupabase) {
      try {
        if (mediaCount > 0 && window.R2) {
          try { await window.R2.deleteAllForProduct(product.id); }
          catch(e) { console.warn('Cleanup R2 fallito (proseguo):', e?.message || e); }
        }
        await window.DataAPI.remove('products', product.id);
      } catch(e) {
        console.error('deleteProduct error', e);
        toast('Errore eliminazione: ' + (e?.message || 'sconosciuto'));
        return;
      }
    }

    setProducts(prev => prev.filter(p => p.id !== product.id));
    toast(`Prodotto eliminato${mediaCount>0?` (${mediaCount} foto cancellate)`:''}`);
    window.LogAPI?.logEvent('product.deleted', {
      entity_type: 'product', entity_id: product.id,
      title: 'Prodotto eliminato',
      description: `${product.marca} ${product.modello} · matricola ${product.matricola||product.id}`,
      metadata: { matricola: product.matricola||product.id, marca: product.marca, modello: product.modello, media_deleted: mediaCount },
    });
  };

  // Apre editor esistente da matricola duplicata (chiamata da ProductEditor)
  const openExistingProduct = (existingProduct) => {
    setEditor({ mode: 'edit', source: existingProduct });
  };

  if (!session) return <Login onLogin={handleLogin} />;

  const isAdmin = session==='admin';
  const darkTheme = isAdmin && theme==='dark';
  const sidebarDark = isAdmin;
  const head = view==='prodotto' ? { t: selected ? prodLabel(selected) : 'Scheda', s:'Scheda prodotto' }
    : view==='prenotazione' ? { t:'Dettaglio prenotazione', s: selBooking?selBooking.cliente:'' }
    : TITLES[view] || TITLES.dashboard;
  const showSearch = view==='catalogo';

  return (
    <div className={(darkTheme?'theme-dark ':'') + (vp.isMobile?'has-bottom-nav ':'')}
      style={{ display:'flex', height:'100vh', width:'100%', overflow:'hidden', background:'var(--bg)' }}>

      {/* SIDEBAR: solo su desktop/tablet */}
      {!vp.isMobile && (
        <Sidebar role={session} view={view} nav={(v)=>{ setSelected(null); nav(v); }} dark={sidebarDark} currentUser={currentUser} />
      )}

      {/* MOBILE DRAWER: sovrapposto quando aperto */}
      {vp.isMobile && (
        <MobileDrawer open={drawerOpen} onClose={()=>setDrawerOpen(false)}
          role={session} view={view}
          nav={(v)=>{ setSelected(null); nav(v); }}
          currentUser={currentUser} onLogout={logout}
          theme={theme} setTheme={isAdmin ? setTheme : null} />
      )}

      <div style={{ flex:1, display:'flex', flexDirection:'column', minWidth:0, overflow:'hidden' }}>
        {view!=='prodotto-editor' && view!=='prenotazione' && (
          vp.isMobile ? (
            <MobileHeader title={head.t} subtitle={head.s}
              onOpenDrawer={()=>setDrawerOpen(true)}
              search={catFilter?.search||''} setSearch={showSearch ? (q)=>setCatFilter(f=>({...(f||{}), search:q})) : null}
              currentUser={currentUser}
              onNavToPrefs={()=>setView('notifiche')} />
          ) : (
            <Header title={head.t} subtitle={head.s} role={session} onLogout={logout}
              search={catFilter?.search||''} setSearch={showSearch ? (q)=>setCatFilter(f=>({...(f||{}), search:q})) : null}
              theme={theme} setTheme={isAdmin ? setTheme : null} currentUser={currentUser}
              onNavToPrefs={()=>setView('notifiche')} />
          )
        )}

        {view==='dashboard' && <Dashboard role={session} nav={nav} openProduct={openProduct} setCatFilter={setCatFilter} attributi={attributi} products={products} currentUser={currentUser} />}
        {view==='catalogo' && <Catalogo role={session} openProduct={openProduct} onPrenota={onPrenota}
          search={catFilter?.search||''} catFilter={catFilter} setCatFilter={setCatFilter} attributi={attributi} products={products} />}
        {view==='prodotto' && selected && <ProductDetail p={selected} role={session} back={()=>{ setView('catalogo'); }} onPrenota={onPrenota} onPDF={onPDF} listino={listino} onStr={openStr} onStorico={openStorico} archive={archive} toast={toast} attributi={attributi} />}
        {view==='prenotazioni' && <Prenotazioni role={session} currentUser={currentUser} users={users} bookings={bookings} onPrenota={onPrenota} onView={openBooking} onEdit={editBooking} onAction={bookingAction} canFree={canFreeBooking} canConfirm={canConfirmBooking} toast={toast} />}
        {view==='noleggi' && <NoleggiInCorso role={session} archive={archive} setArchive={setArchive} products={products} setProducts={setProducts} attributi={attributi} toast={toast} onOpenBooking={(b)=>openBooking(b,'noleggi')} rentalExtensions={rentalExtensions} />}
        {view==='prenotazione' && selBooking && <BookingDetail booking={selBooking} role={session} products={products} zone={zone} listino={listino} clienteCat={clienteCat} coeff={usuraCoeff} allBookings={bookings} onBack={()=>{ setSelBooking(null); setView(bookingOrigin); }} backLabel={bookingOrigin==='archivio'?'Archivio':bookingOrigin==='noleggi'?'Noleggi':'Prenotazioni'} onEdit={editBooking} onContractData={(b)=>setModal({ type:'conferma', booking:b })} openProduct={openProduct} onAction={bookingAction} canFree={canFreeBooking}
          rentalExtensions={rentalExtensions.filter(e => e.archive_id === selBooking.id)}
          interruptionReasons={interruptionReasons}
          onExtendRental={(b)=>setModal({ type:'rental-extend', booking:b })}
          onInterruptRental={(b)=>setModal({ type:'rental-interrupt', booking:b })}
          onChangeStartDate={(b)=>setModal({ type:'rental-edit-start', booking:b })} />}
        {view==='archivio' && <Archivio role={session} currentUser={currentUser} archive={archive} onView={(b)=>openBooking(b,'archivio')} />}
        {view==='anagrafica' && <AnagraficaClienti clienti={clienti} setClienti={setClienti} zone={zone} clienteCat={clienteCat} toast={toast} role={session} setBookings={setBookings} setArchive={setArchive} />}
        {view==='notifiche' && <UserNotificationPrefs currentUser={currentUser} toast={toast} />}
        {view==='attivita' && <div className="scroll" style={{ flex:1, minWidth:0, overflowY:'auto', overflowX:'hidden', padding:'24px 30px 40px' }}><AdminLog /></div>}
        {view==='admin' && session==='admin' && <AdminConsole openProduct={openProduct} toast={toast} attributi={attributi} setAttributi={setAttributi} listino={listino} setListino={setListino} zone={zone} setZone={setZone} users={users} setUsers={setUsers} currentUser={currentUser} products={products} setProducts={setProducts}
          onNewProduct={()=>openEditor('new', null)} onEditProduct={(p)=>openEditor('edit', p)} onDuplicateProduct={(p)=>openEditor('duplicate', p)} onDeleteProduct={deleteProduct} tab={adminTab} setTab={setAdminTab} strListino={strListino} setStrListino={setStrListino}
          clienteCat={clienteCat} setClienteCat={setClienteCat} usuraCoeff={usuraCoeff} setUsuraCoeff={setUsuraCoeff}
          interruptionReasons={interruptionReasons} setInterruptionReasons={setInterruptionReasons} />}
        {view==='prodotto-editor' && session==='admin' && editor && <ProductEditor mode={editor.mode} source={editor.source} role={session} attributi={attributi} products={products} onCancel={()=>{ setEditor(null); setAdminTab('prodotti'); setView('admin'); }} onSave={saveProduct} onOpenExisting={openExistingProduct} toast={toast} onStr={openStr} />}
      </div>

      {/* BOTTOM NAV: solo mobile e solo se non siamo in editor/dettaglio prenotazione */}
      {vp.isMobile && view!=='prodotto-editor' && view!=='prenotazione' && (
        <BottomNav role={session} view={view} nav={(v)=>{ setSelected(null); nav(v); }}
          onOpenDrawer={()=>setDrawerOpen(true)} />
      )}

      {modal?.type==='booking' && <BookingModal product={modal.product} booking={modal.booking} role={session} currentUser={currentUser} users={users} products={products} zone={zone} listino={listino} clienteCat={clienteCat} coeff={usuraCoeff} clienti={clienti} setClienti={setClienti} onClose={()=>setModal(null)} onSave={saveBooking} toast={toast} />}
      {modal?.type==='pdf' && <PdfModal product={modal.product} withBattery={modal.withBattery} listino={listino} onClose={()=>setModal(null)} />}
      {modal?.type==='conferma' && <ConfermaModal booking={modal.booking} onClose={()=>setModal(null)} onSave={modal.booking.esito ? saveContractData : confirmBooking} />}
      {modal?.type==='str' && <StrListinoModal listino={strListino} onClose={()=>setModal(null)} />}
      {modal?.type==='storico' && <StoricoModal product={modal.product} archive={archive} bookings={bookings} clienteCat={clienteCat} onClose={()=>setModal(null)} />}
      {modal?.type==='rental-extend' && <RentalExtendModal
        booking={modal.booking}
        lastEndDate={modal.booking.dataRientro || modal.booking.fine}
        onClose={()=>setModal(null)}
        onSave={(ext) => extendRental(modal.booking, ext)} />}
      {modal?.type==='rental-interrupt' && <RentalInterruptModal
        booking={modal.booking}
        reasons={interruptionReasons}
        onClose={()=>setModal(null)}
        onSave={(data) => interruptRental(modal.booking, data)} />}
      {modal?.type==='rental-edit-start' && <RentalEditStartModal
        booking={modal.booking}
        onClose={()=>setModal(null)}
        onSave={(data) => changeStartDate(modal.booking, data.data_consegna)} />}
      <Toast msg={toastMsg} />
    </div>
  );
}

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