/* match-ui.jsx — shared primitives + icon set for Deman Match */
const { useState, useEffect, useRef, useMemo } = React;
const D = window.DM;

/* ---------------- icons ---------------- */
const I = {
  search:   <path d="M21 21l-4.3-4.3M11 18a7 7 0 100-14 7 7 0 000 14z"/>,
  filter:   <path d="M3 5h18M6 12h12M10 19h4"/>,
  bell:     <path d="M18 8a6 6 0 10-12 0c0 7-3 9-3 9h18s-3-2-3-9M13.7 21a2 2 0 01-3.4 0"/>,
  plus:     <path d="M12 5v14M5 12h14"/>,
  mic:      <path d="M12 2a3 3 0 00-3 3v6a3 3 0 006 0V5a3 3 0 00-3-3zM5 10v1a7 7 0 0014 0v-1M12 18v4"/>,
  micOff:   <path d="M9 9v2a3 3 0 004.2 2.7M15 11V5a3 3 0 00-5.9-.7M5 10v1a7 7 0 0010.7 6M12 18v4M3 3l18 18"/>,
  crown:    <path d="M3 7l4 4 5-7 5 7 4-4-2 12H5L3 7z"/>,
  arrow:    <path d="M5 12h14M13 6l6 6-6 6"/>,
  check:    <path d="M5 12l5 5L20 6"/>,
  x:        <path d="M6 6l12 12M18 6L6 18"/>,
  users:    <path d="M16 19v-2a4 4 0 00-4-4H6a4 4 0 00-4 4v2M9 9a3 3 0 100-6 3 3 0 000 6zM22 19v-2a4 4 0 00-3-3.9M16 3.1a4 4 0 010 7.8"/>,
  bolt:     <path d="M13 2L4 14h6l-1 8 9-12h-6l1-8z"/>,
  radar:    <path d="M12 2a10 10 0 100 20 10 10 0 000-20zM12 12L12 4M12 12l7 5"/>,
  globe:    <path d="M12 2a10 10 0 100 20 10 10 0 000-20zM2 12h20M12 2a15 15 0 000 20 15 15 0 000-20z"/>,
  sun:      <path d="M12 4V2M12 22v-2M4 12H2M22 12h-2M6 6L4.5 4.5M19.5 19.5L18 18M18 6l1.5-1.5M4.5 19.5L6 18M12 17a5 5 0 100-10 5 5 0 000 10z"/>,
  moon:     <path d="M21 12.8A9 9 0 1111.2 3a7 7 0 009.8 9.8z"/>,
  fire:     <path d="M12 2s5 4 5 9a5 5 0 01-10 0c0-2 1-3 1-3s.5 2 2 2c0-3 2-5 2-8zM12 22a5 5 0 005-5"/>,
  link:     <path d="M10 13a5 5 0 007 0l3-3a5 5 0 00-7-7l-1.5 1.5M14 11a5 5 0 00-7 0l-3 3a5 5 0 007 7l1.5-1.5"/>,
  spark:    <path d="M12 3l1.8 5.2L19 10l-5.2 1.8L12 17l-1.8-5.2L5 10l5.2-1.8L12 3z"/>,
  pad:      <path d="M6 11h4M8 9v4M15 11h.01M18 13h.01M17.3 6H6.7A4.7 4.7 0 002 10.7L1 17a2 2 0 003.6 1.4L7 15h10l2.4 3.4A2 2 0 0023 17l-1-6.3A4.7 4.7 0 0017.3 6z"/>,
  chevron:  <path d="M9 6l6 6-6 6"/>,
  back:     <path d="M19 12H5M11 18l-6-6 6-6"/>,
  clock:    <path d="M12 7v5l3 2M12 22a10 10 0 100-20 10 10 0 000 20z"/>,
  shield:   <path d="M12 2l8 3v6c0 5-3.5 8.5-8 11-4.5-2.5-8-6-8-11V5l8-3z"/>,
  trophy:   <path d="M8 21h8M12 17v4M7 4h10v5a5 5 0 01-10 0V4zM7 5H4v2a3 3 0 003 3M17 5h3v2a3 3 0 01-3 3"/>,
  msg:      <path d="M21 12a8 8 0 01-11.5 7.2L3 21l1.8-6.5A8 8 0 1121 12z"/>,
  cards:    <path d="M3 5h7v14H3zM14 5h7v14h-7z"/>,
  rows:     <path d="M3 6h18M3 12h18M3 18h18"/>,
  lanes:    <path d="M4 4h4v16H4zM10 4h4v16h-4zM16 4h4v16h-4z"/>
};
function Ic({ k, w=18, sw=2, style }){
  return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={sw}
    strokeLinecap="round" strokeLinejoin="round" style={{ width:w, height:w, flex:'none', ...style }}>{I[k]}</svg>;
}
const Discord = ({ w=18 }) => (
  <svg viewBox="0 0 24 24" fill="currentColor" style={{ width:w, height:w, flex:'none' }}>
    <path d="M19.3 5.3A17 17 0 0015 4l-.2.4a13 13 0 015 .8 11 11 0 00-13.6 0c1.6-.6 3.3-.8 5-.8L11 4a17 17 0 00-4.3 1.3C3.7 9.6 3 13.8 3.3 18a17 17 0 005.2 2.6l.4-.6c-1-.3-1.8-.7-2.6-1.2l.6-.4a12 12 0 0010 0l.6.4c-.8.5-1.7.9-2.6 1.2l.4.6a17 17 0 005.2-2.6c.4-4.9-.7-9.1-3.2-12.7zM9.3 15.4c-1 0-1.8-.9-1.8-2s.8-2 1.8-2 1.8.9 1.8 2-.8 2-1.8 2zm5.4 0c-1 0-1.8-.9-1.8-2s.8-2 1.8-2 1.8.9 1.8 2-.8 2-1.8 2z"/>
  </svg>
);

/* ---------------- avatar ---------------- */
function Av({ name, size=40, round=false, dot, ring }){
  return (
    <span className={'av'+(round?' round':'')} style={{ width:size, height:size, fontSize:size*0.38, '--av-grad':D.avGrad(name),
      boxShadow: ring ? `inset 0 0 0 1.5px oklch(1 0 0 /.18), 0 0 0 2px ${ring}` : undefined }}>
      {D.initials(name)}
      {dot && <span className={'av-dot '+dot} />}
    </span>
  );
}

/* ---------------- rank tag ---------------- */
function RankTag({ game, rank, sm }){
  const o = D.rankObj(game, rank);
  return <span className="rtag" style={{ '--rc':o.c, fontSize: sm?11:12, padding: sm?'3px 8px':undefined }}>{D.rankName(game,rank)}</span>;
}

/* ---------------- game pill / glyph ---------------- */
function GameGlyph({ game, size=40, r }){
  const g = D.GAMES[game];
  return (
    <span style={{ width:size, height:size, borderRadius:r||'9px', background:g.grad, display:'grid', placeItems:'center',
      fontFamily:'var(--display)', fontStyle:'italic', fontWeight:900, color:'#fff', fontSize:size*0.34, flex:'none',
      boxShadow:'inset 0 0 0 1.5px oklch(1 0 0 /.16)', letterSpacing:'-.03em' }}>{g.short}</span>
  );
}

/* ---------------- party member slots row ----------------
   Renders filled member avatars + empty "want" slots. Core reusable bit. */
function SlotRow({ party, size=38, showLane=true, en }){
  const g = D.GAMES[party.game];
  const filled = party.members;
  const totalNeed = (party.needLanes||[]).length;
  const open = Math.max(0, (g.size||5) - filled.length);
  const slots = [];
  filled.forEach((m,i)=> slots.push(
    <div key={'m'+i} style={{ display:'flex', flexDirection:'column', alignItems:'center', gap:5, width:size }}>
      <Av name={m.name} size={size} dot={m.pres==='online'?'online':undefined} />
      {showLane && m.lane && <span style={{ fontFamily:'var(--mono)', fontSize:9.5, color:'var(--text-mute)', whiteSpace:'nowrap' }}>{D.laneName(party.game, m.lane)}</span>}
    </div>
  ));
  (party.needLanes||[]).forEach((lane,i)=>{
    const urgent = party.urgent || (totalNeed===1);
    slots.push(
      <div key={'s'+i} style={{ display:'flex', flexDirection:'column', alignItems:'center', gap:5, width:size }}>
        <span className={'slot-empty want'+(urgent?' urgent':'')} style={{ width:size, height:size }}>
          <Ic k="plus" w={size*0.42} sw={2.4} />
        </span>
        {showLane && <span style={{ fontFamily:'var(--mono)', fontSize:9.5, color:'var(--q-amber)', fontWeight:600, whiteSpace:'nowrap' }}>{lane==='fill'?(en?'Any':'补位'):D.laneName(party.game, lane)}</span>}
      </div>
    );
  });
  // padding empty (non-need) slots up to size for context, faint
  const ghosts = open - (party.needLanes||[]).length;
  for(let i=0;i<Math.max(0,ghosts);i++) slots.push(
    <div key={'g'+i} style={{ display:'flex', flexDirection:'column', alignItems:'center', gap:5, width:size }}>
      <span className="slot-empty" style={{ width:size, height:size, opacity:.5 }} />
    </div>
  );
  return <div style={{ display:'flex', gap:9, flexWrap:'wrap' }}>{slots}</div>;
}

/* count of open need slots */
function needCount(party){ return (party.needLanes||[]).length; }
function teamLabel(party){ const g=D.GAMES[party.game]; return `${party.members.length}/${g.size||5}`; }

/* ---------------- "X=Y" need badge ---------------- */
function NeedBadge({ party, en }){
  const g = D.GAMES[party.game];
  const have = party.members.length, need = needCount(party);
  const urgent = party.urgent || need===1;
  return (
    <span style={{ fontFamily:'var(--display)', fontStyle:'italic', fontWeight:800, fontSize:15, letterSpacing:'.02em',
      display:'inline-flex', alignItems:'center', gap:4, color: urgent?'var(--q-coral)':'var(--q-amber)' }}>
      <b style={{ fontSize:18 }}>{have}</b>
      <span style={{ opacity:.6, fontStyle:'normal' }}>=</span>
      <b style={{ fontSize:18 }}>{need}</b>
      <span style={{ fontFamily:'var(--cn)', fontStyle:'normal', fontSize:11.5, fontWeight:700, marginLeft:3, opacity:.85 }}>
        {en?`need ${need}`:`缺 ${need}`}
      </span>
    </span>
  );
}

/* ---------------- "time ago" ---------------- */
function ago(min, en){
  if(min<=0) return en?'just now':'刚刚';
  if(min<60) return en?`${min}m ago`:`${min} 分钟前`;
  return en?`${Math.floor(min/60)}h ago`:`${Math.floor(min/60)} 小时前`;
}

/* ---------------- vibe tag ---------------- */
function VibeTag({ vibe, en }){
  const comp = vibe==='comp';
  return <span className="chip" style={{ fontSize:11, padding:'4px 9px', color: comp?'var(--v-bright)':'var(--q-lime)',
    borderColor:`color-mix(in oklab, ${comp?'var(--v-bright)':'var(--q-lime)'} 35%, transparent)`,
    background:`color-mix(in oklab, ${comp?'var(--v-bright)':'var(--q-lime)'} 12%, transparent)` }}>
    {comp?(en?'Ranked':'认真上分'):(en?'For fun':'娱乐局')}</span>;
}

Object.assign(window, { Ic, Discord, Av, RankTag, GameGlyph, SlotRow, NeedBadge, VibeTag, needCount, teamLabel, ago, I });
