/* Shared primitives: Avatar, PriorityDot, StatusPill, Chip, etc. */

const D = window.TASKHUB_DATA;

const userById   = (id) => D.users.find(u => u.id === id);
const statusById = (id) => D.statuses.find(s => s.id === id);
const spaceById  = (id) => D.spaces.find(s => s.id === id);
const groupById  = (id) => D.groups.find(g => g.id === id);
const clientById = (id) => D.clients.find(c => c.id === id);
const tagById    = (id) => D.tags.find(t => t.id === id);
const queueById  = (id) => D.queues.find(q => q.id === id);

const TODAY = D.today;
const dayDelta = (iso) => {
  if (!iso) return null;
  const d = new Date(iso + 'T00:00:00');
  const t = new Date(TODAY); t.setHours(0,0,0,0);
  return Math.round((d - t) / 86400000);
};
const dueLabel = (iso) => {
  if (!iso) return { text: '—', tone: 'muted' };
  const delta = dayDelta(iso);
  const date = new Date(iso + 'T00:00:00');
  const fmt = date.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' });
  if (delta < 0)  return { text: `${fmt} · ${-delta}d late`,   tone: 'late' };
  if (delta === 0) return { text: `Today · ${fmt}`,            tone: 'today' };
  if (delta === 1) return { text: `Tomorrow · ${fmt}`,         tone: 'soon' };
  if (delta <= 7)  return { text: `${fmt} · in ${delta}d`,     tone: 'soon' };
  return { text: fmt,                                          tone: 'normal' };
};
const fmtMins = (m) => {
  if (!m) return '';
  if (m < 60) return `${m}m`;
  const h = Math.floor(m/60), mm = m % 60;
  return mm ? `${h}h ${mm}m` : `${h}h`;
};

function Avatar({ user, size = 24, ring = false }) {
  if (!user) return null;
  const px = size + 'px';
  return (
    <span
      title={`${user.name} · ${user.role}`}
      style={{
        width: px, height: px,
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        background: user.colour, color: 'white',
        fontWeight: 600,
        fontSize: Math.max(9, size * 0.42) + 'px',
        letterSpacing: '0.01em',
        boxShadow: ring ? `0 0 0 2px white` : 'none',
        flexShrink: 0,
        borderRadius: '50%',
      }}>
      {user.initials}
    </span>
  );
}

function AvatarStack({ ids = [], max = 3, size = 24 }) {
  const overflow = ids.length - max;
  const shown = ids.slice(0, max);
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center' }}>
      {shown.map((id, i) => (
        <span key={id} style={{ marginLeft: i === 0 ? 0 : -7, position: 'relative', zIndex: max - i }}>
          <Avatar user={userById(id)} size={size} ring />
        </span>
      ))}
      {overflow > 0 && (
        <span style={{
          marginLeft: -7, width: size, height: size, borderRadius: '50%',
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          fontSize: '10px', fontWeight: 600,
          background: 'rgb(var(--paper-2))', color: 'rgb(var(--muted))',
          boxShadow: '0 0 0 2px white',
        }}>+{overflow}</span>
      )}
    </span>
  );
}

function PriorityDot({ p }) {
  return <span className={`prio prio-${p}`} title={`${p} priority`} />;
}

function StatusPill({ statusId, compact = false }) {
  const s = statusById(statusId); if (!s) return null;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      paddingInline: compact ? 8 : 10, paddingBlock: compact ? 3 : 4,
      background: s.colour + '14',
      color: s.colour,
      fontSize: 11, fontWeight: 600,
      letterSpacing: '-0.005em',
      borderRadius: 999,
      whiteSpace: 'nowrap',
    }}>
      <span className="pip" style={{ background: s.colour }} />
      {s.title}
    </span>
  );
}

function TagChip({ tag }) {
  if (!tag) return null;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 4,
      padding: '2px 8px',
      fontSize: 11, fontWeight: 500,
      color: tag.colour, background: tag.colour + '16',
      borderRadius: 999,
      whiteSpace: 'nowrap',
    }}>
      <span style={{ width: 5, height: 5, background: tag.colour, borderRadius: '50%' }} />
      {tag.name}
    </span>
  );
}

function TypeBadge({ type }) {
  const map = {
    task:      { label: 'Task',      colour: '#64748B', icon: '◇' },
    referral:  { label: 'Referral',  colour: '#3B82F6', icon: '➜' },
    incident:  { label: 'Incident',  colour: '#EF4444', icon: '!' },
    audit:     { label: 'Audit',     colour: '#10B981', icon: '✓' },
    admin:     { label: 'Admin',     colour: '#64748B', icon: '⚙' },
    feature:   { label: 'Feature',   colour: '#F59E0B', icon: '✦' },
    bug:       { label: 'Bug',       colour: '#EF4444', icon: '●' },
    complaint: { label: 'Complaint', colour: '#EC4899', icon: '!' },
    email:     { label: 'Email',     colour: '#3B82F6', icon: '✉' },
  };
  const m = map[type] || map.task;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 4,
      fontSize: 10.5, letterSpacing: '-0.005em',
      fontWeight: 600, color: m.colour,
    }}>
      <span style={{ fontSize: 9 }}>{m.icon}</span>{m.label}
    </span>
  );
}

function DueChip({ iso, compact = false }) {
  if (!iso) return <span style={{ color: 'rgb(var(--muted-2))', fontSize: 12 }}>—</span>;
  const { text, tone } = dueLabel(iso);
  let bg = 'transparent', colour = 'rgb(var(--muted))';
  if (tone === 'late')   { bg = 'rgb(var(--brick-soft))';  colour = 'rgb(var(--brick))'; }
  if (tone === 'today')  { bg = 'rgb(var(--accent-soft))'; colour = 'rgb(var(--accent-2))'; }
  if (tone === 'soon')   { bg = 'rgb(var(--paper-2))';     colour = 'rgb(var(--ink))'; }
  if (tone === 'normal') { bg = 'transparent';             colour = 'rgb(var(--ink-2))'; }
  return (
    <span className="num" style={{
      display: 'inline-flex', alignItems: 'center', gap: 4,
      fontSize: 11.5, padding: '2px 8px',
      color: colour,
      background: bg,
      fontWeight: tone === 'late' || tone === 'today' ? 600 : 500,
      whiteSpace: 'nowrap',
      borderRadius: 999,
    }}>{text}</span>
  );
}

function ProgressBar({ value = 0, height = 4, colour = 'rgb(var(--accent))' }) {
  return (
    <div style={{
      width: '100%', height,
      background: 'rgb(var(--paper-3))',
      position: 'relative', overflow: 'hidden',
      borderRadius: 999,
    }}>
      <div style={{
        position: 'absolute', inset: '0 auto 0 0',
        width: `${Math.max(0, Math.min(100, value))}%`,
        background: colour,
        borderRadius: 999,
        transition: 'width .3s ease-out',
      }} />
    </div>
  );
}

function IconBtn({ children, onClick, title, active = false, style = {} }) {
  return (
    <button onClick={onClick} title={title}
      style={{
        padding: '6px 8px', fontSize: 13,
        color: active ? 'rgb(var(--ink))' : 'rgb(var(--muted))',
        background: active ? 'rgb(var(--paper-2))' : 'transparent',
        transition: 'all .12s',
        borderRadius: 6,
        ...style,
      }}
      onMouseEnter={e => { if (!active) { e.currentTarget.style.color = 'rgb(var(--ink))'; e.currentTarget.style.background = 'rgb(var(--paper-2))'; }}}
      onMouseLeave={e => { if (!active) { e.currentTarget.style.color = 'rgb(var(--muted))'; e.currentTarget.style.background = 'transparent'; }}}
    >{children}</button>
  );
}

/* Subtle rule heading — used for section dividers */
function SectionHead({ children, count, action }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'baseline', gap: 8,
      padding: '4px 0 6px',
    }}>
      <span className="eyebrow">{children}</span>
      {count != null && <span className="num ticket-id">· {count}</span>}
      <span style={{ flex: 1, height: 1, background: 'rgb(var(--rule))', marginLeft: 4 }} />
      {action}
    </div>
  );
}

Object.assign(window, {
  D, userById, statusById, spaceById, groupById, clientById, tagById, queueById,
  TODAY, dayDelta, dueLabel, fmtMins,
  Avatar, AvatarStack, PriorityDot, StatusPill, TagChip, TypeBadge, DueChip,
  ProgressBar, IconBtn, SectionHead,
});
