// Shared components for TVS CRM
const { useState, useEffect, useMemo, useRef } = React;

// =============================================================
// Format helpers
// =============================================================
const formatVND = (n) => {
  if (n == null) return '—';
  if (n >= 1_000_000_000) return (n / 1_000_000_000).toFixed(2).replace(/\.?0+$/, '') + ' tỷ';
  if (n >= 1_000_000) return (n / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'tr';
  if (n >= 1_000) return (n / 1_000).toFixed(0) + 'K';
  return n.toString();
};
const formatVNDFull = (n) => {
  if (n == null) return '—';
  return n.toLocaleString('vi-VN') + 'đ';
};
const formatDate = (iso) => {
  if (!iso) return '—';
  const d = new Date(iso);
  return `${String(d.getDate()).padStart(2,'0')}/${String(d.getMonth()+1).padStart(2,'0')}/${d.getFullYear()}`;
};
const formatRelative = (iso) => {
  if (!iso) return '—';
  // LƯU Ý: từng hardcode "hôm nay" = 2026-05-13 (ngày demo prototype cũ) — khiến mọi
  // ngày thật sau mốc đó (VD "mua gần nhất") bị tính lệch dấu, hiện "X ngày NỮA" thay vì
  // "X ngày TRƯỚC". Phải dùng ngày thật.
  const today = new Date();
  const d = new Date(iso);
  const diff = Math.round((today.setHours(0,0,0,0) - new Date(d).setHours(0,0,0,0)) / (1000*60*60*24));
  if (diff === 0) return 'Hôm nay';
  if (diff === 1) return 'Hôm qua';
  if (diff > 0) return `${diff} ngày trước`;
  if (diff === -1) return 'Ngày mai';
  return `${Math.abs(diff)} ngày nữa`;
};

window.fmt = { vnd: formatVND, vndFull: formatVNDFull, date: formatDate, rel: formatRelative };

// =============================================================
// Avatar
// =============================================================
function Avatar({ name, size = 'md', tier, src }) {
  const cls = size === 'sm' ? 'avatar-sm' : size === 'lg' ? 'avatar-lg' : size === 'xl' ? 'avatar-xl' : '';
  const tierCls = tier ? tier.toLowerCase() : '';
  const initials = useMemo(() => {
    if (!name) return '??';
    const parts = name.trim().split(/\s+/);
    if (parts.length === 1) return parts[0].slice(0,2).toUpperCase();
    return (parts[0][0] + parts[parts.length-1][0]).toUpperCase();
  }, [name]);
  return (
    <span className={`avatar ${cls} ${tierCls}`}>
      {src ? <img src={src} alt="" style={{width:'100%',height:'100%',borderRadius:'50%',objectFit:'cover'}}/> : initials}
    </span>
  );
}

// =============================================================
// Sidebar (Classic / Compact variants)
// =============================================================
function Sidebar({ role, currentScreen, onNavigate, navItems, onLogout }) {
  return (
    <aside className="sidebar">
      <div className="sidebar-brand">
        <img src="assets/logo-horiz-white.png" alt="The Vitamin Shoppe" />
      </div>
      <div className="sidebar-section">Workspace</div>
      <nav style={{display:'flex',flexDirection:'column',gap:2}}>
        {navItems.map(item => (
          <button
            key={item.id}
            className={`sidebar-item ${currentScreen === item.id ? 'active' : ''}`}
            onClick={() => onNavigate(item.id)}
            title={item.label}>
            <Icon name={item.icon} size={18} />
            <span className="label">{item.label}</span>
            {item.badge ? <span className="badge">{item.badge}</span> : null}
          </button>
        ))}
      </nav>
      <SapoSyncBadge/>
      <div className="sidebar-footer">
        <Avatar name={role.person} size="sm" src={role.avatarUrl} />
        <div className="meta">
          <div className="name">{role.person}</div>
          <div className="role-tag">{role.team}</div>
        </div>
        {onLogout && (
          <button className="btn btn-icon btn-sm btn-ghost" onClick={onLogout} title="Đăng xuất"
            style={{color:'rgba(255,255,255,0.5)',background:'transparent'}}>
            <Icon name="close" size={14}/>
          </button>
        )}
      </div>
    </aside>
  );
}

// =============================================================
// Topbar (Classic / Compact: thin top bar with search + quick actions
//          Airy: brand + nav tabs row + filter row )
// =============================================================
function Topbar({ role, currentScreen, navItems, onNavigate, variation, onSearch, breadcrumb, onAddCustomer, onAddPartner, onOpenMobileNav, onLogout, onOpenSearch, onOpenAccount }) {
  const screen = navItems.find(n => n.id === currentScreen);
  const [showCreate, setShowCreate] = useState(false);
  const [showProfile, setShowProfile] = useState(false);
  const [showNotif, setShowNotif] = useState(false);

  const [notifs, setNotifs] = useState([]);
  const live = window.TVS_API && window.TVS_API.isAuthed();

  const loadNotifs = () => {
    if (!live) {
      setNotifs([
        {id:'1', ic:'flag',   color:'var(--status-sale)',    title:'3 follow-up đến hạn hôm nay', meta:'Lý Tuấn Khang, Nguyễn Quốc Đạt...', t:'5 phút trước', unread:true},
        {id:'2', ic:'cart',   color:'var(--status-success)', title:'Đơn mới ghi nhận — Đặng Hoàng Mai', meta:'2.389.000đ · App', t:'18 phút trước', unread:true},
        {id:'3', ic:'flame',  color:'var(--status-warning)', title:'Whey Choco sắp hết tại Q.1', meta:'Còn 12 sản phẩm — dưới mức reorder', t:'1 giờ trước', unread:true},
        {id:'4', ic:'star',   color:'var(--status-warning)', title:'Đánh giá 5★ mới — Vũ Thanh Hà', meta:'Sản phẩm Collagen Peptides', t:'2 giờ trước', unread:false},
        {id:'5', ic:'handshake', color:'var(--vs-light-blue)', title:'KOC Yến Nhi đã đọc proposal', meta:'Đề xuất hợp tác — nên follow-up', t:'3 giờ trước', unread:false},
      ]);
      return;
    }
    window.TVS_API.api('/api/me/notifications')
      .then(r => {
        const newNotifs = r.notifications || [];
        setNotifs(prev => {
          const prevUnreadIds = new Set(prev.filter(n => n.unread).map(n => n.id));
          const hasNewUnread = newNotifs.some(n => n.unread && !prevUnreadIds.has(n.id));
          if (hasNewUnread && prev.length > 0) {
            window.TVS_API.refresh().then(() => {
              window.tvsRefreshUI && window.tvsRefreshUI();
            });
          }
          return newNotifs;
        });
      })
      .catch(() => {});
  };

  useEffect(() => {
    loadNotifs();
    if (live) {
      const interval = setInterval(loadNotifs, 10000);
      return () => clearInterval(interval);
    }
  }, [live]);

  const markReadAll = async () => {
    if (!live) {
      setNotifs(list => list.map(n => ({ ...n, unread: false })));
      return;
    }
    try {
      await window.TVS_API.api('/api/me/notifications/read-all', { method: 'POST' });
      loadNotifs();
    } catch (_) {}
  };

  const formatTime = (t) => {
    if (!t) return '';
    if (typeof t === 'string' && !t.includes('T') && !t.includes('-')) return t;
    try {
      const d = new Date(t);
      const diffMs = Date.now() - d.getTime();
      const diffMins = Math.floor(diffMs / 60000);
      if (diffMins < 1) return 'Vừa xong';
      if (diffMins < 60) return `${diffMins} phút trước`;
      const diffHours = Math.floor(diffMins / 60);
      if (diffHours < 24) return `${diffHours} giờ trước`;
      const diffDays = Math.floor(diffHours / 24);
      return `${diffDays} ngày trước`;
    } catch (_) { return String(t); }
  };

  const notifPanel = (
    <div style={{position:'absolute',right:0,top:'calc(100% + 8px)',background:'var(--bg-page)',border:'1px solid var(--border-1)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-pop)',width:360,maxWidth:'90vw',zIndex:50,overflow:'hidden'}}>
      <div style={{padding:'12px 16px',borderBottom:'1px solid var(--border-1)',display:'flex',alignItems:'center'}}>
        <span className="strong fg-1">Thông báo</span>
        <Tag variant="danger" style={{marginLeft:8}}>{notifs.filter(n=>n.unread).length} mới</Tag>
        <button className="text-xs" style={{marginLeft:'auto',background:'none',border:'none',color:'var(--vs-light-blue)',cursor:'pointer',fontWeight:700}} onClick={markReadAll}>Đánh dấu đã đọc</button>
      </div>
      <div style={{maxHeight:380,overflow:'auto'}}>
        {notifs.map((n, i) => (
          <button key={i} onClick={() => { setShowNotif(false); window.tvsToast('Đang mở: ' + n.title); }}
            style={{display:'flex',gap:10,padding:'12px 16px',width:'100%',border:'none',borderBottom:'1px solid var(--border-1)',background: n.unread ? 'rgba(65,182,230,0.04)' : 'none',cursor:'pointer',textAlign:'left'}}>
            <div style={{width:32,height:32,borderRadius:'50%',background:'var(--bg-soft)',color:n.color,display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}>
              <Icon name={n.ic} size={15}/>
            </div>
            <div style={{flex:1,minWidth:0}}>
              <div className="text-sm strong fg-1" style={{lineHeight:1.3}}>{n.title}</div>
              <div className="text-xs fg-muted" style={{marginTop:2}}>{n.meta}</div>
              <div className="text-xs fg-muted" style={{marginTop:3,color:'var(--vs-light-blue)'}}>{formatTime(n.t)}</div>
            </div>
            {n.unread && <span style={{width:8,height:8,borderRadius:'50%',background:'var(--vs-light-blue)',flexShrink:0,marginTop:6}}/>}
          </button>
        ))}
        {notifs.length === 0 && (
          <div className="empty" style={{padding:'var(--space-6)',textAlign:'center'}}>
            <Icon name="bell" size={24} style={{color:'var(--fg-muted)'}}/>
            <div className="text-sm fg-muted mt-2">Không có thông báo nào</div>
          </div>
        )}
      </div>
      <button style={{display:'block',width:'100%',padding:'12px',border:'none',borderTop:'1px solid var(--border-1)',background:'var(--bg-soft)',cursor:'pointer',color:'var(--vs-dark-blue)',fontWeight:700,fontSize:13}} onClick={() => window.tvsDemo('Trang thông báo đầy đủ')}>
        Xem tất cả thông báo
      </button>
    </div>
  );

  const createMenu = (
    <div style={{position:'absolute',right:0,top:'calc(100% + 8px)',background:'var(--bg-page)',border:'1px solid var(--border-1)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-pop)',minWidth:240,padding:6,zIndex:50}}>
      {onAddCustomer && (
        <button onClick={() => { setShowCreate(false); onAddCustomer(); }}
          style={{display:'flex',width:'100%',alignItems:'center',gap:10,padding:'10px 12px',border:'none',background:'none',borderRadius:'var(--radius-sm)',cursor:'pointer',textAlign:'left'}}
          onMouseEnter={(e)=>e.currentTarget.style.background='var(--bg-soft)'}
          onMouseLeave={(e)=>e.currentTarget.style.background='none'}>
          <Icon name="user" size={16} style={{color:'var(--vs-light-blue)'}}/>
          <div style={{flex:1}}>
            <div className="strong text-sm fg-1">Khách hàng mới</div>
            <div className="text-xs fg-muted">B2C — đăng ký thành viên</div>
          </div>
        </button>
      )}
      {onAddPartner && (
        <button onClick={() => { setShowCreate(false); onAddPartner(); }}
          style={{display:'flex',width:'100%',alignItems:'center',gap:10,padding:'10px 12px',border:'none',background:'none',borderRadius:'var(--radius-sm)',cursor:'pointer',textAlign:'left'}}
          onMouseEnter={(e)=>e.currentTarget.style.background='var(--bg-soft)'}
          onMouseLeave={(e)=>e.currentTarget.style.background='none'}>
          <Icon name="handshake" size={16} style={{color:'var(--vs-light-blue)'}}/>
          <div style={{flex:1}}>
            <div className="strong text-sm fg-1">Đối tác B2B</div>
            <div className="text-xs fg-muted">KOC, nhà thuốc, doanh nghiệp...</div>
          </div>
        </button>
      )}
    </div>
  );

  const profileMenu = (
    <div style={{position:'absolute',right:0,top:'calc(100% + 8px)',background:'var(--bg-page)',border:'1px solid var(--border-1)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-pop)',minWidth:240,padding:6,zIndex:50}}>
      <div style={{padding:'10px 12px',borderBottom:'1px solid var(--border-1)',marginBottom:6}}>
        <div className="strong fg-1">{role.person}</div>
        <div className="text-xs fg-muted">{role.team}</div>
      </div>
      {[
        {ic:'user',     l:'Hồ sơ cá nhân', go:'profile'},
        {ic:'settings', l:'Cài đặt tài khoản', go:'account'},
        {ic:'fileText', l:'Tài liệu hướng dẫn', demo:'Tài liệu hướng dẫn'},
        {ic:'mail',     l:'Liên hệ IT support', demo:'Liên hệ IT support'},
      ].map(m => (
        <button key={m.l} onClick={() => { setShowProfile(false); if (m.go && onOpenAccount) onOpenAccount(m.go); else if (m.demo) window.tvsDemo(m.demo); }} style={{display:'flex',width:'100%',alignItems:'center',gap:10,padding:'8px 12px',border:'none',background:'none',borderRadius:'var(--radius-sm)',cursor:'pointer',textAlign:'left'}}
          onMouseEnter={(e)=>e.currentTarget.style.background='var(--bg-soft)'}
          onMouseLeave={(e)=>e.currentTarget.style.background='none'}>
          <Icon name={m.ic} size={14} style={{color:'var(--fg-muted)'}}/>
          <span className="text-sm fg-2">{m.l}</span>
        </button>
      ))}
      {onLogout && (
        <>
          <div className="divider" style={{margin:'6px 8px'}}/>
          <button onClick={() => { setShowProfile(false); onLogout(); }}
            style={{display:'flex',width:'100%',alignItems:'center',gap:10,padding:'8px 12px',border:'none',background:'none',borderRadius:'var(--radius-sm)',cursor:'pointer',textAlign:'left'}}
            onMouseEnter={(e)=>e.currentTarget.style.background='rgba(191,9,35,0.06)'}
            onMouseLeave={(e)=>e.currentTarget.style.background='none'}>
            <Icon name="arrowleft" size={14} style={{color:'var(--status-sale)'}}/>
            <span className="text-sm" style={{color:'var(--status-sale)',fontWeight:600}}>Đăng xuất</span>
          </button>
        </>
      )}
    </div>
  );

  if (variation === 'airy') {
    return (
      <header className="topbar topbar-airy">
        <div className="row1">
          <div className="brand-h">
            <img src="assets/logo-horiz.png" alt="The Vitamin Shoppe" />
          </div>
          <div className="topbar-search" style={{flex:'0 1 380px',marginLeft:'auto',cursor:'pointer'}} onClick={() => onOpenSearch && onOpenSearch()}>
            <Icon name="search" size={16} style={{color:'var(--fg-muted)'}}/>
            <input placeholder="Tìm khách hàng, đơn hàng, sản phẩm, đối tác..." readOnly style={{cursor:'pointer'}} onFocus={() => onOpenSearch && onOpenSearch()} />
            <kbd>⌘K</kbd>
          </div>
          <div style={{position:'relative'}}>
            <button className="btn btn-icon btn-ghost" title="Thông báo" style={{position:'relative'}} onClick={() => setShowNotif(s => !s)}>
              <Icon name="bell" size={18}/>
              {notifs.some(n=>n.unread) && <span className="notif-dot"/>}
            </button>
            {showNotif && notifPanel}
          </div>
          <div style={{position:'relative'}}>
            <button onClick={() => setShowProfile(p => !p)} style={{background:'none',border:'none',cursor:'pointer',padding:0}}>
              <Avatar name={role.person} size="sm" src={role.avatarUrl} />
            </button>
            {showProfile && profileMenu}
          </div>
        </div>
        <div className="row2">
          {navItems.map(n => (
            <button key={n.id}
              className={`tab ${currentScreen === n.id ? 'active' : ''}`}
              onClick={() => onNavigate(n.id)}>
              <Icon name={n.icon} size={16}/>
              {n.label}
              {n.badge ? <span className="badge">{n.badge}</span> : null}
            </button>
          ))}
        </div>
      </header>
    );
  }
  return (
    <header className="topbar">
      {onOpenMobileNav && (
        <button className="btn btn-icon btn-ghost mobile-only" onClick={onOpenMobileNav} title="Mở menu">
          <Icon name="filter" size={20}/>
        </button>
      )}
      <div className="crumbs">
        <span className="hide-on-mobile">{role.team}</span>
        <span className="sep hide-on-mobile">/</span>
        <span className="current">{breadcrumb || (screen ? screen.label : '')}</span>
      </div>
      <div className="topbar-search hide-on-mobile" style={{cursor:'pointer'}} onClick={() => onOpenSearch && onOpenSearch()}>
        <Icon name="search" size={16} style={{color:'var(--fg-muted)'}}/>
        <input placeholder="Tìm khách hàng, đơn hàng, sản phẩm..." readOnly style={{cursor:'pointer'}} onFocus={() => onOpenSearch && onOpenSearch()} />
        <kbd>⌘K</kbd>
      </div>
      <div className="topbar-actions">
        <div style={{position:'relative'}}>
          <button className="btn btn-icon btn-ghost" title="Thông báo" style={{position:'relative'}} onClick={() => setShowNotif(s => !s)}>
            <Icon name="bell" size={18}/>
            {notifs.some(n=>n.unread) && <span className="notif-dot"/>}
          </button>
          {showNotif && notifPanel}
        </div>

        <div className="hide-on-mobile" style={{width:1,height:24,background:'var(--border-1)'}}/>
        {(onAddCustomer || onAddPartner) && (
          <div style={{position:'relative'}}>
            <button className="btn btn-cta btn-sm" onClick={() => setShowCreate(c => !c)}>
              <Icon name="plus" size={14}/>
              <span className="hide-on-mobile">Tạo mới</span>
            </button>
            {showCreate && createMenu}
          </div>
        )}
        <div style={{position:'relative'}} className="hide-on-mobile">
          <button onClick={() => setShowProfile(p => !p)} style={{background:'none',border:'none',cursor:'pointer',padding:0}}>
            <Avatar name={role.person} size="sm" src={role.avatarUrl} />
          </button>
          {showProfile && profileMenu}
        </div>
      </div>
    </header>
  );
}

// =============================================================
// KPI Card
// =============================================================
function KPI({ label, value, unit, delta, deltaDir = 'up', progress, progressLabel, feature, sub, children }) {
  return (
    <div className={`kpi ${feature ? 'feature' : ''}`}>
      <div className="label">{label}</div>
      <div className="value tnum">
        {value}
        {unit && <span className="unit">{unit}</span>}
      </div>
      {sub && <div style={{fontSize:'var(--t-xs)',color:'var(--fg-muted)',marginTop:4}}>{sub}</div>}
      {delta && (
        <div className={`delta ${deltaDir}`}>
          <Icon name={deltaDir === 'up' ? 'trending' : deltaDir === 'down' ? 'trendingDown' : 'activity'} size={12} stroke={2.2}/>
          {delta}
        </div>
      )}
      {progress != null && (
        <>
          <div className="kpi-progress">
            <div style={{width: Math.min(100, progress) + '%'}}/>
          </div>
          {progressLabel && (
            <div className="kpi-progress-meta">
              <span>{progressLabel.left}</span>
              <span>{progressLabel.right}</span>
            </div>
          )}
        </>
      )}
      {children}
    </div>
  );
}

// =============================================================
// Sparkline (simple SVG)
// =============================================================
function Sparkline({ data, color = 'var(--vs-light-blue)', height = 56, fill }) {
  const max = Math.max(...data) || 1;
  const min = Math.min(...data);
  const range = max - min || 1;
  const w = 200;
  const step = w / (data.length - 1 || 1);
  const points = data.map((v, i) => [i*step, height - ((v - min) / range) * (height - 8) - 4]);
  const path = points.map((p,i) => `${i===0?'M':'L'}${p[0]},${p[1]}`).join(' ');
  const area = path + ` L${w},${height} L0,${height} Z`;
  return (
    <svg className="spark" viewBox={`0 0 ${w} ${height}`} preserveAspectRatio="none">
      {fill && <path d={area} fill={fill} opacity="0.18"/>}
      <path d={path} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" vectorEffect="non-scaling-stroke"/>
      {points.map((p,i) => i === points.length-1 && <circle key={i} cx={p[0]} cy={p[1]} r="3" fill={color}/>)}
    </svg>
  );
}

// =============================================================
// Tag
// =============================================================
function Tag({ children, variant = 'default', dot }) {
  return (
    <span className={`tag ${variant !== 'default' ? variant : ''}`}>
      {dot && <span className="tag-dot" style={{background: typeof dot === 'string' ? dot : 'currentColor'}}/>}
      {children}
    </span>
  );
}

function tierVariant(tier) {
  const t = (tier || '').toLowerCase();
  if (t.includes('platinum') || t.includes('bạch')) return 'platinum';
  if (t.includes('gold') || t.includes('vàng')) return 'gold';
  if (t.includes('silver') || t.includes('bạc')) return 'silver';
  if (t.includes('bronze') || t.includes('đồng')) return 'bronze';
  return 'outline';
}

// =============================================================
// Card / CardHeader
// =============================================================
function Card({ children, pad = true, className = '', style }) {
  return <div className={`card ${pad ? 'card-pad' : ''} ${className}`} style={style}>{children}</div>;
}
function CardHeader({ title, sub, actions }) {
  return (
    <div className="card-h">
      <div>
        <h3>{title}</h3>
        {sub && <div className="sub">{sub}</div>}
      </div>
      {actions && <div className="actions">{actions}</div>}
    </div>
  );
}

// =============================================================
// Segmented control
// =============================================================
function Segmented({ value, options, onChange }) {
  return (
    <div className="segmented">
      {options.map(o => (
        <button key={o.value || o}
          className={value === (o.value || o) ? 'active' : ''}
          onClick={() => onChange(o.value || o)}>
          {o.label || o}
        </button>
      ))}
    </div>
  );
}

// =============================================================
// OwnerPicker — chọn NHIỀU người phụ trách cho 1 khách bằng checkbox (dropdown).
// currentIds: mảng userId đang phụ trách; onChange(nextIds) gọi khi tick/bỏ tick.
// =============================================================
function OwnerPicker({ currentIds = [], assignees = [], onChange, disabled, dark, fallbackLabel }) {
  const [open, setOpen] = useState(false);
  const sel = new Set(currentIds.filter(Boolean));
  const names = assignees.filter(u => sel.has(u.id)).map(u => u.name || '');
  const label = names.length ? names.join(' + ') : (fallbackLabel || 'Chưa phân công');
  const toggle = (id) => {
    const next = new Set(sel);
    next.has(id) ? next.delete(id) : next.add(id);
    const filtered = [...next].filter(x => assignees.some(u => u.id === x));
    onChange && onChange(filtered);
  };
  return (
    <div style={{position:'relative', display:'inline-block'}} onClick={(e)=>e.stopPropagation()}>
      <button type="button" disabled={disabled}
        onClick={(e)=>{ e.stopPropagation(); setOpen(o=>!o); }}
        title={label}
        style={{
          display:'inline-flex', alignItems:'center', gap:6, maxWidth:170,
          height:28, padding:'0 8px', fontSize:12, fontWeight:600, cursor:'pointer',
          borderRadius:6, border:'1px solid var(--border-1)',
          background: dark ? 'rgba(255,255,255,0.94)' : 'var(--bg-soft)',
          color:'var(--vs-dark-blue)',
        }}>
        <span style={{overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap', flex:1, textAlign:'left'}}>{label}</span>
        {sel.size > 1 && <span className="tag info" style={{padding:'0 5px', fontSize:10}}>{sel.size}</span>}
        <Icon name="chevron" size={12} style={{opacity:0.6}}/>
      </button>
      {open && (
        <>
          <div onClick={(e)=>{ e.stopPropagation(); setOpen(false); }} style={{position:'fixed', inset:0, zIndex:60}}/>
          <div style={{position:'absolute', top:'calc(100% + 4px)', left:0, zIndex:61, background:'var(--bg-page)', border:'1px solid var(--border-1)', borderRadius:8, boxShadow:'var(--shadow-pop)', minWidth:210, maxHeight:280, overflow:'auto', padding:6}}>
            <div className="text-xs fg-muted" style={{padding:'4px 8px 6px'}}>Chọn 1 hoặc nhiều người phụ trách</div>
            {assignees.map(u => {
              const on = sel.has(u.id);
              return (
                <label key={u.id} style={{display:'flex', gap:8, alignItems:'center', padding:'7px 8px', cursor:'pointer', borderRadius:6, background: on ? 'rgba(65,182,230,0.08)' : 'transparent'}}>
                  <input type="checkbox" checked={on} onChange={()=>toggle(u.id)} style={{accentColor:'var(--vs-light-blue)', width:15, height:15}}/>
                  <span className="text-sm fg-1">{u.name}</span>
                </label>
              );
            })}
            {assignees.length === 0 && <div className="text-xs fg-muted" style={{padding:8}}>Không có nhân viên</div>}
          </div>
        </>
      )}
    </div>
  );
}

// =============================================================
// DateRangePicker — chọn khoảng thời gian (lọc theo NGÀY HOÀN THÀNH).
// value = { from, to, preset } (YYYY-MM-DD, giờ VN). onChange(nextValue).
// =============================================================
function rpYMD(d) { return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; }
function computeRange(key) {
  const now = new Date();
  const today = rpYMD(now);
  const shift = (n) => { const d = new Date(now); d.setDate(d.getDate() + n); return d; };
  switch (key) {
    case 'today': return { from: today, to: today };
    case 'yesterday': { const y = rpYMD(shift(-1)); return { from: y, to: y }; }
    case '7d': return { from: rpYMD(shift(-6)), to: today };
    case '30d': return { from: rpYMD(shift(-29)), to: today };
    case 'thisMonth': return { from: rpYMD(new Date(now.getFullYear(), now.getMonth(), 1)), to: today };
    case 'lastMonth': return { from: rpYMD(new Date(now.getFullYear(), now.getMonth() - 1, 1)), to: rpYMD(new Date(now.getFullYear(), now.getMonth(), 0)) };
    case 'thisYear': return { from: rpYMD(new Date(now.getFullYear(), 0, 1)), to: today };
    case 'lastYear': return { from: rpYMD(new Date(now.getFullYear() - 1, 0, 1)), to: rpYMD(new Date(now.getFullYear() - 1, 11, 31)) };
    default: return { from: today, to: today };
  }
}
const RANGE_PRESETS = [
  ['today', 'Hôm nay'], ['yesterday', 'Hôm qua'],
  ['7d', '7 ngày qua'], ['30d', '30 ngày qua'],
  ['lastMonth', 'Tháng trước'], ['thisMonth', 'Tháng này'],
  ['lastYear', 'Năm trước'], ['thisYear', 'Năm nay'],
];
const RANGE_PRESET_LABEL = Object.fromEntries(RANGE_PRESETS);
function fmtVNDate(s) { if (!s) return ''; const [y, m, d] = s.split('-'); return `${d}/${m}/${y}`; }
function rangeLabelOf(v) {
  if (!v || !v.from) return '';
  if (v.preset && v.preset !== 'custom' && RANGE_PRESET_LABEL[v.preset]) return RANGE_PRESET_LABEL[v.preset];
  return v.from === v.to ? fmtVNDate(v.from) : `${fmtVNDate(v.from)} – ${fmtVNDate(v.to)}`;
}
function DateRangePicker({ value, onChange }) {
  const [open, setOpen] = useState(false);
  const [draft, setDraft] = useState(value);
  const [custom, setCustom] = useState(value.preset === 'custom');
  useEffect(() => { if (open) { setDraft(value); setCustom(value.preset === 'custom'); } }, [open]);
  // Bấm preset = áp dụng NGAY (không cần bấm Lọc), đóng dropdown luôn.
  const pick = (key) => { onChange({ ...computeRange(key), preset: key }); setOpen(false); };
  const apply = () => { if (draft.from && draft.to && draft.from <= draft.to) { onChange(draft); setOpen(false); } };
  const label = value.from === value.to ? fmtVNDate(value.from) : `${fmtVNDate(value.from)} - ${fmtVNDate(value.to)}`;
  return (
    <div style={{ position: 'relative', display: 'inline-block' }}>
      <button className="btn btn-secondary" onClick={() => setOpen(o => !o)} style={{ minWidth: 210, display: 'inline-flex', alignItems: 'center', gap: 8, justifyContent: 'space-between' }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}><Icon name="calendar" size={14} />{label}</span>
        <Icon name="chevron" size={13} style={{ opacity: 0.6 }} />
      </button>
      {open && (
        <>
          <div onClick={() => setOpen(false)} style={{ position: 'fixed', inset: 0, zIndex: 60 }} />
          <div style={{ position: 'absolute', top: 'calc(100% + 6px)', right: 0, zIndex: 61, background: 'var(--bg-page)', border: '1px solid var(--border-1)', borderRadius: 12, boxShadow: 'var(--shadow-pop)', padding: 12, width: 340 }}>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
              {RANGE_PRESETS.map(([k, l]) => {
                const active = !custom && value.preset === k;
                return (
                  <button key={k} onClick={() => pick(k)} style={{
                    padding: '13px 10px', cursor: 'pointer', borderRadius: 8, fontSize: 14,
                    border: active ? '1px solid var(--vs-light-blue)' : '1px solid var(--border-1)',
                    background: active ? 'rgba(65,182,230,0.10)' : 'var(--bg-page)',
                    color: active ? 'var(--vs-dark-blue)' : 'var(--fg-1)', fontWeight: active ? 700 : 500,
                  }}>{l}</button>
                );
              })}
            </div>
            <button onClick={() => { setCustom(true); setDraft({ from: value.from, to: value.to, preset: 'custom' }); }} style={{
              width: '100%', marginTop: 8, padding: '13px 10px', cursor: 'pointer', borderRadius: 8, fontSize: 14,
              border: custom ? '1px solid var(--vs-light-blue)' : '1px solid var(--border-1)',
              background: custom ? 'rgba(65,182,230,0.10)' : 'var(--bg-page)',
              color: custom ? 'var(--vs-dark-blue)' : 'var(--fg-1)', fontWeight: custom ? 700 : 500,
            }}>Tùy chọn (chọn ngày)</button>
            {custom && (
              <>
                <div className="row gap-2 mt-2" style={{ alignItems: 'center' }}>
                  <input type="date" className="input" value={draft.from} max={draft.to} onChange={e => setDraft(d => ({ ...d, from: e.target.value, preset: 'custom' }))} style={{ flex: 1 }} />
                  <span className="fg-muted">→</span>
                  <input type="date" className="input" value={draft.to} min={draft.from} onChange={e => setDraft(d => ({ ...d, to: e.target.value, preset: 'custom' }))} style={{ flex: 1 }} />
                </div>
                <button className="btn btn-cta" style={{ width: '100%', marginTop: 10, justifyContent: 'center' }} onClick={apply}>Lọc khoảng ngày</button>
              </>
            )}
          </div>
        </>
      )}
    </div>
  );
}

// =============================================================
// Bar chart (simple, vertical)
// =============================================================
function BarChart({ data, height = 120, color = 'var(--vs-light-blue)', highlight, labels }) {
  const max = Math.max(...data) || 1;
  const [hover, setHover] = useState(null);
  return (
    <div className="bar-row" style={{height, position:'relative', paddingTop: 20}}>
      {data.map((v, i) => (
        <div key={i}
          className={highlight != null && highlight !== i ? 'dim' : ''}
          style={{height: `${(v/max)*100}%`, background: highlight === i ? 'var(--vs-dark-blue)' : color, position:'relative'}}
          onMouseEnter={() => setHover(i)} onMouseLeave={() => setHover(h => h === i ? null : h)}
          title={labels ? labels[i] : `${v}`}
        >
          <div style={{position:'absolute',bottom:'100%',left:'50%',transform:'translateX(-50%)',marginBottom:3,fontSize:10,color:'var(--fg-1)',fontWeight:600,whiteSpace:'nowrap',pointerEvents:'none',fontFamily:'var(--font-display)'}}>
            {v > 0 ? v : ''}
          </div>
          {hover === i && (
            <div style={{position:'absolute',bottom:'100%',left:'50%',transform:'translateX(-50%)',marginBottom:18,background:'var(--vs-dark-blue)',color:'#fff',padding:'4px 9px',borderRadius:4,fontSize:11,fontWeight:600,whiteSpace:'nowrap',zIndex:20,pointerEvents:'none',boxShadow:'var(--shadow-pop)'}}>
              {labels ? labels[i] : v}
            </div>
          )}
        </div>
      ))}
    </div>
  );
}

Object.assign(window, {
  Avatar, Sidebar, Topbar, KPI, Sparkline, Tag, tierVariant,
  Card, CardHeader, Segmented, BarChart,
});

// =============================================================
// Global Search overlay (Cmd+K)
// =============================================================
function GlobalSearch({ onClose, onOpenCustomer, onNavigate }) {
  const [q, setQ] = useState('');
  const D = window.TVS_DATA;

  const [results, setResults] = useState(null);
  const [loading, setLoading] = useState(false);
  const apiLive = !!(window.TVS_API && window.TVS_API.isAuthed());

  useEffect(() => {
    if (!q.trim()) {
      setResults(null);
      return;
    }

    if (!apiLive) {
      const s = q.toLowerCase();
      const customers = D.customers.filter(c =>
        c.name.toLowerCase().includes(s) || c.phone.includes(s) || c.id.toLowerCase().includes(s)
      ).slice(0, 5);
      const partners = D.partners.filter(p =>
        p.name.toLowerCase().includes(s) || p.contact.toLowerCase().includes(s) || p.phone.includes(s)
      ).slice(0, 4);
      const products = D.products.filter(p =>
        p.name.toLowerCase().includes(s) || p.sku.toLowerCase().includes(s)
      ).slice(0, 4);
      setResults({ customers, partners, products });
      return;
    }

    setLoading(true);
    const delayDebounce = setTimeout(async () => {
      try {
        const custRes = await window.TVS_API.api('/api/customers/list?q=' + encodeURIComponent(q) + '&pageSize=20');
        const allCusts = custRes.customers || [];
        
        const customers = allCusts.filter(c => {
          const grp = (c.group || '').toLowerCase();
          return !grp.includes('wholesale') && !grp.includes('đối tác');
        }).slice(0, 5);

        const partners = allCusts.filter(c => {
          const grp = (c.group || '').toLowerCase();
          return grp.includes('wholesale') || grp.includes('đối tác');
        }).map(p => ({
          ...p,
          contact: p.preferredContact || 'phone'
        })).slice(0, 4);

        const s = q.toLowerCase();
        const products = D.products.filter(p =>
          p.name.toLowerCase().includes(s) || p.sku.toLowerCase().includes(s)
        ).slice(0, 4);

        setResults({ customers, partners, products });
      } catch (e) {
        console.error(e);
      } finally {
        setLoading(false);
      }
    }, 250);

    return () => clearTimeout(delayDebounce);
  }, [q]);

  const pages = [
    {l:'Tổng quan', s:'dashboard', ic:'dashboard'},
    {l:'Khách hàng', s:'customers', ic:'users'},
    {l:'Báo cáo', s:'reports', ic:'chart'},
    {l:'Tồn kho', s:'inventory', ic:'package'},
  ].filter(p => !q || p.l.toLowerCase().includes(q.toLowerCase()));

  return (
    <div style={{position:'fixed',inset:0,background:'rgba(1,33,105,0.40)',zIndex:300,display:'flex',justifyContent:'center',alignItems:'flex-start',paddingTop:'12vh',animation:'fadein 0.16s ease-out'}} onClick={onClose}>
      <div onClick={(e)=>e.stopPropagation()}
        style={{background:'var(--bg-page)',width:'min(620px,94vw)',maxHeight:'70vh',borderRadius:'var(--radius-lg)',boxShadow:'var(--shadow-pop)',overflow:'hidden',display:'flex',flexDirection:'column',animation:'slidein 0.2s var(--ease-out)'}}>
        <div style={{display:'flex',alignItems:'center',gap:12,padding:'16px 20px',borderBottom:'1px solid var(--border-1)'}}>
          <Icon name="search" size={20} style={{color:'var(--fg-muted)'}}/>
          <input autoFocus value={q} onChange={(e)=>setQ(e.target.value)}
            placeholder="Tìm khách hàng, đối tác, sản phẩm, trang..."
            style={{flex:1,border:'none',outline:'none',fontSize:16,fontFamily:'inherit',color:'var(--fg-1)',background:'none'}}/>
          <kbd style={{fontFamily:'var(--font-mono)',fontSize:11,background:'var(--bg-soft)',border:'1px solid var(--border-1)',borderRadius:4,padding:'2px 6px',color:'var(--fg-muted)'}}>ESC</kbd>
        </div>
        <div style={{overflow:'auto',flex:1}}>
          {!q.trim() ? (
            <div style={{padding:'14px 20px'}}>
              <div className="text-xs fg-muted mb-2" style={{textTransform:'uppercase',letterSpacing:'0.1em',fontWeight:700}}>Truy cập nhanh</div>
              {pages.map(p => (
                <button key={p.s} onClick={() => { onNavigate(p.s); onClose(); }}
                  style={{display:'flex',width:'100%',alignItems:'center',gap:12,padding:'10px 12px',border:'none',background:'none',borderRadius:'var(--radius-sm)',cursor:'pointer',textAlign:'left'}}
                  onMouseEnter={(e)=>e.currentTarget.style.background='var(--bg-soft)'}
                  onMouseLeave={(e)=>e.currentTarget.style.background='none'}>
                  <Icon name={p.ic} size={16} style={{color:'var(--vs-light-blue)'}}/>
                  <span className="text-sm fg-1">{p.l}</span>
                </button>
              ))}
            </div>
          ) : loading && !results ? (
            <div style={{padding:'32px 20px',textAlign:'center',color:'var(--fg-muted)'}}>
              <div className="text-sm">Đang tìm kiếm...</div>
            </div>
          ) : results ? (
            <div style={{padding:'8px 0'}}>
              {results.customers.length > 0 && (
                <SearchGroup label="Khách hàng">
                  {results.customers.map(c => (
                    <SearchItem key={c.id} onClick={() => { onOpenCustomer(c); onClose(); }}>
                      <Avatar name={c.name} size="sm" tier={tierVariant(c.tier)}/>
                      <div style={{flex:1,minWidth:0}}>
                        <div className="text-sm strong fg-1">{c.name}</div>
                        <div className="text-xs fg-muted tnum">{c.phone} · {c.code} · {c.city}</div>
                      </div>
                      <Tag variant={tierVariant(c.tier)}>{c.tier}</Tag>
                    </SearchItem>
                  ))}
                </SearchGroup>
              )}
              {results.partners.length > 0 && (
                <SearchGroup label="Đối tác B2B">
                  {results.partners.map(p => (
                    <SearchItem key={p.id} onClick={() => { onOpenCustomer(p); onClose(); }}>
                      <Avatar name={p.name} size="sm" tier={tierVariant(p.tier)}/>
                      <div style={{flex:1,minWidth:0}}>
                        <div className="text-sm strong fg-1">{p.name}</div>
                        <div className="text-xs fg-muted">{p.code} · {p.phone}</div>
                      </div>
                    </SearchItem>
                  ))}
                </SearchGroup>
              )}
              {results.products.length > 0 && (
                <SearchGroup label="Sản phẩm">
                  {results.products.map(p => (
                    <SearchItem key={p.sku} onClick={() => { onNavigate('inventory'); onClose(); }}>
                      <div style={{width:28,height:28,borderRadius:4,background:'var(--bg-soft)',color:'var(--vs-light-blue)',display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}><Icon name="pill" size={15}/></div>
                      <div style={{flex:1,minWidth:0}}>
                        <div className="text-sm strong fg-1">{p.name}</div>
                        <div className="text-xs fg-muted">{p.sku} · {p.cat}</div>
                      </div>
                    </SearchItem>
                  ))}
                </SearchGroup>
              )}
              {results.customers.length === 0 && results.partners.length === 0 && results.products.length === 0 && (
                <div style={{padding:'32px 20px',textAlign:'center',color:'var(--fg-muted)'}}>
                  <div className="text-sm">Không tìm thấy kết quả cho "<b>{q}</b>"</div>
                </div>
              )}
            </div>
          ) : null}
        </div>
      </div>
    </div>
  );
}
function SearchGroup({ label, children }) {
  return (
    <div style={{marginBottom:4}}>
      <div className="text-xs fg-muted" style={{padding:'8px 20px 4px',textTransform:'uppercase',letterSpacing:'0.1em',fontWeight:700}}>{label}</div>
      {children}
    </div>
  );
}
function SearchItem({ children, onClick }) {
  return (
    <button onClick={onClick}
      style={{display:'flex',width:'100%',alignItems:'center',gap:12,padding:'8px 20px',border:'none',background:'none',cursor:'pointer',textAlign:'left'}}
      onMouseEnter={(e)=>e.currentTarget.style.background='var(--bg-soft)'}
      onMouseLeave={(e)=>e.currentTarget.style.background='none'}>
      {children}
    </button>
  );
}
window.GlobalSearch = GlobalSearch;
