/* ============================================================
   ui.jsx — shared presentational components
   ============================================================ */
const { useRef, useEffect, useState, useLayoutEffect } = React;

/* Pixel sprite rendered to a scaled canvas */
function Sprite({ name, scale = 4, flip = false, hue = 0, className = '', style = {} }) {
  const ref = useRef(null);
  useEffect(() => {
    const host = ref.current;
    if (!host) return;
    host.innerHTML = '';
    const cv = window.spriteEl(name, scale, flip);
    host.appendChild(cv);
  }, [name, scale, flip]);
  return (
    <span ref={ref} className={'sprite ' + className}
      style={{ ...style, filter: hue ? `hue-rotate(${hue}deg)` : 'none' }} />
  );
}

/* Small 8x8 icon glyph tinted to a color via canvas */
function Glyph({ name, scale = 3, color = '#fff', style = {} }) {
  const ref = useRef(null);
  useEffect(() => {
    const host = ref.current; if (!host) return;
    host.innerHTML = '';
    const base = window.spriteBase(name);
    if (!base) return;
    const cv = document.createElement('canvas');
    cv.width = base.width * scale; cv.height = base.height * scale;
    const ctx = cv.getContext('2d');
    ctx.imageSmoothingEnabled = false;
    ctx.drawImage(base, 0, 0, cv.width, cv.height);
    // tint: keep alpha, replace color
    ctx.globalCompositeOperation = 'source-in';
    ctx.fillStyle = color;
    ctx.fillRect(0, 0, cv.width, cv.height);
    cv.style.imageRendering = 'pixelated';
    host.appendChild(cv);
  }, [name, scale, color]);
  return <span ref={ref} className="sprite" style={{ ...style, display: 'inline-block' }} />;
}

/* HP / block bar */
function StatBar({ hp, maxHp, block = 0, width = 160 }) {
  const pct = Math.max(0, Math.min(100, (hp / maxHp) * 100));
  return (
    <div className="col" style={{ width, gap: 4 }}>
      <div className="bar bar-hp">
        <div className="bar-fill" style={{ width: pct + '%' }} />
        <div className="bar-label">{Math.max(0, Math.round(hp))}/{maxHp}</div>
      </div>
      {block > 0 && (
        <div className="row" style={{ alignItems: 'center', gap: 6 }}>
          <Glyph name="ic_shield" scale={2} color="#2ce8d8" />
          <span className="pix" style={{ fontSize: 11, color: '#2ce8d8', textShadow: '1px 1px 0 #000' }}>{block}</span>
        </div>
      )}
    </div>
  );
}

/* status badges row */
function StatusRow({ statuses }) {
  const map = {
    poison: { color: '#9ae600', icon: 'ic_drop' },
    burn:   { color: '#ff9f1c', icon: 'ic_flame' },
    weak:   { color: '#8aa6bf', icon: 'ic_down' },
    vuln:   { color: '#ff7a4d', icon: 'ic_spike' },
    frail:  { color: '#c98ab5', icon: 'ic_shield' },
    strength:{ color: '#ff4fa3', icon: 'ic_fist' },
  };
  const keys = Object.keys(statuses || {}).filter(k => statuses[k] > 0);
  if (!keys.length) return null;
  return (
    <div className="row" style={{ gap: 5, flexWrap: 'wrap', justifyContent: 'center', maxWidth: 160 }}>
      {keys.map(k => (
        <div key={k} className="row" {...tipProps(tipForStatus(k, statuses[k]))} style={{ alignItems: 'center', gap: 2, cursor:'help',
          background: 'rgba(0,0,0,.5)', padding: '2px 4px', border: '2px solid ' + (map[k]?.color || '#fff') }}>
          <Glyph name={map[k]?.icon || 'ic_star'} scale={2} color={map[k]?.color || '#fff'} />
          <span className="pix" style={{ fontSize: 9, color: map[k]?.color }}>{statuses[k]}</span>
        </div>
      ))}
    </div>
  );
}

/* Intent bubble above an enemy */
function Intent({ intent }) {
  if (!intent) return null;
  // ACTIVABLE — telegraphed tank setup (its own bubble with a ⚙ warning)
  if (intent.type === 'activable') {
    const a = window.GAME.activableInfo(intent.kind);
    return (
      <div className="row pop" {...tipProps({ title: 'PREPARA · ' + a.label, color: a.color, icon: a.icon, body: a.body })}
        style={{ position:'relative', alignItems:'center', gap:6, background:'rgba(7,19,31,.92)', cursor:'help',
        border:'3px solid ' + a.color, padding:'4px 8px', boxShadow:'0 4px 0 rgba(0,0,0,.4)' }}>
        <Glyph name={a.icon} scale={2.5} color={a.color} />
        <span className="pix" style={{ fontSize:8, color:a.color }}>⚙</span>
        <div style={{ position:'absolute', top:-5, right:-5, width:9, height:9, borderRadius:'50%', background:a.color, boxShadow:'0 0 0 2px #07131f' }} />
      </div>
    );
  }
  const dt = intent.dtype || 'weak';   // debuff flavor
  const DBUFF = {
    weak:  { color:'#8aa6bf', icon:'ic_down',  text:'',         body:'Va a debilitarte: pegarás un 25% menos.' },
    vuln:  { color:'#ff7a4d', icon:'ic_spike', text:'',         body:'Te dejará VULNERABLE: recibirás un 50% más de daño.' },
    frail: { color:'#c98ab5', icon:'ic_shield',text:'',         body:'Te volverá FRÁGIL: ganarás un 40% menos de bloqueo.' },
  }[dt];
  const m = {
    attack: { color: '#ff5a3c', icon: 'ic_sword', text: intent.value },
    block:  { color: '#2ce8d8', icon: 'ic_shield', text: intent.value },
    buff:   { color: '#ff4fa3', icon: 'ic_up', text: '+' + intent.value },
    debuff: { color: DBUFF.color, icon: DBUFF.icon, text: DBUFF.text },
    venom:  { color: '#9ae600', icon: 'ic_drop', text: '+' + intent.value },
    rally:  { color: '#ffd23f', icon: 'ic_up', text: '+' + intent.value },
    aegis:  { color: '#2ce8d8', icon: 'ic_shield', text: '+' + intent.value },
    healAlly:{ color: '#9ae600', icon: 'ic_heart', text: '+' + intent.value },
    swallow:{ color: '#b06bff', icon: 'ic_swirl', text: '' },
  }[intent.type] || {};
  const body = { attack: 'Va a atacarte por ' + intent.value + ' de daño.',
    block: 'Ganará ' + intent.value + ' de bloqueo.',
    buff: 'Aumentará su fuerza en ' + intent.value + '.',
    debuff: DBUFF.body,
    venom: 'Te va a ENVENENAR +' + intent.value + ' (daño al inicio de tus turnos).',
    rally: 'ARENGA: dará +' + intent.value + ' de fuerza a TODOS sus aliados.',
    aegis: 'MURO CORAL: dará +' + intent.value + ' de bloqueo a TODOS sus aliados.',
    healAlly: 'LUZ DE GUARDIA: curará ' + intent.value + ' al aliado más herido.',
    swallow: 'Se traga tu botín: pierdes 1 lanzamiento el próximo turno.' }[intent.type] || '';
  const title = intent.reactive ? 'INTENCIÓN ⚡' : 'INTENCIÓN';
  return (
    <div className="row pop" {...tipProps({ title, color: m.color, icon: m.icon,
      body: (intent.reactive ? '⚡ Reacciona a ti. ' : '') + body })}
      style={{ position:'relative', alignItems: 'center', gap: 6, background: 'rgba(7,19,31,.92)', cursor: 'help',
      border: '3px solid ' + m.color, padding: '4px 8px', boxShadow: '0 4px 0 rgba(0,0,0,.4)' }}>
      <Glyph name={m.icon} scale={2.5} color={m.color} />
      {m.text !== '' && <span className="pix" style={{ fontSize: 13, color: '#fff' }}>{m.text}</span>}
      {intent.reactive && <div style={{ position:'absolute', top:-5, right:-5, width:9, height:9, borderRadius:'50%',
        background:'#ffd23f', boxShadow:'0 0 0 2px #07131f' }} />}
    </div>
  );
}

/* ITEM card / token visual (used in deck views & rewards) */
// map an 8x8 glyph name to its big pixel-art icon (only registered for some); null = fall back to glyph
function bigIcon(iconName) { const k = 'ii_' + (iconName || '').replace('ic_', ''); return (window.SPRITES && window.SPRITES[k]) ? k : null; }
// pick a card's big art: bespoke per-card icon (it.art) if registered, else the category big-icon
function cardArt(it) { if (it && it.art && window.SPRITES && window.SPRITES[it.art]) return it.art; return bigIcon(it && it.icon); }

function ItemCard({ it, size = 'md', onClick, selected, design = 'token' }) {
  const cat = window.GAME.CAT[it.cat];
  const aff = window.GAME.AFF[it.aff] || { color:'#9db8c9', label:'' };
  const dims = { sm: 52, md: 86, lg: 104 }[size];
  const rarity = { c:'#9db8c9', u:'#2ce8d8', r:'#ffd23f' }[it.rarity];
  const up = it.up || 0;

  if (design === 'flat') {
    // flat card design
    return (
      <div onClick={onClick} className={'col ' + (onClick ? 'btn-card' : '')} {...tipProps(tipForItem(it))}
        style={{ width: dims*1.4, cursor: onClick?'pointer':'help',
          background: '#0b1d2e', border: '4px solid ' + (selected?'#ffd23f':'#16242f'),
          boxShadow: selected?'0 0 0 3px #ffd23f, 0 6px 0 rgba(0,0,0,.4)':'0 6px 0 rgba(0,0,0,.4)' }}>
        <div className="row" style={{ background: cat.color, padding: '6px 8px', alignItems:'center', gap:6 }}>
          <Glyph name={it.icon} scale={2.5} color="#0b1d2e" />
          <span className="pix" style={{ fontSize: 9, color:'#0b1d2e' }}>{it.val||'•'}</span>
          {up > 0 && <span className="pix" style={{ fontSize: 7, color:'#0b1d2e' }}>+{up}</span>}
          <span className="pix" style={{ fontSize: 6, color:'#0b1d2e', marginLeft:'auto' }}>{aff.label}</span>
        </div>
        <div className="col" style={{ padding: '8px', gap: 6, flex:1 }}>
          <div className="pix" style={{ fontSize: 9, color: '#fff', lineHeight:1.5 }}>{it.name}</div>
          <div className="body" style={{ fontSize: 17, color: '#9db8c9', lineHeight:1 }}>{it.desc}</div>
          <div className="row" style={{ marginTop:'auto', justifyContent:'space-between' }}>
            <span className="tiny" style={{ color: rarity, fontSize:7 }}>{cat.label}</span>
            <span className="tiny" style={{ color: aff.color, fontSize:7 }}>◈{aff.label}</span>
          </div>
        </div>
      </div>
    );
  }

  // default: circular token (matches the tank look) — outer ring = affinity
  return (
    <div onClick={onClick} className="col center" {...tipProps(tipForItem(it))}
      style={{ cursor: onClick?'pointer':'help', gap: 6, width: dims+24 }}>
      <div className="col center" style={{
        width: dims, height: dims, borderRadius: '50%',
        background: `radial-gradient(circle at 35% 30%, ${cat.color}, ${shade(cat.color,-30)})`,
        boxShadow: selected
          ? `0 0 0 4px #07131f, 0 0 0 8px #ffd23f, ${up ? '0 0 18px 6px rgba(255,210,63,.55), ' : ''}inset 6px 6px 0 rgba(255,255,255,.25), inset -6px -6px 0 rgba(0,0,0,.3)`
          : `0 0 0 4px #07131f, 0 0 0 7px ${up ? '#ffd23f' : aff.color}, ${up ? '0 0 18px 5px rgba(255,210,63,.45), ' : ''}inset 6px 6px 0 rgba(255,255,255,.25), inset -6px -6px 0 rgba(0,0,0,.3)`,
        position:'relative' }}>
        {(() => { const bi = cardArt(it); return bi
          ? <Sprite name={bi} scale={size==='sm'?1.8:size==='lg'?2.9:2.5} />
          : <Glyph name={it.icon} scale={size==='sm'?3:4} color="#07131f" />; })()}
        {it.val>0 && <div className="pix" style={{ position:'absolute', bottom:6, right:6, fontSize:11, color:'#fff', textShadow:'2px 2px 0 #000' }}>{it.val}</div>}
        {up > 0 && <div className="pix" style={{ position:'absolute', top:-6, right:-7, fontSize:9, color:'#07131f',
          background:'#ffd23f', border:'2px solid #07131f', padding:'2px 4px', boxShadow:'0 0 0 2px #ffd23f' }}>+{up}</div>}
      </div>
      <div className="pix" style={{ fontSize: 8, color:'#eaf6ff', textAlign:'center', lineHeight:1.5 }}>{it.name}</div>
      {size !== 'sm' && <div className="pix" style={{ fontSize: 6, color: aff.color, letterSpacing:1 }}>◈ {aff.label}{it.aff2 ? <span style={{ color: it.aff2Color }}> +{window.GAME.AFF[it.aff2].label}</span> : ''}</div>}
    </div>
  );
}

/* RELIC card */
function RelicCard({ rel, onClick, owned }) {
  return (
    <div onClick={onClick} className="col center" {...tipProps(tipForRelic(rel))}
      style={{ width: 188, cursor: onClick?'pointer':'help', gap: 10, opacity: owned?0.5:1,
        background:'#0b1d2e', border:'4px solid '+rel.color, padding:16, boxShadow:'0 6px 0 rgba(0,0,0,.4)' }}>
      <div className="col center" style={{ width:64, height:64, borderRadius:'50%',
        background:`radial-gradient(circle at 35% 30%, ${rel.color}, ${shade(rel.color,-45)})`,
        boxShadow:'0 0 0 4px #07131f, inset 5px 5px 0 rgba(255,255,255,.22), inset -5px -5px 0 rgba(0,0,0,.3)' }}>
        {(() => { const bi = bigIcon(rel.icon); return bi ? <Sprite name={bi} scale={2.5} /> : <Glyph name={rel.icon} scale={4} color="#07131f" />; })()}
      </div>
      <div className="pix" style={{ fontSize:10, color:'#fff', textAlign:'center', lineHeight:1.5 }}>{rel.name}</div>
      <div className="body" style={{ fontSize:18, color:'#9db8c9', textAlign:'center', lineHeight:1.05 }}>{rel.desc}</div>
    </div>
  );
}

function shade(hex, amt) {
  let c = hex.replace('#',''); if (c.length===3) c=c.split('').map(x=>x+x).join('');
  let r=parseInt(c.slice(0,2),16), g=parseInt(c.slice(2,4),16), b=parseInt(c.slice(4,6),16);
  r=Math.max(0,Math.min(255,r+amt)); g=Math.max(0,Math.min(255,g+amt)); b=Math.max(0,Math.min(255,b+amt));
  return `rgb(${r},${g},${b})`;
}

function Btn({ children, onClick, disabled, variant = '', style = {} }) {
  return (
    <button className={'btn ' + variant} disabled={disabled} style={style}
      onClick={(e) => { if (window.SFX) window.SFX.click(); onClick && onClick(e); }}>{children}</button>
  );
}

/* ============================================================
   TOOLTIP SYSTEM
   ============================================================ */
let _tipSetter = null;
function showTip(data, x, y) { if (_tipSetter) _tipSetter({ ...data, x, y }); }
function hideTip() { if (_tipSetter) _tipSetter(null); }
function tipProps(data) {
  return {
    onMouseEnter: (e) => showTip(data, e.clientX, e.clientY),
    onMouseMove: (e) => showTip(data, e.clientX, e.clientY),
    onMouseLeave: () => hideTip(),
    onMouseDown: () => hideTip(),   // clicking (e.g. a map node) navigates away with no mouseleave → kill tip now
  };
}

function TooltipHost() {
  const [tip, setTip] = useState(null);
  useEffect(() => { _tipSetter = setTip; return () => { _tipSetter = null; }; }, []);
  if (!tip) return null;
  const W = 270;
  let left = tip.x + 18, top = tip.y + 18;
  if (left + W > window.innerWidth - 8) left = tip.x - W - 18;
  if (top + 170 > window.innerHeight - 8) top = Math.max(8, tip.y - 160);
  const color = tip.color || '#9db8c9';
  return (
    <div style={{ position: 'fixed', left, top, zIndex: 99999, pointerEvents: 'none', width: W }}>
      <div style={{ background: '#0b1d2e', border: '3px solid ' + color, padding: '10px 12px',
        boxShadow: '0 6px 0 rgba(0,0,0,.5), inset 2px 2px 0 rgba(255,255,255,.06)', imageRendering: 'pixelated' }}>
        <div className="row" style={{ alignItems: 'center', gap: 7 }}>
          {tip.icon && <Glyph name={tip.icon} scale={2.5} color={color} />}
          <span className="pix" style={{ fontSize: 10, color, lineHeight: 1.5 }}>{tip.title}</span>
        </div>
        {tip.sub && <div className="pix" style={{ fontSize: 7, color: '#6f8aa0', marginTop: 5, letterSpacing: 1 }}>{tip.sub}</div>}
        {tip.body && <div className="body" style={{ fontSize: 18, color: '#eaf6ff', marginTop: 7, lineHeight: 1.04 }}>{tip.body}</div>}
        {tip.rows && tip.rows.map((r, i) => (
          <div key={i} className="row" style={{ justifyContent: 'space-between', marginTop: 5, gap: 10 }}>
            <span className="pix" style={{ fontSize: 7, color: '#9db8c9' }}>{r.label}</span>
            <span className="pix" style={{ fontSize: 7, color: r.color || '#eaf6ff' }}>{r.value}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ---- content builders ---- */
const MOVE_LABEL = { static: 'Quieto', drift: 'Deriva', fast: 'Errático', current: 'Corriente' };
const RARITY_LABEL = { c: 'Común', u: 'Poco común', r: 'Raro' };

function tipForItem(it) {
  const G = window.GAME;
  const aff = G.AFF[it.aff];
  if (it.hazard) {
    return { title: it.name, color: '#ff3b3b', icon: it.icon, sub: 'PELIGRO',
      body: it.desc, rows: [{ label: 'MOVIMIENTO', value: MOVE_LABEL[it.move] || '—' }] };
  }
  if (it.junk) {
    return { title: it.name, color: '#9db8c9', icon: it.icon, sub: 'CHATARRA',
      body: it.desc, rows: [{ label: 'MOVIMIENTO', value: MOVE_LABEL[it.move] || '—' }] };
  }
  const aff2 = it.aff2 ? G.AFF[it.aff2] : null;
  return {
    title: it.name, color: it.catColor, icon: it.icon,
    sub: G.CAT[it.cat].label + ' · ◈' + (aff ? aff.label : '') + (aff2 ? '+' + aff2.label : '') + (it.up ? ' · MEJORA +' + it.up : ''),
    body: it.desc,
    rows: [
      { label: 'AFINIDAD', value: (aff ? aff.label : '—') + (aff2 ? ' + ' + aff2.label : ''), color: it.affColor },
      { label: 'MOVIMIENTO', value: MOVE_LABEL[it.move] || '—' },
      { label: 'RAREZA', value: RARITY_LABEL[it.rarity] || '—' },
    ],
  };
}
// TEMPLAR — tooltip comparativo: muestra qué valores subirían al mejorar (esto → esto)
const UPGRADE_LABELS = { damage:'DAÑO', block:'BLOQUEO', poison:'VENENO', burn:'QUEMADURA', heal:'CURA', vamp:'ROBO DE VIDA',
  bomb:'BOMBA', strength:'FUERZA', weaken:'DÉBIL', expose:'VULNERABLE', frailty:'FRÁGIL', thorns:'PÚAS',
  ifWaterBonus:'BONUS AGUA', ifThermalBurn:'BONUS TERMAL', perChain:'POR CADENA', pressureBlast:'PRESIÓN', ifPrism:'BONUS PRISMA',
  blockDamage:'BLOQUEO→DAÑO', detonatePoison:'DETONA VENENO' };
function tipForUpgrade(card) {
  const G = window.GAME;
  const cur = G.item(card), next = G.item(G.upgradeCard(card));
  const rows = [];
  if ((cur.val || 0) !== (next.val || 0)) rows.push({ label:'VALOR', value:(cur.val||0) + ' → ' + (next.val||0), color:'#ffd23f' });
  const ce = cur.eff || {}, ne = next.eff || {};
  Object.keys(UPGRADE_LABELS).forEach(k => {
    if (typeof ce[k] === 'number' || typeof ne[k] === 'number') {
      const a = ce[k] || 0, b = ne[k] || 0;
      if (a !== b) rows.push({ label: UPGRADE_LABELS[k], value: a + ' → ' + b, color:'#ffd23f' });
    }
  });
  const baseName = (cur.name || '').replace(/\s*\+\d+$/, '');
  return { title: baseName, color:'#ffd23f', icon: cur.icon, sub:'TEMPLAR · MEJORA +1',
    body: rows.length ? 'Al templarla mejora sus valores:' : 'Esta carta no puede mejorarse más.', rows };
}
const MOD_DESC = {
  anchor:  'Ancla objetos de tu tanque: si el arpón roza uno, se DETIENE ahí.',
  junk:    'Inyecta Chatarra inútil en tu tanque para estorbar tu línea.',
  hazard:  'Siembra Erizos Mina: si el arpón los roza, te dañan y rebota.',
  current: 'Refuerza la corriente: tus objetos se mueven mucho más rápido.',
  fog:     'Niebla que tapa parte del tanque y oculta los objetos.',
  vortex:  'Un remolino vivo arrastra todos los objetos en espiral hacia su centro móvil. Cronometra tu tiro.',
};
function tipForEnemy(en) {
  const next = en.pattern[en.intentIdx % en.pattern.length];
  const intentTxt = next ? ({
    attack: 'Atacará por ' + next.value, block: 'Se protege (+' + next.value + ')',
    buff: 'Se fortalece (+' + next.value + ' fuerza)', debuff: 'Te debilita',
    rally: 'Arenga: +' + next.value + ' fuerza a aliados', aegis: 'Muro: +' + next.value + ' bloqueo a aliados',
    healAlly: 'Cura ' + next.value + ' a un aliado',
  }[next.type]) : '';
  const rows = [{ label: 'PV', value: Math.max(0, Math.round(en.hp)) + '/' + en.maxHp, color: '#ff6b8b' }];
  if (intentTxt) rows.push({ label: 'INTENCIÓN', value: intentTxt, color: '#ffd23f' });
  return { title: en.name, color: en.boss ? '#ff6b8b' : '#ff5a3c',
    body: en.mod ? MOD_DESC[en.mod] : 'Una bestia del abismo.', rows };
}
function tipForRelic(rel) {
  return { title: rel.name, color: rel.color, icon: rel.icon, sub: 'RELIQUIA', body: rel.desc };
}
const STATUS_DESC = {
  poison: (v) => 'VENENO ' + v + ': al inicio de su turno pierde ' + v + ' PV (luego baja 1).',
  burn: (v) => 'QUEMADURA ' + v + ': al inicio de su turno pierde ' + v + ' PV (luego baja 2).',
  weak: (v) => 'DÉBIL ' + v + ': inflige un 25% menos de daño (baja 1/turno).',
  vuln: (v) => 'VULNERABLE ' + v + ': recibe un 50% MÁS de daño (baja 1/turno).',
  frail: (v) => 'FRÁGIL ' + v + ': gana un 40% MENOS de bloqueo (baja 1/turno).',
  strength: (v) => 'FUERZA ' + v + ': +' + v + ' de daño por cada ataque.',
};
const STATUS_COLOR = { poison:'#9ae600', burn:'#ff9f1c', weak:'#8aa6bf', vuln:'#ff7a4d', frail:'#c98ab5', strength:'#ff4fa3' };
const STATUS_ICON = { poison:'ic_drop', burn:'ic_flame', weak:'ic_down', vuln:'ic_spike', frail:'ic_shield', strength:'ic_fist' };
function tipForStatus(key, val) {
  return { title: key.toUpperCase(), color: STATUS_COLOR[key] || '#fff', icon: STATUS_ICON[key],
    body: (STATUS_DESC[key] ? STATUS_DESC[key](val) : '') };
}
function tipForMod(mod, info) {
  return { title: info.label, color: info.color, icon: info.icon, sub: 'EFECTO DE AGUA', body: MOD_DESC[mod] || '' };
}

Object.assign(window, { Sprite, Glyph, StatBar, StatusRow, Intent, ItemCard, RelicCard, Btn, shade, bigIcon, cardArt,
  TooltipHost, showTip, hideTip, tipProps, tipForItem, tipForUpgrade, tipForEnemy, tipForRelic, tipForStatus, tipForMod });
