// Settings screen

const PREFS_KEY = 'velonics_prefs';
const PREFS_DEFAULT = {
  push: false, email: true, sms: false,
  notifyCritical: true, notifyWarning: true, notifyInfo: false,
  units: 'liters', tempUnits: 'c', lang: 'English',
  theme: 'dark', currency: '₹', rate: '7.50',
  timezone: 'Asia/Calcutta',
  fontSize: 'normal',
  avatarColor: 'cyan',
  themeAccent: 'aqua',
  darkBg: 'navy',
  lightBg: 'cloud',
  accentIntensity: 100,
  bgDepth: 100,
  cardOpacity: 50,
  glowStrength: 50,
  cornerRadius: 'rounded',
  textColor: '',
  customAccent: '',
};

const AVATAR_COLORS = {
  cyan:   'linear-gradient(135deg, #00d4ff, #00b894)',
  purple: 'linear-gradient(135deg, #a855f7, #7c3aed)',
  orange: 'linear-gradient(135deg, #ff6b35, #f59e0b)',
  green:  'linear-gradient(135deg, #00e676, #2d9b6f)',
  pink:   'linear-gradient(135deg, #ff4d8d, #c026d3)',
  indigo: 'linear-gradient(135deg, #6366f1, #3b82f6)',
};

const ACCENT_THEMES = [
  { id: 'aqua',   label: 'Aqua',   cyan: '#00d4ff', teal: '#00b894', glow1: 'rgba(0,212,255,0.10)',    glow2: 'rgba(0,184,148,0.08)',    glowRgb1: '0,212,255',   glowBase1: 0.10, glowRgb2: '0,184,148',   glowBase2: 0.08 },
  { id: 'forest', label: 'Forest', cyan: '#10b981', teal: '#059669', glow1: 'rgba(16,185,129,0.10)',   glow2: 'rgba(5,150,105,0.08)',    glowRgb1: '16,185,129',  glowBase1: 0.10, glowRgb2: '5,150,105',   glowBase2: 0.08 },
  { id: 'indigo', label: 'Indigo', cyan: '#6366f1', teal: '#8b5cf6', glow1: 'rgba(99,102,241,0.12)',   glow2: 'rgba(139,92,246,0.08)',   glowRgb1: '99,102,241',  glowBase1: 0.12, glowRgb2: '139,92,246',  glowBase2: 0.08 },
  { id: 'sunset', label: 'Sunset', cyan: '#f59e0b', teal: '#ef4444', glow1: 'rgba(245,158,11,0.12)',   glow2: 'rgba(239,68,68,0.08)',    glowRgb1: '245,158,11',  glowBase1: 0.12, glowRgb2: '239,68,68',   glowBase2: 0.08 },
  { id: 'slate',  label: 'Slate',  cyan: '#64748b', teal: '#94a3b8', glow1: 'rgba(100,116,139,0.08)',  glow2: 'rgba(148,163,184,0.05)',  glowRgb1: '100,116,139', glowBase1: 0.08, glowRgb2: '148,163,184', glowBase2: 0.05 },
  { id: 'royal',  label: 'Royal',  cyan: '#7c3aed', teal: '#ec4899', glow1: 'rgba(124,58,237,0.12)',   glow2: 'rgba(236,72,153,0.08)',   glowRgb1: '124,58,237',  glowBase1: 0.12, glowRgb2: '236,72,153',  glowBase2: 0.08 },
];

function _mixColor(hex, intensity) {
  const r = parseInt(hex.slice(1,3),16), g = parseInt(hex.slice(3,5),16), b = parseInt(hex.slice(5,7),16);
  let nr, ng, nb;
  if (intensity <= 1.0) {
    const grey = r*0.299 + g*0.587 + b*0.114;
    nr = r*intensity + grey*(1-intensity); ng = g*intensity + grey*(1-intensity); nb = b*intensity + grey*(1-intensity);
  } else {
    const ex = intensity-1.0; nr = r+(255-r)*ex; ng = g+(255-g)*ex; nb = b+(255-b)*ex;
  }
  return '#'+[nr,ng,nb].map(x=>Math.max(0,Math.min(255,Math.round(x))).toString(16).padStart(2,'0')).join('');
}

function _adjustHex(hex, factor) {
  const r = parseInt(hex.slice(1,3),16), g = parseInt(hex.slice(3,5),16), b = parseInt(hex.slice(5,7),16);
  return '#'+[r,g,b].map(x=>Math.max(0,Math.min(255,Math.round(x*factor))).toString(16).padStart(2,'0')).join('');
}

const CORNER_PRESETS = {
  sharp:   { card: '8px',  btn: '6px',  pill: '12px' },
  rounded: { card: '16px', btn: '12px', pill: '20px' },
  pill:    { card: '24px', btn: '18px', pill: '30px' },
};

function _applyCornerRadius(style) {
  const r = CORNER_PRESETS[style] || CORNER_PRESETS.rounded;
  const el = document.documentElement;
  el.style.setProperty('--radius-card', r.card);
  el.style.setProperty('--radius-btn',  r.btn);
  el.style.setProperty('--radius-pill', r.pill);
}

function _applyCardOpacity(value, isDark) {
  const v = value ?? 50;
  const el = document.documentElement;
  if (isDark) {
    const op  = +(0.02 + (v/100)*0.12).toFixed(3);
    const ops = +(Math.min(0.20, op*1.6)).toFixed(3);
    el.style.setProperty('--card',        `rgba(255,255,255,${op})`);
    el.style.setProperty('--card-strong', `rgba(255,255,255,${ops})`);
  } else {
    const op  = +(0.60 + (v/100)*0.38).toFixed(2);
    const ops = +(Math.min(0.99, op+0.15)).toFixed(2);
    el.style.setProperty('--card',        `rgba(255,255,255,${op})`);
    el.style.setProperty('--card-strong', `rgba(255,255,255,${ops})`);
  }
}

function _applyAccent(accentId, intensity, glowStrength, customAccent) {
  let cyanHex, tealHex, gr1, gb1, gr2, gb2;
  if (customAccent) {
    cyanHex = customAccent;
    tealHex = _adjustHex(customAccent, 0.78);
    const r = parseInt(customAccent.slice(1,3),16);
    const g = parseInt(customAccent.slice(3,5),16);
    const b = parseInt(customAccent.slice(5,7),16);
    gr1 = `${r},${g},${b}`; gb1 = 0.12; gr2 = gr1; gb2 = 0.09;
  } else {
    const t = ACCENT_THEMES.find(a => a.id === accentId) || ACCENT_THEMES[0];
    cyanHex = t.cyan; tealHex = t.teal;
    gr1 = t.glowRgb1; gb1 = t.glowBase1; gr2 = t.glowRgb2; gb2 = t.glowBase2;
  }
  const intF  = (intensity    ?? 100) / 100;
  const glowF = (glowStrength ?? 50)  / 50;
  const el = document.documentElement;
  el.style.setProperty('--cyan',   _mixColor(cyanHex, intF));
  el.style.setProperty('--teal',   _mixColor(tealHex, intF));
  el.style.setProperty('--glow-1', `rgba(${gr1},${Math.min(0.35, +(gb1*glowF).toFixed(3))})`);
  el.style.setProperty('--glow-2', `rgba(${gr2},${Math.min(0.25, +(gb2*glowF).toFixed(3))})`);
}

const DARK_BACKGROUNDS = [
  { id: 'navy',        label: 'Navy',     bg1: '#0a0e27', bg2: '#1a1f3a', bg3: '#0f1430', card: 'rgba(255,255,255,0.05)', cardStrong: 'rgba(255,255,255,0.08)', border: 'rgba(255,255,255,0.08)', borderStrong: 'rgba(255,255,255,0.14)' },
  { id: 'midnight',    label: 'Black',    bg1: '#000000', bg2: '#0d0d0d', bg3: '#050505', card: 'rgba(255,255,255,0.07)', cardStrong: 'rgba(255,255,255,0.11)', border: 'rgba(255,255,255,0.10)', borderStrong: 'rgba(255,255,255,0.16)' },
  { id: 'graphite',    label: 'Graphite', bg1: '#111827', bg2: '#1f2937', bg3: '#0f1624', card: 'rgba(255,255,255,0.05)', cardStrong: 'rgba(255,255,255,0.08)', border: 'rgba(255,255,255,0.08)', borderStrong: 'rgba(255,255,255,0.14)' },
  { id: 'deep-purple', label: 'Purple',   bg1: '#0d0b1e', bg2: '#1a1530', bg3: '#100e22', card: 'rgba(255,255,255,0.05)', cardStrong: 'rgba(255,255,255,0.08)', border: 'rgba(255,255,255,0.08)', borderStrong: 'rgba(255,255,255,0.14)' },
  { id: 'forest',      label: 'Forest',   bg1: '#0a1a0f', bg2: '#0f2318', bg3: '#081509', card: 'rgba(255,255,255,0.05)', cardStrong: 'rgba(255,255,255,0.08)', border: 'rgba(255,255,255,0.08)', borderStrong: 'rgba(255,255,255,0.14)' },
  { id: 'ocean',       label: 'Ocean',    bg1: '#03111f', bg2: '#071e35', bg3: '#021018', card: 'rgba(255,255,255,0.05)', cardStrong: 'rgba(255,255,255,0.08)', border: 'rgba(255,255,255,0.08)', borderStrong: 'rgba(255,255,255,0.14)' },
];

const LIGHT_BACKGROUNDS = [
  { id: 'cloud',    label: 'Cloud',    bg1: '#eef2fb', bg2: '#e4eaf4', bg3: '#f5f7ff', card: 'rgba(255,255,255,0.78)', cardStrong: 'rgba(255,255,255,0.95)', border: 'rgba(0,0,0,0.08)', borderStrong: 'rgba(0,0,0,0.15)' },
  { id: 'snow',     label: 'Snow',     bg1: '#f8fafc', bg2: '#f1f5f9', bg3: '#ffffff', card: 'rgba(255,255,255,0.85)', cardStrong: 'rgba(255,255,255,0.98)', border: 'rgba(0,0,0,0.07)', borderStrong: 'rgba(0,0,0,0.12)' },
  { id: 'warm',     label: 'Warm',     bg1: '#faf7f0', bg2: '#f5ede0', bg3: '#fffbf5', card: 'rgba(255,255,255,0.80)', cardStrong: 'rgba(255,255,255,0.95)', border: 'rgba(0,0,0,0.08)', borderStrong: 'rgba(0,0,0,0.14)' },
  { id: 'rose',     label: 'Rose',     bg1: '#fff0f3', bg2: '#fde8ed', bg3: '#fff5f7', card: 'rgba(255,255,255,0.80)', cardStrong: 'rgba(255,255,255,0.95)', border: 'rgba(0,0,0,0.08)', borderStrong: 'rgba(0,0,0,0.14)' },
  { id: 'sage',     label: 'Sage',     bg1: '#f0f7f4', bg2: '#e5f2ec', bg3: '#f5fbf8', card: 'rgba(255,255,255,0.80)', cardStrong: 'rgba(255,255,255,0.95)', border: 'rgba(0,0,0,0.08)', borderStrong: 'rgba(0,0,0,0.14)' },
  { id: 'lavender', label: 'Lavender', bg1: '#f3f0ff', bg2: '#ebe6ff', bg3: '#f8f6ff', card: 'rgba(255,255,255,0.82)', cardStrong: 'rgba(255,255,255,0.96)', border: 'rgba(0,0,0,0.08)', borderStrong: 'rgba(0,0,0,0.14)' },
];

const TEXT_PRESETS = [
  { id: '',        label: 'Auto',  color: null      },
  { id: '#ffffff', label: 'White', color: '#ffffff'  },
  { id: '#f5f5f5', label: 'Soft',  color: '#f5f5f5'  },
  { id: '#fef3c7', label: 'Warm',  color: '#fef3c7'  },
  { id: '#dbeafe', label: 'Cool',  color: '#dbeafe'  },
  { id: '#d1fae5', label: 'Mint',  color: '#d1fae5'  },
];

function _applyBackground(preset, depth, cardOpacity, isDark) {
  const f = (depth ?? 100) / 100;
  const el = document.documentElement;
  el.style.setProperty('--bg-1', _adjustHex(preset.bg1, f));
  el.style.setProperty('--bg-2', _adjustHex(preset.bg2, f));
  el.style.setProperty('--bg-3', _adjustHex(preset.bg3, f));
  el.style.setProperty('--border',        preset.border);
  el.style.setProperty('--border-strong', preset.borderStrong);
  _applyCardOpacity(cardOpacity, isDark ?? true);
}

function _applyTextColor(color) {
  if (color) {
    document.documentElement.style.setProperty('--text', color);
  } else {
    document.documentElement.style.removeProperty('--text');
  }
}

function _loadPrefs() {
  try { return { ...PREFS_DEFAULT, ...JSON.parse(localStorage.getItem(PREFS_KEY) || '{}') }; }
  catch { return { ...PREFS_DEFAULT }; }
}

const GROUPS_KEY_S = 'velonics_groups';

// Map of pref keys that are synced to cloud via PATCH /api/user/preferences
const _CLOUD_SIMPLE_PREFS = {
  notifyCritical: 'notifyCritical',
  notifyWarning:  'notifyWarning',
  notifyInfo:     'notifyInfo',
  units:          'units',
  tempUnits:      'tempUnits',
  currency:       'currency',
  rate:           'rate',
  lang:           'lang',
  theme:          'theme',
  fontSize:       'fontSize',
  avatarColor:    'avatarColor',
};

const Settings = ({ tanks, user, onLogout, refreshAlerts, navigate, onUpdateUser }) => {
  const [prefs, setPrefs] = useState(_loadPrefs);
  const [confirmLogout, setConfirmLogout] = useState(false);
  const [testPushState, setTestPushState] = useState('idle'); // 'idle'|'sending'|'ok'|'error'
  const [testPushMsg, setTestPushMsg]     = useState('');
  // Edit profile sheet
  const [showEditProfile, setShowEditProfile] = useState(false);
  const [editName,        setEditName]        = useState('');
  const [editPhone,       setEditPhone]       = useState('');
  const [editSaving,      setEditSaving]      = useState(false);
  // Change password sheet
  const [showChangePw, setShowChangePw] = useState(false);
  const [pwCurrent,    setPwCurrent]    = useState('');
  const [pwNew,        setPwNew]        = useState('');
  const [pwConfirm,    setPwConfirm]    = useState('');
  const [pwSaving,     setPwSaving]     = useState(false);
  const [pwError,      setPwError]      = useState('');
  const [groups, setGroups] = useState(() => {
    try { return JSON.parse(localStorage.getItem(GROUPS_KEY_S) || '[]'); } catch { return []; }
  });
  const [showTzModal,      setShowTzModal]      = useState(false);
  const [appVer,           setAppVer]           = useState('…');
  const [appBuildDate,     setAppBuildDate]     = useState('');
  const [appBuildTime,     setAppBuildTime]     = useState('');
  const [latestVer,        setLatestVer]        = useState(null);
  const [updateInstalling, setUpdateInstalling] = useState(false);

  useEffect(() => {
    API.get('/api/health')
      .then(h => {
        setAppVer(h.version  || '?');
        setAppBuildDate(h.buildDate || '');
        setAppBuildTime(h.buildTime || '');
        setLatestVer(h.version || '?');
      })
      .catch(() => {
        setAppVer('?');
        setLatestVer('?');
      });
  }, []);

  const installUpdate = useCallback(async () => {
    setUpdateInstalling(true);
    if ('serviceWorker' in navigator) {
      const regs = await navigator.serviceWorker.getRegistrations();
      await Promise.all(regs.map(r => r.unregister()));
    }
    if ('caches' in window) {
      const keys = await caches.keys();
      await Promise.all(keys.map(k => caches.delete(k)));
    }
    window.location.reload(true);
  }, []);

  const sendTestPush = useCallback(async () => {
    setTestPushState('sending');
    setTestPushMsg('');
    try {
      const res = await API.post('/api/push/test', {});
      if (res.sent > 0) {
        setTestPushState('ok');
        setTestPushMsg(`Sent to ${res.sent} device${res.sent > 1 ? 's' : ''} — check your notifications`);
      } else if (res.vapidFailed > 0) {
        setTestPushState('error');
        setTestPushMsg('VAPID key mismatch — toggle push OFF then ON again to re-subscribe');
      } else if (res.removed > 0) {
        setTestPushState('error');
        setTestPushMsg('Subscription expired — toggle push OFF then ON again');
      } else {
        setTestPushState('error');
        setTestPushMsg(res.diagnosis || 'Enable push notifications first');
      }
      // Backend always inserts a test alert — refresh the alerts list immediately
      refreshAlerts && refreshAlerts();
    } catch (e) {
      setTestPushState('error');
      setTestPushMsg('Server error — check backend is running');
    }
    setTimeout(() => setTestPushState('idle'), 6000);
  }, [refreshAlerts]);

  const set = useCallback((key, val) => {
    setPrefs(prev => {
      const next = { ...prev, [key]: val };
      try { localStorage.setItem(PREFS_KEY, JSON.stringify(next)); } catch {}
      return next;
    });
    if (key === 'push' && window.Push) {
      if (val) {
        Push.subscribe().catch(err => {
          setPrefs(prev => {
            const reverted = { ...prev, push: false };
            try { localStorage.setItem(PREFS_KEY, JSON.stringify(reverted)); } catch {}
            return reverted;
          });
          alert(err.message);
        });
      } else {
        Push.unsubscribe().catch(() => {});
      }
    }
    if (key === 'timezone' && window.API) {
      API.patch('/api/user/profile', { timezone: val }).catch(() => {});
    }
    if (key === 'themeAccent' && window.API) {
      API.patch('/api/user/preferences', { themeAccent: val }).catch(() => {});
    }
    if ((key === 'darkBg' || key === 'lightBg') && window.API) {
      API.patch('/api/user/preferences', { [key]: val }).catch(() => {});
    }
    if (['accentIntensity','bgDepth','cardOpacity','glowStrength','cornerRadius','textColor','customAccent'].includes(key) && window.API) {
      API.patch('/api/user/preferences', { [key]: val }).catch(() => {});
    }
    if (_CLOUD_SIMPLE_PREFS[key] && window.API) {
      API.patch('/api/user/preferences', { [_CLOUD_SIMPLE_PREFS[key]]: val }).catch(() => {});
    }
  }, []);

  // When the user logs in, pull their saved timezone from the DB (roams across devices).
  // Use setPrefs directly (not set()) to avoid triggering the redundant API write-back.
  useEffect(() => {
    if (!user?.timezone) return;
    setPrefs(prev => {
      if (prev.timezone === user.timezone) return prev;
      const next = { ...prev, timezone: user.timezone };
      try { localStorage.setItem(PREFS_KEY, JSON.stringify(next)); } catch {}
      return next;
    });
  }, [user]);

  // Expose globally so other screens can read units/currency/rate
  useEffect(() => { window.PREFS = prefs; }, [prefs]);

  // Sync groups count when returning from ManageGroups sub-screen
  useEffect(() => {
    const sync = () => setGroups(() => {
      try { return JSON.parse(localStorage.getItem(GROUPS_KEY_S) || '[]'); } catch { return []; }
    });
    window.addEventListener('popstate', sync);
    return () => window.removeEventListener('popstate', sync);
  }, []);

  // Apply theme to <html data-theme="...">; "system" follows OS preference
  useEffect(() => {
    const apply = (dark) => {
      document.documentElement.dataset.theme = dark ? 'dark' : 'light';
    };
    if (prefs.theme === 'system') {
      const mq = window.matchMedia('(prefers-color-scheme: dark)');
      apply(mq.matches);
      const handler = (e) => apply(e.matches);
      mq.addEventListener('change', handler);
      return () => mq.removeEventListener('change', handler);
    }
    apply(prefs.theme !== 'light');
  }, [prefs.theme]);

  // Apply font scale via CSS zoom on <body> — fixed elements (BottomNav, TopBar) stay
  // anchored to the real viewport; only scrollable body content scales.
  useEffect(() => {
    const zoomMap = { small: '0.88', normal: '1', large: '1.14', xl: '1.28' };
    document.documentElement.style.zoom = ''; // clear any legacy value from old pre-hydration script
    document.body.style.zoom = zoomMap[prefs.fontSize] || '1';
  }, [prefs.fontSize]);

  // Publish avatar gradient as a CSS variable so all avatar circles (incl. TopBar) react instantly
  useEffect(() => {
    document.documentElement.style.setProperty(
      '--avatar-gradient',
      AVATAR_COLORS[prefs.avatarColor] || AVATAR_COLORS.cyan
    );
  }, [prefs.avatarColor]);

  // Apply accent theme CSS variables whenever the preference changes
  useEffect(() => {
    _applyAccent(prefs.themeAccent || 'aqua', prefs.accentIntensity, prefs.glowStrength, prefs.customAccent);
  }, [prefs.themeAccent, prefs.accentIntensity, prefs.glowStrength, prefs.customAccent]);

  // Apply background preset — also re-runs when dark/light mode changes
  useEffect(() => {
    const applyBg = () => {
      const isDark = prefs.theme === 'dark' || (prefs.theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);
      const bgList = isDark ? DARK_BACKGROUNDS : LIGHT_BACKGROUNDS;
      const bgKey  = isDark ? (prefs.darkBg || 'navy') : (prefs.lightBg || 'cloud');
      const preset = bgList.find(b => b.id === bgKey) || bgList[0];
      _applyBackground(preset, prefs.bgDepth, prefs.cardOpacity, isDark);
    };
    applyBg();
    if (prefs.theme === 'system') {
      const mq = window.matchMedia('(prefers-color-scheme: dark)');
      mq.addEventListener('change', applyBg);
      return () => mq.removeEventListener('change', applyBg);
    }
  }, [prefs.darkBg, prefs.lightBg, prefs.theme, prefs.bgDepth, prefs.cardOpacity]);

  // Apply corner radius CSS variables
  useEffect(() => {
    _applyCornerRadius(prefs.cornerRadius || 'rounded');
  }, [prefs.cornerRadius]);

  // Apply text colour CSS variable
  useEffect(() => {
    _applyTextColor(prefs.textColor || '');
  }, [prefs.textColor]);

  // Load cloud-saved display prefs when user logs in (roams across devices)
  useEffect(() => {
    if (!user) return;
    API.get('/api/user/preferences').then(data => {
      setPrefs(prev => {
        let changed = false;
        const next = { ...prev };
        if (data.themeAccent && prev.themeAccent !== data.themeAccent)   { next.themeAccent = data.themeAccent; changed = true; }
        if (data.darkBg  && prev.darkBg  !== data.darkBg)               { next.darkBg  = data.darkBg;  changed = true; }
        if (data.lightBg && prev.lightBg !== data.lightBg)              { next.lightBg = data.lightBg; changed = true; }
        if (data.accentIntensity != null && prev.accentIntensity !== data.accentIntensity) { next.accentIntensity = data.accentIntensity; changed = true; }
        if (data.bgDepth      != null && prev.bgDepth      !== data.bgDepth)      { next.bgDepth      = data.bgDepth;      changed = true; }
        if (data.cardOpacity  != null && prev.cardOpacity  !== data.cardOpacity)  { next.cardOpacity  = data.cardOpacity;  changed = true; }
        if (data.glowStrength != null && prev.glowStrength !== data.glowStrength) { next.glowStrength = data.glowStrength; changed = true; }
        if (data.cornerRadius && prev.cornerRadius !== data.cornerRadius)         { next.cornerRadius = data.cornerRadius; changed = true; }
        if (data.textColor !== undefined && prev.textColor !== data.textColor)    { next.textColor = data.textColor || ''; changed = true; }
        if (data.customAccent !== undefined && prev.customAccent !== (data.customAccent||'')) { next.customAccent = data.customAccent || ''; changed = true; }
        if (data.notifyCritical != null && prev.notifyCritical !== data.notifyCritical) { next.notifyCritical = data.notifyCritical; changed = true; }
        if (data.notifyWarning  != null && prev.notifyWarning  !== data.notifyWarning)  { next.notifyWarning  = data.notifyWarning;  changed = true; }
        if (data.notifyInfo     != null && prev.notifyInfo     !== data.notifyInfo)     { next.notifyInfo     = data.notifyInfo;     changed = true; }
        if (data.units      && prev.units      !== data.units)      { next.units      = data.units;      changed = true; }
        if (data.tempUnits  && prev.tempUnits  !== data.tempUnits)  { next.tempUnits  = data.tempUnits;  changed = true; }
        if (data.currency   && prev.currency   !== data.currency)   { next.currency   = data.currency;   changed = true; }
        if (data.rate       && prev.rate       !== data.rate)       { next.rate       = data.rate;       changed = true; }
        if (data.lang       && prev.lang       !== data.lang)       { next.lang       = data.lang;       changed = true; }
        if (data.theme      && prev.theme      !== data.theme)      { next.theme      = data.theme;      changed = true; }
        if (data.fontSize   && prev.fontSize   !== data.fontSize)   { next.fontSize   = data.fontSize;   changed = true; }
        if (data.avatarColor && prev.avatarColor !== data.avatarColor) { next.avatarColor = data.avatarColor; changed = true; }
        if (!changed) return prev;
        try { localStorage.setItem(PREFS_KEY, JSON.stringify(next)); } catch {}
        return next;
      });
    }).catch(() => {});
  }, [user]);

  const openEditProfile = useCallback(() => {
    setEditName(user?.name || '');
    setEditPhone(user?.phone || '');
    setShowEditProfile(true);
  }, [user]);

  const saveProfile = useCallback(async () => {
    const name  = editName.trim();
    const phone = editPhone.trim();
    if (!name) return;
    setEditSaving(true);
    try {
      await API.patch('/api/user/profile', { name, phone });
      const initials = name.split(/\s+/).filter(Boolean).map(w => w[0]).join('').toUpperCase().slice(0, 2) || '?';
      onUpdateUser?.({ name, phone, initials });
      setShowEditProfile(false);
      window.__toast?.('Profile updated', { kind: 'success' });
    } catch {
      window.__toast?.('Failed to save — please try again', { kind: 'error' });
    }
    setEditSaving(false);
  }, [editName, editPhone, onUpdateUser]);

  const openChangePw = useCallback(() => {
    setPwCurrent(''); setPwNew(''); setPwConfirm(''); setPwError('');
    setShowChangePw(true);
  }, []);

  const changePassword = useCallback(async () => {
    if (pwNew !== pwConfirm) { setPwError('Passwords do not match'); return; }
    if (pwNew.length < 8)    { setPwError('New password must be at least 8 characters'); return; }
    setPwSaving(true); setPwError('');
    try {
      await API.post('/api/user/change-password', { currentPassword: pwCurrent, newPassword: pwNew });
      setShowChangePw(false);
      setPwCurrent(''); setPwNew(''); setPwConfirm('');
      window.__toast?.('Password changed successfully', { kind: 'success' });
    } catch (e) {
      const msg = e.message || '';
      setPwError(msg.toLowerCase().includes('incorrect') ? 'Current password is incorrect' : 'Something went wrong — please try again');
    }
    setPwSaving(false);
  }, [pwCurrent, pwNew, pwConfirm]);

  return (
    <div style={{padding: '8px 16px 100px'}}>
      <div style={{padding: '6px 4px 14px'}}>
        <div style={{fontSize: 22, fontWeight: 600}}>Settings</div>
        <div style={{fontSize: 13, color: 'var(--text-2)', marginTop: 2}}>Profile, preferences & system</div>
      </div>

      {/* Profile card */}
      <Card style={{padding: 16, marginBottom: 18, display: 'flex', alignItems: 'center', gap: 14}}>
        <div style={{
          width: 56, height: 56, borderRadius: '50%',
          background: 'var(--avatar-gradient, linear-gradient(135deg, var(--cyan), var(--teal)))',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          fontSize: 22, fontWeight: 600, color: '#0a0e27', flexShrink: 0,
        }}>{user ? user.initials : '?'}</div>
        <div style={{flex: 1, minWidth: 0}}>
          <div style={{fontSize: 16, fontWeight: 600}}>{user ? user.name : '—'}</div>
          <div style={{fontSize: 12, color: 'var(--text-2)'}}>{user ? user.email : ''}</div>
          {user?.phone && <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 1}}>{user.phone}</div>}
          <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 2}}>Member since {user?.joinedAt ? new Date(user.joinedAt * 1000).toLocaleDateString('en-IN', { month: 'short', year: 'numeric' }) : '—'}</div>
        </div>
        <Btn variant="secondary" icon="edit" size="sm" onClick={openEditProfile}>Edit</Btn>
      </Card>

      {/* Devices & Groups */}
      <SectionTitle>Devices & Groups</SectionTitle>
      <Card style={{padding: 4}}>
        <div onClick={() => navigate && navigate('/settings/devices')} style={{display: 'flex', alignItems: 'center', gap: 10, padding: '12px', cursor: 'pointer'}}>
          <div style={{width: 30, height: 30, borderRadius: 8, background: 'rgba(0,212,255,0.10)', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
            <Ic name="grid" size={14} color="var(--cyan)"/>
          </div>
          <div style={{flex: 1, fontSize: 14, fontWeight: 500}}>Manage Devices</div>
          <Ic name="chevronRight" size={16} color="var(--text-3)"/>
        </div>
        <Divider/>
        <div onClick={() => navigate && navigate('/settings/groups')} style={{display: 'flex', alignItems: 'center', gap: 10, padding: '12px', cursor: 'pointer'}}>
          <div style={{width: 30, height: 30, borderRadius: 8, background: 'rgba(0,212,255,0.10)', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
            <Ic name="layers" size={14} color="var(--cyan)"/>
          </div>
          <div style={{flex: 1, fontSize: 14, fontWeight: 500}}>Manage Groups</div>
          <div style={{fontSize: 11, color: 'var(--text-3)', marginRight: 4}}>
            {groups.length > 0 ? `${groups.length} group${groups.length > 1 ? 's' : ''}` : 'None'}
          </div>
          <Ic name="chevronRight" size={16} color="var(--text-3)"/>
        </div>
        <Divider/>
        <div onClick={() => navigate && navigate('/settings/sharing')} style={{display: 'flex', alignItems: 'center', gap: 10, padding: '12px', cursor: 'pointer'}}>
          <div style={{width: 30, height: 30, borderRadius: 8, background: 'rgba(0,212,255,0.10)', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
            <Ic name="users" size={14} color="var(--cyan)"/>
          </div>
          <div style={{flex: 1, fontSize: 14, fontWeight: 500}}>Device Sharing</div>
          <Ic name="chevronRight" size={16} color="var(--text-3)"/>
        </div>
      </Card>

      {/* Notifications */}
      <SectionTitle>Notifications</SectionTitle>
      <Card style={{padding: 4}}>
        <RowToggle label="Push notifications" hint="On this device" on={prefs.push} onChange={v => set('push', v)}/>
        {prefs.push && (
          <div style={{padding: '4px 12px 12px'}}>
            <Btn
              variant="ghost"
              icon={testPushState === 'sending' ? 'loader' : testPushState === 'ok' ? 'check' : 'bell'}
              size="sm"
              disabled={testPushState === 'sending'}
              onClick={sendTestPush}
              style={{width: '100%', justifyContent: 'center'}}
            >
              {testPushState === 'sending' ? 'Sending…' : testPushState === 'ok' ? 'Sent!' : 'Send test notification'}
            </Btn>
            {testPushMsg ? (
              <div style={{
                marginTop: 8, fontSize: 12, padding: '6px 10px', borderRadius: 8,
                background: testPushState === 'ok' ? 'rgba(0,200,83,0.12)' : 'rgba(255,82,82,0.12)',
                color: testPushState === 'ok' ? 'var(--green)' : 'var(--red)',
              }}>{testPushMsg}</div>
            ) : null}
          </div>
        )}
        <Divider/>
        <RowToggle label="Critical alerts" hint="Always recommended" on={prefs.notifyCritical} onChange={v => set('notifyCritical', v)} dotColor="var(--red)"/>
        <RowToggle label="Warning alerts" on={prefs.notifyWarning} onChange={v => set('notifyWarning', v)} dotColor="var(--amber)"/>
        <RowToggle label="Info alerts" on={prefs.notifyInfo} onChange={v => set('notifyInfo', v)} dotColor="var(--info)"/>
      </Card>

      {/* Display */}
      <SectionTitle>Display</SectionTitle>
      <Card style={{padding: 4}}>
        <div onClick={() => navigate && navigate('/settings/display')} style={{display: 'flex', alignItems: 'center', gap: 10, padding: '12px', cursor: 'pointer'}}>
          <div style={{width: 30, height: 30, borderRadius: 8, background: 'rgba(0,212,255,0.10)', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
            <Ic name="palette" size={14} color="var(--cyan)"/>
          </div>
          <div style={{flex: 1, fontSize: 14, fontWeight: 500}}>Display Preferences</div>
          <Ic name="chevronRight" size={16} color="var(--text-3)"/>
        </div>
      </Card>

      {/* Preferences */}
      <SectionTitle>Preferences</SectionTitle>
      <Card style={{padding: 14}}>
        <RowSelect label="Volume" right={<Segmented size="sm" options={[{value:'liters', label:'L'}, {value:'gallons', label:'Gal'}]} value={prefs.units} onChange={v => set('units', v)}/>}/>
        <Divider/>
        <RowSelect label="Temperature" right={<Segmented size="sm" options={[{value:'c', label:'°C'}, {value:'f', label:'°F'}]} value={prefs.tempUnits} onChange={v => set('tempUnits', v)}/>}/>
        <Divider/>
        <RowSelect label="Language" right={<DropSelect value={prefs.lang} onChange={v => set('lang', v)} options={['English','हिन्दी','தமிழ்','తెలుగు','বাংলা']}/>}/>
        <Divider/>
        <RowSelect label="Currency" right={<DropSelect value={prefs.currency} onChange={v => set('currency', v)} options={['₹','$','€','£']}/>}/>
        <Divider/>
        <RowSelect label="Time zone" right={
          <button onClick={() => setShowTzModal(true)} style={{
            display: 'flex', alignItems: 'center', gap: 6, maxWidth: 170, overflow: 'hidden',
            background: 'rgba(255,255,255,0.05)', border: '1px solid var(--border)',
            borderRadius: 10, padding: '6px 10px', color: 'var(--text)', fontSize: 13,
            cursor: 'pointer', fontFamily: 'inherit',
          }}>
            <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
              {(!prefs.timezone || prefs.timezone === 'auto')
                ? 'Auto-detect'
                : prefs.timezone.replace(/_/g, ' ')}
            </span>
            <Ic name="chevronRight" size={12} color="var(--text-2)" style={{ flexShrink: 0 }}/>
          </button>
        }/>
        <Divider/>
        <div style={{padding: '12px 4px'}}>
          <div style={{fontSize: 11, color: 'var(--text-2)', textTransform: 'uppercase', letterSpacing: 0.5, marginBottom: 6}}>Electricity rate</div>
          <TextInput icon="zap" value={prefs.rate} onChange={v => set('rate', v)} suffix={`${prefs.currency}/kWh`}/>
        </div>
      </Card>

      {showTzModal && (
        <TimezoneModal
          value={prefs.timezone || 'auto'}
          onChange={v => set('timezone', v)}
          onClose={() => setShowTzModal(false)}
        />
      )}

      {/* Account */}
      <SectionTitle>Account</SectionTitle>
      <Card style={{padding: 4}}>
        <div onClick={openChangePw} style={{display: 'flex', alignItems: 'center', gap: 10, padding: '12px', cursor: 'pointer'}}>
          <div style={{width: 30, height: 30, borderRadius: 8, background: 'rgba(0,212,255,0.10)', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
            <Ic name="shield" size={14} color="var(--cyan)"/>
          </div>
          <div style={{flex: 1, fontSize: 14, fontWeight: 500}}>Change Password</div>
          <Ic name="chevronRight" size={16} color="var(--text-3)"/>
        </div>
        <Divider/>
        <div onClick={() => setConfirmLogout(true)} style={{display: 'flex', alignItems: 'center', gap: 10, padding: '12px', cursor: 'pointer'}}>
          <div style={{width: 30, height: 30, borderRadius: 8, background: 'rgba(255,82,82,0.10)', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
            <Ic name="logout" size={14} color="var(--red)"/>
          </div>
          <div style={{flex: 1, fontSize: 14, fontWeight: 500, color: 'var(--red)'}}>Sign out</div>
          <Ic name="chevronRight" size={16} color="var(--text-3)"/>
        </div>
      </Card>

      {/* About */}
      <SectionTitle>About</SectionTitle>
      <Card style={{padding: 16}}>
        {/* App identity */}
        <div style={{display: 'flex', alignItems: 'center', gap: 12, marginBottom: 14}}>
          <div style={{
            width: 44, height: 44, borderRadius: 12,
            background: '#ffffff',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            boxShadow: '0 4px 10px rgba(0,0,0,0.12)',
          }}>
            <svg viewBox="0 0 48 48" width={30} height={30} fill="none">
              <circle cx="24" cy="24" r="19" stroke="#1D9E75" strokeWidth="0.75" fill="none" opacity="0.45"/>
              <line x1="24" y1="15" x2="24" y2="5" stroke="#1D9E75" strokeWidth="1"/>
              <line x1="31.79" y1="19.5" x2="40.45" y2="14.5" stroke="#1D9E75" strokeWidth="1"/>
              <line x1="31.79" y1="28.5" x2="40.45" y2="33.5" stroke="#1D9E75" strokeWidth="1"/>
              <line x1="24" y1="33" x2="24" y2="43" stroke="#1D9E75" strokeWidth="1"/>
              <line x1="16.21" y1="28.5" x2="7.55" y2="33.5" stroke="#1D9E75" strokeWidth="1"/>
              <line x1="16.21" y1="19.5" x2="7.55" y2="14.5" stroke="#1D9E75" strokeWidth="1"/>
              <circle cx="24" cy="24" r="9" fill="#1D9E75"/>
              <path d="M 26 20.54 A 4 4 0 1 1 22 20.54" stroke="white" strokeWidth="1.4" fill="none" strokeLinecap="round"/>
              <line x1="24" y1="18" x2="24" y2="22.5" stroke="white" strokeWidth="1.4" strokeLinecap="round"/>
              <circle cx="24" cy="5" r="3" fill="#185FA5"/>
              <circle cx="40.45" cy="14.5" r="3" fill="#D85A30"/>
              <circle cx="40.45" cy="33.5" r="3" fill="#7F77DD"/>
              <circle cx="24" cy="43" r="3" fill="#EF9F27"/>
              <circle cx="7.55" cy="33.5" r="3" fill="#D4537E"/>
              <circle cx="7.55" cy="14.5" r="3" fill="#639922"/>
            </svg>
          </div>
          <div>
            <div style={{fontSize: 14, fontWeight: 600}}>Velonics Hub</div>
            <div style={{fontSize: 11, color: 'var(--text-3)'}}>Unified IoT Control</div>
          </div>
        </div>

        {/* Version info rows */}
        <div style={{borderTop: '1px solid var(--border)', paddingTop: 12, marginBottom: 12, display: 'flex', flexDirection: 'column', gap: 10}}>
          <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center'}}>
            <span style={{fontSize: 13, color: 'var(--text-2)'}}>Installed version</span>
            <span style={{fontSize: 13, fontWeight: 600, fontFamily: 'monospace', color: 'var(--text)'}}>v{appVer}</span>
          </div>
          <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center'}}>
            <span style={{fontSize: 13, color: 'var(--text-2)'}}>Latest version</span>
            {latestVer === null
              ? <span style={{fontSize: 12, color: 'var(--text-3)'}}>Checking…</span>
              : latestVer === appVer
                ? <span style={{fontSize: 12, color: 'var(--green)', display:'flex', alignItems:'center', gap:4}}><Ic name="check" size={12} color="var(--green)"/> Up to date</span>
                : <span style={{fontSize: 13, fontWeight: 600, fontFamily: 'monospace', color: 'var(--amber)'}}>v{latestVer} — update available</span>
            }
          </div>
        </div>

        {/* Install Update button */}
        <button
          disabled={updateInstalling}
          onClick={installUpdate}
          style={{
            width: '100%', padding: '11px 0', borderRadius: 10,
            border: '1px solid ' + (latestVer && latestVer !== appVer ? 'rgba(255,184,0,0.5)' : 'rgba(0,212,255,0.35)'),
            background: latestVer && latestVer !== appVer ? 'rgba(255,184,0,0.10)' : 'rgba(0,212,255,0.08)',
            color: latestVer && latestVer !== appVer ? 'var(--amber)' : 'var(--cyan)',
            fontWeight: 600, fontSize: 13, cursor: updateInstalling ? 'wait' : 'pointer',
            display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
          }}>
          <Ic name="refresh" size={14}/>
          {updateInstalling ? 'Refreshing…' : (latestVer && latestVer !== appVer ? 'Update available — Install Now' : 'Refresh App')}
        </button>
      </Card>

      <Confirm
        open={confirmLogout}
        title="Sign out?"
        body="You will be returned to the login screen. Your preferences and tank data will be preserved."
        confirmLabel="Sign out"
        danger
        onCancel={() => setConfirmLogout(false)}
        onConfirm={() => { setConfirmLogout(false); onLogout && onLogout(); }}
      />

      {/* ── Edit Profile sheet ── */}
      {showEditProfile && ReactDOM.createPortal(
        <div style={{position:'fixed',inset:0,zIndex:1000,display:'flex',flexDirection:'column',justifyContent:'flex-end',background:'rgba(0,0,0,0.6)'}}
          onClick={e => { if (e.target === e.currentTarget) setShowEditProfile(false); }}>
          <div style={{background:'var(--bg-2,#1a1f3a)',borderRadius:'20px 20px 0 0',padding:'20px 16px 36px',borderTop:'1px solid var(--border)',maxHeight:'90vh',overflowY:'auto'}}>
            <div style={{fontWeight:700,fontSize:17,marginBottom:20}}>Edit Profile</div>

            {/* Avatar preview + colour picker */}
            <div style={{display:'flex',alignItems:'center',gap:16,marginBottom:20}}>
              <div style={{
                width:64,height:64,borderRadius:'50%',flexShrink:0,
                background:'var(--avatar-gradient,linear-gradient(135deg,#00d4ff,#00b894))',
                display:'flex',alignItems:'center',justifyContent:'center',
                fontSize:24,fontWeight:700,color:'#0a0e27',
              }}>
                {editName.trim().split(/\s+/).filter(Boolean).map(w=>w[0]).join('').toUpperCase().slice(0,2) || user?.initials || '?'}
              </div>
              <div style={{flex:1}}>
                <div style={{fontSize:12,color:'var(--text-2)',marginBottom:10}}>Avatar colour</div>
                <div style={{display:'flex',gap:10,flexWrap:'wrap'}}>
                  {Object.entries(AVATAR_COLORS).map(([key, grad]) => (
                    <button key={key} onClick={() => set('avatarColor', key)} style={{
                      width:30,height:30,borderRadius:'50%',border:'none',cursor:'pointer',
                      background:grad,
                      outline: prefs.avatarColor === key ? '3px solid var(--cyan)' : '3px solid transparent',
                      outlineOffset:2,transition:'outline 150ms',
                    }}/>
                  ))}
                </div>
              </div>
            </div>

            {/* Name */}
            <label style={{fontSize:13,color:'var(--text-2)',display:'block',marginBottom:6}}>Display name</label>
            <input
              value={editName} onChange={e => setEditName(e.target.value)}
              placeholder="Your name"
              style={{width:'100%',boxSizing:'border-box',padding:'11px 14px',borderRadius:12,
                background:'rgba(255,255,255,0.06)',border:'1px solid var(--border)',
                color:'var(--text)',fontSize:14,outline:'none',marginBottom:14,fontFamily:'inherit'}}/>

            {/* Phone */}
            <label style={{fontSize:13,color:'var(--text-2)',display:'block',marginBottom:6}}>Phone number <span style={{color:'var(--text-3)',fontSize:11}}>(optional)</span></label>
            <input
              value={editPhone} onChange={e => setEditPhone(e.target.value)}
              placeholder="+91 98765 43210" type="tel"
              style={{width:'100%',boxSizing:'border-box',padding:'11px 14px',borderRadius:12,
                background:'rgba(255,255,255,0.06)',border:'1px solid var(--border)',
                color:'var(--text)',fontSize:14,outline:'none',marginBottom:24,fontFamily:'inherit'}}/>

            <button onClick={saveProfile} disabled={editSaving || !editName.trim()} style={{
              width:'100%',padding:'14px 0',borderRadius:14,
              background:(!editSaving && editName.trim()) ? 'linear-gradient(90deg,var(--cyan),var(--teal))' : 'rgba(255,255,255,0.06)',
              border:'none',
              color:(!editSaving && editName.trim()) ? '#0a0e27' : 'var(--text-3)',
              fontWeight:700,fontSize:15,cursor:(!editSaving && editName.trim()) ? 'pointer' : 'not-allowed',
            }}>{editSaving ? 'Saving…' : 'Save Changes'}</button>
          </div>
        </div>,
        document.getElementById('modal-root')
      )}

      {/* ── Change Password sheet ── */}
      {showChangePw && ReactDOM.createPortal(
        <div style={{position:'fixed',inset:0,zIndex:1000,display:'flex',flexDirection:'column',justifyContent:'flex-end',background:'rgba(0,0,0,0.6)'}}
          onClick={e => { if (e.target === e.currentTarget) setShowChangePw(false); }}>
          <div style={{background:'var(--bg-2,#1a1f3a)',borderRadius:'20px 20px 0 0',padding:'20px 16px 36px',borderTop:'1px solid var(--border)'}}>
            <div style={{fontWeight:700,fontSize:17,marginBottom:20}}>Change Password</div>

            <label style={{fontSize:13,color:'var(--text-2)',display:'block',marginBottom:6}}>Current password</label>
            <input type="password" value={pwCurrent} onChange={e=>setPwCurrent(e.target.value)}
              style={{width:'100%',boxSizing:'border-box',padding:'11px 14px',borderRadius:12,
                background:'rgba(255,255,255,0.06)',border:'1px solid var(--border)',
                color:'var(--text)',fontSize:14,outline:'none',marginBottom:14,fontFamily:'inherit'}}/>

            <label style={{fontSize:13,color:'var(--text-2)',display:'block',marginBottom:6}}>New password</label>
            <input type="password" value={pwNew} onChange={e=>{setPwNew(e.target.value);setPwError('');}}
              style={{width:'100%',boxSizing:'border-box',padding:'11px 14px',borderRadius:12,
                background:'rgba(255,255,255,0.06)',border:`1px solid ${pwError?'var(--red)':'var(--border)'}`,
                color:'var(--text)',fontSize:14,outline:'none',marginBottom:14,fontFamily:'inherit'}}/>

            <label style={{fontSize:13,color:'var(--text-2)',display:'block',marginBottom:6}}>Confirm new password</label>
            <input type="password" value={pwConfirm} onChange={e=>{setPwConfirm(e.target.value);setPwError('');}}
              style={{width:'100%',boxSizing:'border-box',padding:'11px 14px',borderRadius:12,
                background:'rgba(255,255,255,0.06)',border:`1px solid ${pwError?'var(--red)':'var(--border)'}`,
                color:'var(--text)',fontSize:14,outline:'none',marginBottom: pwError ? 8 : 24,fontFamily:'inherit'}}/>

            {pwError && <div style={{fontSize:12,color:'var(--red)',marginBottom:16}}>{pwError}</div>}

            <button onClick={changePassword} disabled={pwSaving||!pwCurrent||!pwNew||!pwConfirm} style={{
              width:'100%',padding:'14px 0',borderRadius:14,
              background:(!pwSaving&&pwCurrent&&pwNew&&pwConfirm) ? 'linear-gradient(90deg,var(--cyan),var(--teal))' : 'rgba(255,255,255,0.06)',
              border:'none',
              color:(!pwSaving&&pwCurrent&&pwNew&&pwConfirm) ? '#0a0e27' : 'var(--text-3)',
              fontWeight:700,fontSize:15,cursor:(!pwSaving&&pwCurrent&&pwNew&&pwConfirm) ? 'pointer' : 'not-allowed',
            }}>{pwSaving ? 'Updating…' : 'Change Password'}</button>
          </div>
        </div>,
        document.getElementById('modal-root')
      )}
    </div>
  );
};

const TimezoneModal = ({ value, onChange, onClose }) => {
  const [search, setSearch] = useState('');

  const allZones = useMemo(() => {
    try { return Intl.supportedValuesOf('timeZone'); }
    catch { return ['UTC','Asia/Kolkata','Asia/Dubai','Asia/Singapore','Europe/London','America/New_York','America/Los_Angeles','Australia/Sydney']; }
  }, []);

  const filtered = useMemo(() => {
    const q = search.toLowerCase();
    if (!q) return allZones;
    return allZones.filter(z => z.toLowerCase().replace(/_/g, ' ').includes(q));
  }, [search, allZones]);

  const detectedTz = Intl.DateTimeFormat().resolvedOptions().timeZone;

  const rowStyle = (selected) => ({
    display: 'flex', alignItems: 'center', justifyContent: 'space-between',
    padding: '13px 16px', cursor: 'pointer',
    borderBottom: '1px solid var(--border)',
    background: selected ? 'rgba(0,212,255,0.10)' : 'var(--bg-1, #0a0e27)',
  });

  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 400, background: 'var(--bg-1, #0a0e27)', display: 'flex', flexDirection: 'column' }}>
      <div style={{ padding: '16px 16px 12px', borderBottom: '1px solid var(--border)', background: 'var(--bg-1, #0a0e27)', display: 'flex', alignItems: 'center', gap: 12 }}>
        <button onClick={onClose} style={{ background: 'transparent', border: 'none', color: 'var(--cyan)', fontSize: 14, fontWeight: 600, cursor: 'pointer', padding: 0, display: 'flex', alignItems: 'center', gap: 2 }}>
          <Ic name="chevronLeft" size={18}/> Back
        </button>
        <div style={{ fontSize: 16, fontWeight: 600 }}>Select Time Zone</div>
      </div>

      <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', background: 'var(--bg-1, #0a0e27)' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, background: 'rgba(255,255,255,0.06)', border: '1px solid var(--border)', borderRadius: 12, padding: '10px 14px' }}>
          <Ic name="search" size={15} color="var(--text-3)"/>
          <input
            type="text"
            placeholder="Search city or region…"
            value={search}
            onChange={e => setSearch(e.target.value)}
            autoFocus
            style={{ flex: 1, background: 'transparent', border: 'none', outline: 'none', color: 'var(--text)', fontSize: 14, fontFamily: 'inherit' }}
          />
          {search && (
            <button onClick={() => setSearch('')} style={{ background: 'transparent', border: 'none', color: 'var(--text-3)', cursor: 'pointer', padding: 0, display: 'flex' }}>
              <Ic name="x" size={15}/>
            </button>
          )}
        </div>
        <div style={{ fontSize: 11, color: 'var(--text-3)', marginTop: 8, paddingLeft: 2 }}>
          {filtered.length} time zone{filtered.length !== 1 ? 's' : ''}
        </div>
      </div>

      <div style={{ flex: 1, overflowY: 'auto' }}>
        <div onClick={() => { onChange('auto'); onClose(); }}
          style={{ ...rowStyle(value === 'auto'), borderBottom: '1px solid var(--border)' }}>
          <div>
            <div style={{ fontSize: 14, fontWeight: 500, color: value === 'auto' ? 'var(--cyan)' : 'var(--text)' }}>Auto-detect</div>
            <div style={{ fontSize: 11, color: 'var(--text-3)', marginTop: 2 }}>{detectedTz.replace(/_/g, ' ')}</div>
          </div>
          {value === 'auto' && <Ic name="check" size={16} color="var(--cyan)"/>}
        </div>

        {filtered.map(z => (
          <div key={z} onClick={() => { onChange(z); onClose(); }} style={rowStyle(value === z)}>
            <span style={{ fontSize: 14, color: value === z ? 'var(--cyan)' : 'var(--text)' }}>
              {z.replace(/_/g, ' ')}
            </span>
            {value === z && <Ic name="check" size={16} color="var(--cyan)"/>}
          </div>
        ))}

        {filtered.length === 0 && (
          <div style={{ textAlign: 'center', padding: '48px 20px', color: 'var(--text-3)', fontSize: 14 }}>
            No time zones match "{search}"
          </div>
        )}
      </div>
    </div>
  );
};

const Divider = () => <div style={{height: 1, background: 'var(--border)', margin: '2px 4px'}}/>;

const RowToggle = ({ label, hint, on, onChange, dotColor }) => (
  <div style={{display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '12px 12px'}}>
    <div style={{display: 'flex', alignItems: 'center', gap: 10}}>
      {dotColor && <span style={{width: 8, height: 8, borderRadius: '50%', background: dotColor}}/>}
      <div>
        <div style={{fontSize: 14, fontWeight: 500}}>{label}</div>
        {hint && <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 2}}>{hint}</div>}
      </div>
    </div>
    <Toggle on={on} onChange={onChange}/>
  </div>
);

const RowSelect = ({ label, right }) => (
  <div style={{display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '8px 4px'}}>
    <div style={{fontSize: 14, fontWeight: 500}}>{label}</div>
    {right}
  </div>
);

const DropSelect = ({ value, onChange, options }) => (
  <div style={{display: 'flex', alignItems: 'center', gap: 4, background: 'rgba(255,255,255,0.05)', border: '1px solid var(--border)', borderRadius: 10, padding: '4px 8px'}}>
    <select value={value} onChange={e=> onChange(e.target.value)} style={{
      background: 'transparent', border: 'none', outline: 'none', color: 'var(--text)',
      fontSize: 13, fontFamily: 'inherit', padding: '4px 0',
    }}>
      {options.map(o => <option key={o} value={o} style={{background: 'var(--bg-2)'}}>{o}</option>)}
    </select>
    <Ic name="chevronDown" size={12} color="var(--text-2)"/>
  </div>
);

window.Settings = Settings;

/* ============================================================
   DISPLAY PREFERENCES SUB-SCREEN
   ============================================================ */

const DisplayPreferences = ({ user, onBack }) => {
  const [prefs, setPrefs] = useState(_loadPrefs);

  const set = useCallback((key, val) => {
    setPrefs(prev => {
      const next = { ...prev, [key]: val };
      try { localStorage.setItem(PREFS_KEY, JSON.stringify(next)); } catch {}
      if (window.PREFS) window.PREFS = next;
      return next;
    });
    const cloudKeys = ['themeAccent','darkBg','lightBg','accentIntensity','bgDepth','cardOpacity','glowStrength','cornerRadius','textColor','customAccent'];
    if (cloudKeys.includes(key) && window.API) {
      API.patch('/api/user/preferences', { [key]: val }).catch(() => {});
    }
  }, []);

  // Theme mode
  useEffect(() => {
    const apply = (dark) => { document.documentElement.dataset.theme = dark ? 'dark' : 'light'; };
    if (prefs.theme === 'system') {
      const mq = window.matchMedia('(prefers-color-scheme: dark)');
      apply(mq.matches);
      const h = (e) => apply(e.matches);
      mq.addEventListener('change', h);
      return () => mq.removeEventListener('change', h);
    }
    apply(prefs.theme !== 'light');
  }, [prefs.theme]);

  // Font scale
  useEffect(() => {
    const zm = { small:'0.88', normal:'1', large:'1.14', xl:'1.28' };
    document.documentElement.style.zoom = '';
    document.body.style.zoom = zm[prefs.fontSize] || '1';
  }, [prefs.fontSize]);

  // Accent
  useEffect(() => {
    _applyAccent(prefs.themeAccent||'aqua', prefs.accentIntensity, prefs.glowStrength, prefs.customAccent);
  }, [prefs.themeAccent, prefs.accentIntensity, prefs.glowStrength, prefs.customAccent]);

  // Background + card opacity
  useEffect(() => {
    const applyBg = () => {
      const isDark = prefs.theme==='dark'||(prefs.theme==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);
      const bgList = isDark ? DARK_BACKGROUNDS : LIGHT_BACKGROUNDS;
      const bgKey  = isDark ? (prefs.darkBg||'navy') : (prefs.lightBg||'cloud');
      const preset = bgList.find(b=>b.id===bgKey)||bgList[0];
      _applyBackground(preset, prefs.bgDepth, prefs.cardOpacity, isDark);
    };
    applyBg();
    if (prefs.theme==='system') {
      const mq = window.matchMedia('(prefers-color-scheme: dark)');
      mq.addEventListener('change', applyBg);
      return () => mq.removeEventListener('change', applyBg);
    }
  }, [prefs.darkBg, prefs.lightBg, prefs.theme, prefs.bgDepth, prefs.cardOpacity]);

  // Corner radius
  useEffect(() => { _applyCornerRadius(prefs.cornerRadius||'rounded'); }, [prefs.cornerRadius]);

  // Text colour
  useEffect(() => { _applyTextColor(prefs.textColor||''); }, [prefs.textColor]);

  // Cloud load on mount
  useEffect(() => {
    if (!user) return;
    API.get('/api/user/preferences').then(data => {
      setPrefs(prev => {
        let changed = false;
        const next = { ...prev };
        const strFields = ['themeAccent','darkBg','lightBg','cornerRadius','customAccent'];
        strFields.forEach(k => {
          if (data[k] && prev[k] !== data[k]) { next[k] = data[k]; changed = true; }
        });
        if (data.textColor !== undefined && prev.textColor !== (data.textColor||'')) { next.textColor = data.textColor||''; changed = true; }
        const numFields = ['accentIntensity','bgDepth','cardOpacity','glowStrength'];
        numFields.forEach(k => {
          if (data[k] != null && prev[k] !== data[k]) { next[k] = data[k]; changed = true; }
        });
        if (!changed) return prev;
        try { localStorage.setItem(PREFS_KEY, JSON.stringify(next)); } catch {}
        return next;
      });
    }).catch(() => {});
  }, [user]);

  // Restore system defaults
  const DISPLAY_DEFAULTS = {
    themeAccent:'aqua', customAccent:'', darkBg:'navy', lightBg:'cloud',
    textColor:'', accentIntensity:100, bgDepth:100, cardOpacity:50, glowStrength:50, cornerRadius:'rounded',
  };
  const restoreDefaults = useCallback(() => {
    const restored = { ...prefs, ...DISPLAY_DEFAULTS };
    setPrefs(restored);
    try { localStorage.setItem(PREFS_KEY, JSON.stringify(restored)); } catch {}
    if (window.PREFS) window.PREFS = restored;
    _applyAccent('aqua', 100, 50, '');
    const isDark = prefs.theme==='dark'||(prefs.theme==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);
    const preset = isDark ? (DARK_BACKGROUNDS.find(b=>b.id==='navy')||DARK_BACKGROUNDS[0]) : (LIGHT_BACKGROUNDS.find(b=>b.id==='cloud')||LIGHT_BACKGROUNDS[0]);
    _applyBackground(preset, 100, 50, isDark);
    _applyTextColor('');
    _applyCornerRadius('rounded');
    if (window.API) API.patch('/api/user/preferences', DISPLAY_DEFAULTS).catch(() => {});
  }, [prefs]);

  // Shared tile container style (horizontal scroll row)
  const tileRow = { display:'flex', gap:8, overflowX:'auto', paddingBottom:6, WebkitOverflowScrolling:'touch' };

  // Current dark/light state (for bg section)
  const isDarkMode = prefs.theme==='dark'||(prefs.theme==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);
  const bgList  = isDarkMode ? DARK_BACKGROUNDS : LIGHT_BACKGROUNDS;
  const bgKey   = isDarkMode ? (prefs.darkBg||'navy') : (prefs.lightBg||'cloud');
  const bgPref  = isDarkMode ? 'darkBg' : 'lightBg';
  const restoreBg = () => _applyBackground(bgList.find(b=>b.id===bgKey)||bgList[0], prefs.bgDepth, prefs.cardOpacity, isDarkMode);

  return (
    <div style={{paddingBottom:100}}>
      {/* Header */}
      <div style={{display:'flex',alignItems:'center',gap:10,padding:'14px 16px 10px',position:'sticky',top:0,background:'var(--bg-1)',zIndex:10,borderBottom:'1px solid var(--border)'}}>
        <button onClick={onBack} style={{background:'none',border:'none',padding:'6px',borderRadius:8,color:'var(--text)',display:'flex',alignItems:'center',cursor:'pointer'}}>
          <Ic name="chevronLeft" size={20}/>
        </button>
        <div>
          <div style={{fontSize:18,fontWeight:700}}>Display</div>
          <div style={{fontSize:12,color:'var(--text-2)'}}>Theme, colours & layout</div>
        </div>
      </div>

      <div style={{padding:'12px 16px'}}>

        {/* ── Mode ── */}
        <SectionTitle>Mode</SectionTitle>
        <Card style={{padding:14}}>
          <RowSelect label="Appearance" right={
            <Segmented size="sm"
              options={[{value:'dark',label:'Dark'},{value:'light',label:'Light'},{value:'system',label:'Sys'}]}
              value={prefs.theme} onChange={v=>set('theme',v)}/>
          }/>
        </Card>

        {/* ── Accent Colour ── */}
        <SectionTitle>Accent Colour</SectionTitle>
        <Card style={{padding:14}}>
          <div style={tileRow}>
            {ACCENT_THEMES.map(t => {
              const active = !prefs.customAccent && (prefs.themeAccent||'aqua')===t.id;
              return (
                <button key={t.id}
                  onClick={() => { set('themeAccent',t.id); set('customAccent',''); }}
                  onMouseEnter={() => _applyAccent(t.id, prefs.accentIntensity, prefs.glowStrength, '')}
                  onMouseLeave={() => _applyAccent(prefs.themeAccent||'aqua', prefs.accentIntensity, prefs.glowStrength, prefs.customAccent)}
                  style={{
                    position:'relative',
                    flexShrink:0, width:52, padding:'8px 6px 7px',
                    borderRadius:12, cursor:'pointer',
                    border:`2px solid ${active?t.cyan:'transparent'}`,
                    background:active?t.glow1:'rgba(255,255,255,0.04)',
                    display:'flex', flexDirection:'column', alignItems:'center', gap:5,
                    transition:'border-color 150ms,background 150ms',
                  }}>
                  <div style={{width:'100%',height:24,borderRadius:6,background:`linear-gradient(135deg,${t.cyan},${t.teal})`,boxShadow:active?`0 2px 8px ${t.glow1}`:'none'}}/>
                  <div style={{fontSize:10,fontWeight:active?700:500,color:active?t.cyan:'var(--text-2)',whiteSpace:'nowrap'}}>{t.label}</div>
                  {active && <div style={{position:'absolute',top:4,right:4}}><Ic name="check" size={10} color={t.cyan}/></div>}
                </button>
              );
            })}
            {/* Custom accent tile */}
            {(() => {
              const active = !!prefs.customAccent;
              const cc = prefs.customAccent || '#00d4ff';
              return (
                <div style={{position:'relative',flexShrink:0,width:52,display:'flex',flexDirection:'column',alignItems:'center',gap:5,padding:'8px 6px 7px',borderRadius:12,border:`2px solid ${active?'var(--cyan)':'var(--border)'}`,background:active?'rgba(0,212,255,0.08)':'rgba(255,255,255,0.04)'}}>
                  <div style={{width:'100%',height:24,borderRadius:6,background:cc,position:'relative',overflow:'hidden'}}>
                    <input type="color" value={cc} onChange={e=>{set('customAccent',e.target.value);}}
                      style={{position:'absolute',inset:0,width:'100%',height:'100%',opacity:0,cursor:'pointer',border:'none',padding:0}}/>
                  </div>
                  <div style={{fontSize:10,fontWeight:active?700:500,color:active?'var(--cyan)':'var(--text-2)'}}>Custom</div>
                  {active && <div style={{position:'absolute',top:4,right:4}}><Ic name="check" size={10} color="var(--cyan)"/></div>}
                </div>
              );
            })()}
          </div>
          {prefs.customAccent && (
            <button onClick={() => set('customAccent','')} style={{marginTop:10,width:'100%',padding:'7px',borderRadius:8,border:'1px solid var(--border)',background:'none',color:'var(--text-2)',fontSize:12,cursor:'pointer'}}>
              Reset to preset
            </button>
          )}
        </Card>

        {/* ── Background ── */}
        <SectionTitle>Background</SectionTitle>
        <Card style={{padding:14}}>
          <div style={tileRow}>
            {bgList.map(b => {
              const active = bgKey===b.id;
              return (
                <button key={b.id}
                  onClick={() => set(bgPref,b.id)}
                  onMouseEnter={() => _applyBackground(b, prefs.bgDepth, prefs.cardOpacity, isDarkMode)}
                  onMouseLeave={restoreBg}
                  style={{
                    position:'relative',
                    flexShrink:0, width:52, padding:'8px 6px 7px',
                    borderRadius:12, cursor:'pointer',
                    border:`2px solid ${active?'var(--cyan)':'transparent'}`,
                    background:active?'rgba(255,255,255,0.06)':'rgba(255,255,255,0.03)',
                    display:'flex', flexDirection:'column', alignItems:'center', gap:5,
                    transition:'border-color 150ms',
                  }}>
                  <div style={{
                    width:'100%', height:24, borderRadius:6, overflow:'hidden',
                    background:`linear-gradient(160deg,${b.bg1} 0%,${b.bg2} 100%)`,
                    border:'1px solid rgba(255,255,255,0.12)',
                    display:'flex', alignItems:'flex-end', padding:3,
                  }}>
                    <div style={{width:'60%',height:6,borderRadius:3,background:b.card}}/>
                  </div>
                  <div style={{fontSize:10,fontWeight:active?700:500,color:active?'var(--cyan)':'var(--text-2)',whiteSpace:'nowrap'}}>{b.label}</div>
                  {active && <div style={{position:'absolute',top:4,right:4}}><Ic name="check" size={10} color="var(--cyan)"/></div>}
                </button>
              );
            })}
          </div>
        </Card>

        {/* ── Font Colour ── */}
        <SectionTitle>Font Colour</SectionTitle>
        <Card style={{padding:14}}>
          <div style={tileRow}>
            {TEXT_PRESETS.map(preset => {
              const active = (prefs.textColor||'')===preset.id;
              return (
                <button key={preset.id}
                  onClick={() => set('textColor',preset.id)}
                  style={{
                    position:'relative',
                    flexShrink:0, width:52, padding:'8px 6px 7px',
                    borderRadius:12, cursor:'pointer',
                    border:`2px solid ${active?'var(--cyan)':'transparent'}`,
                    background:active?'rgba(0,212,255,0.08)':'rgba(255,255,255,0.04)',
                    display:'flex', flexDirection:'column', alignItems:'center', gap:5,
                    transition:'border-color 150ms,background 150ms',
                  }}>
                  <div style={{
                    width:24,height:24,borderRadius:'50%',
                    background: preset.color || 'linear-gradient(135deg,var(--text-3),var(--text-2))',
                    border:'1px solid rgba(255,255,255,0.15)',
                    display:'flex',alignItems:'center',justifyContent:'center',
                  }}>
                    {!preset.color && <span style={{fontSize:11,fontWeight:700,color:'var(--text)'}}>A</span>}
                  </div>
                  <div style={{fontSize:10,fontWeight:active?700:500,color:active?'var(--cyan)':'var(--text-2)',whiteSpace:'nowrap'}}>{preset.label}</div>
                  {active && <div style={{position:'absolute',top:4,right:4}}><Ic name="check" size={10} color="var(--cyan)"/></div>}
                </button>
              );
            })}
            {/* Custom font colour tile */}
            {(() => {
              const isCustom = prefs.textColor && !TEXT_PRESETS.find(p=>p.id===prefs.textColor&&p.id!=='');
              const cc = isCustom ? prefs.textColor : '#ffffff';
              return (
                <div style={{position:'relative',flexShrink:0,width:52,display:'flex',flexDirection:'column',alignItems:'center',gap:5,padding:'8px 6px 7px',borderRadius:12,border:`2px solid ${isCustom?'var(--cyan)':'var(--border)'}`,background:isCustom?'rgba(0,212,255,0.08)':'rgba(255,255,255,0.04)'}}>
                  <div style={{width:24,height:24,borderRadius:'50%',background:cc,border:'1px solid rgba(255,255,255,0.2)',position:'relative',overflow:'hidden'}}>
                    <input type="color" value={cc} onChange={e=>set('textColor',e.target.value)}
                      style={{position:'absolute',inset:0,width:'100%',height:'100%',opacity:0,cursor:'pointer',border:'none',padding:0}}/>
                  </div>
                  <div style={{fontSize:10,fontWeight:isCustom?700:500,color:isCustom?'var(--cyan)':'var(--text-2)'}}>Custom</div>
                  {isCustom && <div style={{position:'absolute',top:4,right:4}}><Ic name="check" size={10} color="var(--cyan)"/></div>}
                </div>
              );
            })()}
          </div>
          {prefs.textColor && (
            <button onClick={() => set('textColor','')} style={{marginTop:10,width:'100%',padding:'7px',borderRadius:8,border:'1px solid var(--border)',background:'none',color:'var(--text-2)',fontSize:12,cursor:'pointer'}}>
              Reset to Auto
            </button>
          )}
        </Card>

        {/* ── Fine-tune (4 sliders, no Corner Radius) ── */}
        <SectionTitle>Fine-tune</SectionTitle>
        <Card style={{padding:14}}>
          {[
            {key:'accentIntensity', label:'Accent Intensity', min:60,  max:140, left:'Muted',  right:'Vivid',   fmt: v=>`${v}%`},
            {key:'bgDepth',         label:'Background Depth', min:75,  max:125, left:'Darker', right:'Lighter', fmt: v=>`${v}%`},
            {key:'cardOpacity',     label:'Card Opacity',     min:0,   max:100, left:'Flat',   right:'Frosted', fmt: v=>`${v}%`},
            {key:'glowStrength',    label:'Glow Strength',    min:0,   max:100, left:'None',   right:'Strong',  fmt: v=>`${v}%`},
          ].map(({key,label,min,max,left,right,fmt},idx) => (
            <div key={key} style={{marginBottom: idx<3 ? 18 : 0}}>
              <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:8}}>
                <span style={{fontSize:13,fontWeight:500,color:'var(--text)'}}>{label}</span>
                <span style={{fontSize:12,color:'var(--cyan)',fontWeight:600,fontFamily:'monospace',minWidth:40,textAlign:'right'}}>{fmt(prefs[key])}</span>
              </div>
              <input type="range" min={min} max={max} step={1} value={prefs[key]}
                onChange={e=>set(key,parseInt(e.target.value))} style={{width:'100%'}}/>
              <div style={{display:'flex',justifyContent:'space-between',marginTop:4}}>
                <span style={{fontSize:10,color:'var(--text-3)'}}>{left}</span>
                <span style={{fontSize:10,color:'var(--text-3)'}}>{right}</span>
              </div>
            </div>
          ))}
        </Card>

        {/* ── Text Size ── */}
        <SectionTitle>Text Size</SectionTitle>
        <Card style={{padding:14}}>
          <div style={{display:'flex',gap:8,justifyContent:'center'}}>
            {[{value:'small',label:'A',fs:11},{value:'normal',label:'A',fs:15},{value:'large',label:'A',fs:20},{value:'xl',label:'A',fs:25}].map(({value,label,fs}) => (
              <button key={value} onClick={()=>set('fontSize',value)} style={{
                width:56,height:44,borderRadius:10,
                background:prefs.fontSize===value?'rgba(0,212,255,0.15)':'rgba(255,255,255,0.05)',
                border:`1px solid ${prefs.fontSize===value?'var(--cyan)':'var(--border)'}`,
                color:prefs.fontSize===value?'var(--cyan)':'var(--text-2)',
                fontSize:fs,fontWeight:700,cursor:'pointer',
                display:'flex',alignItems:'center',justifyContent:'center',
                lineHeight:1,padding:0,
              }}>{label}</button>
            ))}
          </div>
        </Card>

        {/* ── Restore Defaults ── */}
        <div style={{marginTop:24}}>
          <button onClick={restoreDefaults} style={{
            width:'100%',padding:'13px',borderRadius:12,
            border:'1px solid rgba(255,82,82,0.35)',
            background:'rgba(255,82,82,0.08)',
            color:'var(--red)',fontWeight:600,fontSize:14,cursor:'pointer',
            display:'flex',alignItems:'center',justifyContent:'center',gap:8,
          }}>
            <Ic name="refresh" size={16} color="var(--red)"/>
            Restore System Default
          </button>
        </div>

      </div>
    </div>
  );
};
window.DisplayPreferences = DisplayPreferences;

/* ============================================================
   MANAGE GROUPS SUB-SCREEN
   ============================================================ */

const ManageGroups = ({ onBack }) => {
  const [groups,       setGroups]       = useState(() => {
    try { return JSON.parse(localStorage.getItem(GROUPS_KEY_S) || '[]'); } catch { return []; }
  });
  const [newGroupName, setNewGroupName] = useState('');

  const addGroup = useCallback(() => {
    const name = newGroupName.trim();
    if (!name) return;
    setGroups(prev => {
      const next = [...prev, { id: 'g_' + Date.now(), name }];
      try { localStorage.setItem(GROUPS_KEY_S, JSON.stringify(next)); } catch {}
      window.GROUPS = next;
      if (window.API) API.patch('/api/user/preferences', { groups: next }).catch(() => {});
      return next;
    });
    setNewGroupName('');
  }, [newGroupName]);

  const deleteGroup = useCallback((id) => {
    setGroups(prev => {
      const next = prev.filter(g => g.id !== id);
      try { localStorage.setItem(GROUPS_KEY_S, JSON.stringify(next)); } catch {}
      window.GROUPS = next;
      if (window.API) API.patch('/api/user/preferences', { groups: next }).catch(() => {});
      return next;
    });
    try {
      const dg = JSON.parse(localStorage.getItem('velonics_device_groups') || '{}');
      Object.keys(dg).forEach(k => { dg[k] = dg[k].filter(gid => gid !== id); });
      localStorage.setItem('velonics_device_groups', JSON.stringify(dg));
      if (window.API) API.patch('/api/user/preferences', { deviceGroups: dg }).catch(() => {});
    } catch {}
  }, []);

  return (
    <div>
      <div style={{
        position: 'sticky', top: 56, zIndex: 10,
        background: 'rgba(10,14,39,0.86)', backdropFilter: 'blur(14px)',
        borderBottom: '1px solid var(--border)',
        padding: '12px 14px', display: 'flex', alignItems: 'center', gap: 10,
      }}>
        <button onClick={onBack} style={{
          background: 'rgba(255,255,255,0.06)', border: '1px solid var(--border)',
          borderRadius: 10, width: 34, height: 34,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          color: '#fff', cursor: 'pointer',
        }}>
          <Ic name="chevronLeft" size={18}/>
        </button>
        <div style={{flex: 1}}>
          <div style={{fontSize: 15, fontWeight: 600}}>Manage Groups</div>
          <div style={{fontSize: 11, color: 'var(--text-3)'}}>Create groups to organise your devices</div>
        </div>
      </div>

      <div style={{padding: '14px 16px 100px'}}>
        <Card style={{padding: 14}}>
          {groups.length === 0 && (
            <div style={{fontSize: 13, color: 'var(--text-3)', paddingBottom: 12}}>
              No groups yet. Create one to organise your devices on the dashboard.
            </div>
          )}
          {groups.map((g, i) => (
            <div key={g.id} style={{
              display: 'flex', alignItems: 'center', gap: 10,
              paddingBottom: 10, marginBottom: 10,
              borderBottom: i < groups.length - 1 ? '1px solid var(--border)' : 'none',
            }}>
              <div style={{width: 28, height: 28, borderRadius: 8, background: 'rgba(0,212,255,0.10)', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
                <Ic name="tag" size={13} color="var(--cyan)"/>
              </div>
              <div style={{flex: 1, fontSize: 14, fontWeight: 500}}>{g.name}</div>
              <button onClick={() => deleteGroup(g.id)} style={{
                background: 'transparent', border: 'none', padding: 4,
                cursor: 'pointer', display: 'flex', alignItems: 'center',
              }}>
                <Ic name="trash" size={15} color="var(--red)"/>
              </button>
            </div>
          ))}
          <div style={{display: 'flex', gap: 8, marginTop: groups.length > 0 ? 8 : 0}}>
            <input
              value={newGroupName}
              onChange={e => setNewGroupName(e.target.value)}
              onKeyDown={e => e.key === 'Enter' && addGroup()}
              placeholder="Group name (e.g. Home, Farm…)"
              style={{
                flex: 1, background: 'rgba(255,255,255,0.05)',
                border: '1px solid var(--border)', borderRadius: 10,
                padding: '8px 12px', color: 'var(--text)', fontSize: 13, outline: 'none',
              }}
            />
            <button onClick={addGroup} disabled={!newGroupName.trim()} style={{
              padding: '8px 14px', borderRadius: 10,
              background: newGroupName.trim() ? 'var(--cyan)' : 'rgba(255,255,255,0.06)',
              border: 'none', color: newGroupName.trim() ? '#0a0e27' : 'var(--text-3)',
              fontWeight: 600, fontSize: 13, cursor: newGroupName.trim() ? 'pointer' : 'default',
            }}>Add</button>
          </div>
        </Card>
      </div>
    </div>
  );
};

window.ManageGroups = ManageGroups;

/* ============================================================
   MANAGE SHARING SUB-SCREEN
   ============================================================ */

const ROLE_COLORS = { viewer: 'var(--text-3)', operator: 'var(--amber)', admin: 'var(--cyan)' };
const ROLE_DESC   = {
  viewer:   'View live data and history only',
  operator: 'Also control motor, valves, flush',
  admin:    'Also change setpoints and rename',
};

const ManageSharing = ({ tanks, onBack }) => {
  const owned       = (tanks || []).filter(t => !t.sharedBy);
  const sharedWithMe = (tanks || []).filter(t =>  t.sharedBy);

  const [expanded,  setExpanded]  = useState(null);  // tank.id currently expanded
  const [shares,    setShares]    = useState({});     // { [tankId]: share[] }
  const [loadingId, setLoadingId] = useState(null);
  const [showSheet, setShowSheet] = useState(null);   // tank.id for the share bottom sheet
  const [email,     setEmail]     = useState('');
  const [role,      setRole]      = useState('viewer');
  const [sharing,   setSharing]   = useState(false);
  const [shareErr,  setShareErr]  = useState('');

  const toggle = useCallback(async (tank) => {
    if (expanded === tank.id) { setExpanded(null); return; }
    setExpanded(tank.id);
    if (shares[tank.id] !== undefined) return;
    setLoadingId(tank.id);
    try {
      const data = await API.get(`/api/tanks/${tank.id}/shares`);
      setShares(prev => ({ ...prev, [tank.id]: data }));
    } catch {}
    setLoadingId(null);
  }, [expanded, shares]);

  const doRoleChange = async (tankId, shareId, newRole) => {
    try {
      await API.put(`/api/tanks/${tankId}/shares/${shareId}`, { role: newRole });
      setShares(prev => ({
        ...prev,
        [tankId]: prev[tankId].map(s => s.id === shareId ? { ...s, role: newRole } : s),
      }));
    } catch { window.__toast?.('Failed to update role', { kind: 'error' }); }
  };

  const doRevoke = async (tankId, shareId) => {
    try {
      await API.del(`/api/tanks/${tankId}/shares/${shareId}`);
      setShares(prev => ({ ...prev, [tankId]: prev[tankId].filter(s => s.id !== shareId) }));
      window.__toast?.('Access revoked', { kind: 'info' });
    } catch { window.__toast?.('Failed to revoke — please try again', { kind: 'error' }); }
  };

  const openSheet = (tankId) => {
    setShowSheet(tankId); setEmail(''); setRole('viewer'); setShareErr('');
  };

  const doShare = async () => {
    if (!email.trim() || !showSheet) return;
    setSharing(true); setShareErr('');
    try {
      const r = await API.post(`/api/tanks/${showSheet}/shares`, { email: email.trim(), role });
      const newShare = { id: r.shareId, email: email.trim(), name: null, role, pending: r.pending };
      setShares(prev => ({ ...prev, [showSheet]: [...(prev[showSheet] || []), newShare] }));
      setShowSheet(null);
      window.__toast?.(r.pending
        ? `Invite sent — ${email.trim()} will get access when they register`
        : 'Device shared successfully',
        { kind: r.pending ? 'info' : 'success' });
    } catch (e) {
      const msg = e.message || '';
      setShareErr(msg.includes('409') ? 'Already shared with this user'
                : msg.includes('yourself') ? 'Cannot share with yourself'
                : 'Something went wrong — please try again');
    }
    setSharing(false);
  };

  const shareCount = (tankId) => {
    const list = shares[tankId];
    if (!list) return 'Tap to manage';
    return list.length === 0 ? 'Not shared' : `${list.length} ${list.length === 1 ? 'person' : 'people'}`;
  };

  return (
    <div>
      {/* Sticky header */}
      <div style={{
        position: 'sticky', top: 56, zIndex: 10,
        background: 'rgba(10,14,39,0.86)', backdropFilter: 'blur(14px)',
        borderBottom: '1px solid var(--border)',
        padding: '12px 14px', display: 'flex', alignItems: 'center', gap: 10,
      }}>
        <button onClick={onBack} style={{
          background: 'rgba(255,255,255,0.06)', border: '1px solid var(--border)',
          borderRadius: 10, width: 34, height: 34,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          color: '#fff', cursor: 'pointer',
        }}>
          <Ic name="chevronLeft" size={18}/>
        </button>
        <div style={{flex: 1}}>
          <div style={{fontSize: 15, fontWeight: 600}}>Device Sharing</div>
          <div style={{fontSize: 11, color: 'var(--text-3)'}}>Manage who can access your devices</div>
        </div>
      </div>

      <div style={{padding: '14px 16px 100px'}}>

        {/* Devices you own */}
        {owned.length > 0 && (
          <>
            <div style={{fontSize: 11, fontWeight: 700, color: 'var(--text-3)', letterSpacing: 0.8, textTransform: 'uppercase', marginBottom: 8, paddingLeft: 2}}>Your Devices</div>
            <Card style={{padding: 0, overflow: 'hidden', marginBottom: 20}}>
              {owned.map((tank, i) => {
                const isExpanded = expanded === tank.id;
                const shareList  = shares[tank.id] || [];
                const isLoading  = loadingId === tank.id;
                return (
                  <div key={tank.id} style={{borderTop: i > 0 ? '1px solid var(--border)' : 'none'}}>
                    {/* Device row */}
                    <div onClick={() => toggle(tank)} style={{display: 'flex', alignItems: 'center', gap: 12, padding: '14px 16px', cursor: 'pointer'}}>
                      <div style={{width: 34, height: 34, borderRadius: 10, background: 'rgba(0,212,255,0.10)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0}}>
                        <Ic name="grid" size={16} color="var(--cyan)"/>
                      </div>
                      <div style={{flex: 1, minWidth: 0}}>
                        <div style={{fontSize: 14, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap'}}>{tank.name}</div>
                        <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 1}}>
                          {isLoading ? 'Loading…' : shareCount(tank.id)}
                        </div>
                      </div>
                      <Ic name={isExpanded ? 'chevUp' : 'chevronDown'} size={16} color="var(--text-3)"/>
                    </div>

                    {/* Expanded share list */}
                    {isExpanded && (
                      <div style={{borderTop: '1px solid var(--border)', background: 'rgba(255,255,255,0.02)'}}>
                        {shareList.length === 0 && (
                          <div style={{padding: '12px 16px', fontSize: 13, color: 'var(--text-3)'}}>Not shared with anyone yet.</div>
                        )}
                        {shareList.map((s, idx) => (
                          <div key={s.id} style={{
                            display: 'flex', alignItems: 'center', gap: 12,
                            padding: '10px 16px',
                            borderTop: idx > 0 ? '1px solid rgba(255,255,255,0.04)' : 'none',
                          }}>
                            <div style={{
                              width: 32, height: 32, borderRadius: '50%', flexShrink: 0,
                              background: 'rgba(0,188,212,0.15)',
                              display: 'flex', alignItems: 'center', justifyContent: 'center',
                              fontWeight: 700, fontSize: 13, color: 'var(--cyan)',
                            }}>
                              {(s.name || s.email || '?')[0].toUpperCase()}
                            </div>
                            <div style={{flex: 1, minWidth: 0}}>
                              <div style={{fontWeight: 600, fontSize: 13, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap'}}>{s.name || s.email}</div>
                              {s.name && <div style={{fontSize: 11, color: 'var(--text-3)'}}>{s.email}</div>}
                              {s.pending && <div style={{fontSize: 11, color: 'var(--amber)'}}>Invite pending</div>}
                            </div>
                            <select value={s.role} onChange={e => doRoleChange(tank.id, s.id, e.target.value)}
                              style={{background: 'rgba(255,255,255,0.06)', border: '1px solid var(--border)', borderRadius: 8, color: 'var(--text)', fontSize: 12, padding: '4px 8px', cursor: 'pointer'}}>
                              <option value="viewer">Viewer</option>
                              <option value="operator">Operator</option>
                              <option value="admin">Admin</option>
                            </select>
                            <button onClick={() => doRevoke(tank.id, s.id)} style={{
                              background: 'rgba(255,60,60,0.08)', border: '1px solid rgba(255,60,60,0.2)',
                              borderRadius: 8, color: 'var(--red)', fontSize: 12, fontWeight: 600,
                              padding: '5px 10px', cursor: 'pointer',
                            }}>Revoke</button>
                          </div>
                        ))}
                        <div style={{padding: '10px 16px', borderTop: shareList.length > 0 ? '1px solid rgba(255,255,255,0.04)' : 'none'}}>
                          <button onClick={() => openSheet(tank.id)} style={{
                            width: '100%', padding: '10px', borderRadius: 10,
                            border: '1px dashed rgba(0,212,255,0.4)',
                            background: 'rgba(0,212,255,0.05)', color: 'var(--cyan)',
                            fontWeight: 600, fontSize: 13, cursor: 'pointer',
                            display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6,
                          }}>
                            <Ic name="plus" size={14}/> Share with someone
                          </button>
                        </div>
                      </div>
                    )}
                  </div>
                );
              })}
            </Card>
          </>
        )}

        {/* Shared with you */}
        {sharedWithMe.length > 0 && (
          <>
            <div style={{fontSize: 11, fontWeight: 700, color: 'var(--text-3)', letterSpacing: 0.8, textTransform: 'uppercase', marginBottom: 8, paddingLeft: 2}}>Shared With You</div>
            <Card style={{padding: 0, overflow: 'hidden', marginBottom: 20}}>
              {sharedWithMe.map((tank, i) => (
                <div key={tank.id} style={{display: 'flex', alignItems: 'center', gap: 12, padding: '14px 16px', borderTop: i > 0 ? '1px solid var(--border)' : 'none'}}>
                  <div style={{width: 34, height: 34, borderRadius: 10, background: 'rgba(0,212,255,0.10)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0}}>
                    <Ic name="grid" size={16} color="var(--cyan)"/>
                  </div>
                  <div style={{flex: 1, minWidth: 0}}>
                    <div style={{fontSize: 14, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap'}}>{tank.name}</div>
                    <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 1}}>
                      Shared by {tank.sharedBy?.name || tank.sharedBy?.email}
                    </div>
                  </div>
                  <span style={{
                    fontSize: 11, fontWeight: 600, padding: '3px 8px', borderRadius: 6,
                    background: 'rgba(0,212,255,0.08)',
                    color: ROLE_COLORS[tank.myRole] || 'var(--text-3)',
                    textTransform: 'capitalize', border: '1px solid rgba(255,255,255,0.08)',
                  }}>{tank.myRole}</span>
                </div>
              ))}
            </Card>
          </>
        )}

        {owned.length === 0 && sharedWithMe.length === 0 && (
          <div style={{textAlign: 'center', padding: '48px 20px', color: 'var(--text-3)', fontSize: 14}}>
            No devices found. Add a device first to start sharing.
          </div>
        )}
      </div>

      {/* Share bottom sheet */}
      {showSheet && ReactDOM.createPortal(
        <div
          style={{position: 'fixed', inset: 0, zIndex: 1000, display: 'flex', flexDirection: 'column', justifyContent: 'flex-end', background: 'rgba(0,0,0,0.6)'}}
          onClick={e => { if (e.target === e.currentTarget) setShowSheet(null); }}>
          <div style={{background: 'var(--bg-2, #1a1f3a)', borderRadius: '20px 20px 0 0', padding: '20px 16px 32px', borderTop: '1px solid var(--border)'}}>
            <div style={{fontWeight: 700, fontSize: 17, marginBottom: 16}}>Share Device</div>

            <label style={{fontSize: 13, color: 'var(--text-2)', display: 'block', marginBottom: 6}}>Email address</label>
            <input
              type="email" value={email}
              onChange={e => { setEmail(e.target.value); setShareErr(''); }}
              placeholder="user@example.com"
              style={{
                width: '100%', boxSizing: 'border-box', padding: '11px 14px', borderRadius: 12,
                background: 'rgba(255,255,255,0.06)',
                border: `1px solid ${shareErr ? 'var(--red)' : 'var(--border)'}`,
                color: 'var(--text)', fontSize: 14, outline: 'none', marginBottom: 4,
              }}/>
            {shareErr && <div style={{fontSize: 12, color: 'var(--red)', marginBottom: 8}}>{shareErr}</div>}

            <div style={{fontSize: 13, color: 'var(--text-2)', marginBottom: 8, marginTop: 14}}>Role</div>
            <div style={{display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 20}}>
              {['viewer', 'operator', 'admin'].map(r => (
                <button key={r} onClick={() => setRole(r)} style={{
                  display: 'flex', alignItems: 'center', gap: 12, padding: '12px 14px',
                  borderRadius: 12, textAlign: 'left',
                  background: role === r ? 'rgba(0,188,212,0.12)' : 'rgba(255,255,255,0.04)',
                  border: `1px solid ${role === r ? 'var(--cyan)' : 'var(--border)'}`,
                  color: 'var(--text)', cursor: 'pointer', transition: 'all 150ms',
                }}>
                  <div style={{flex: 1}}>
                    <div style={{fontWeight: 600, fontSize: 13, textTransform: 'capitalize'}}>{r}</div>
                    <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 2}}>{ROLE_DESC[r]}</div>
                  </div>
                  {role === r && <Ic name="check" size={16} color="var(--cyan)"/>}
                </button>
              ))}
            </div>

            <button
              onClick={doShare} disabled={sharing || !email.trim()}
              style={{
                width: '100%', padding: '14px 0', borderRadius: 14,
                background: (!sharing && email.trim()) ? 'linear-gradient(90deg, var(--cyan), var(--teal))' : 'rgba(255,255,255,0.06)',
                border: 'none',
                color: (!sharing && email.trim()) ? '#0a0e27' : 'var(--text-3)',
                fontWeight: 700, fontSize: 15,
                cursor: (sharing || !email.trim()) ? 'not-allowed' : 'pointer',
              }}>
              {sharing ? 'Sharing…' : 'Share Device'}
            </button>
          </div>
        </div>,
        document.getElementById('modal-root')
      )}
    </div>
  );
};

window.ManageSharing = ManageSharing;
