(function() {
  var useState  = React.useState;
  var useEffect = React.useEffect;
  var useRef    = React.useRef;
  var Icon      = window.CBIcon;

  /* ═══════════════════════════════════════════════════════
     League components — Duolingo/Candy-Crush leaderboard kit
     CBCountUp · CBMedal · CBPodium · CBRewardChest
     ═══════════════════════════════════════════════════════ */

  /* Animated number — counts up with ease-out on mount/value change */
  function CountUp(props) {
    var target = props.value || 0;
    var _v = useState(0); var v = _v[0], setV = _v[1];
    useEffect(function() {
      var start = null, dur = props.duration || 1100, raf;
      function tick(ts) {
        if (!start) start = ts;
        var p = Math.min(1, (ts - start) / dur);
        setV(Math.round(target * (1 - Math.pow(1 - p, 3))));
        if (p < 1) raf = requestAnimationFrame(tick);
      }
      var delay = setTimeout(function() { raf = requestAnimationFrame(tick); }, props.delay || 0);
      return function() { clearTimeout(delay); cancelAnimationFrame(raf); };
    }, [target]);
    return React.createElement(React.Fragment, null, v.toLocaleString());
  }

  /* Rank medal — gold/silver/bronze shine for top 3, chip for the rest */
  var MEDAL_BG = {
    1: 'linear-gradient(135deg, #ffe27a 0%, #f5b73d 45%, #c8860a 100%)',
    2: 'linear-gradient(135deg, #f0f3f7 0%, #c3ccd9 45%, #8b97a8 100%)',
    3: 'linear-gradient(135deg, #f3b183 0%, #cd7f4a 45%, #97561f 100%)',
  };
  function Medal(props) {
    var rank = props.rank, size = props.size || 34;
    if (rank <= 3) {
      return (
        <span className={'lb-medal lb-medal-' + rank} style={{ width: size, height: size, background: MEDAL_BG[rank] }}>
          {rank === 1 ? <span className="lb-medal-crown"><Icon name="crown" size={Math.round(size * 0.42)} /></span> : null}
          <span className="lb-medal-num">{rank}</span>
        </span>
      );
    }
    return <span className="lb-rank-chip" style={{ width: size, height: size }}>{rank}</span>;
  }

  /* Top-3 podium — pillars grow 3rd → 2nd → 1st, crown lands, confetti */
  function Podium(props) {
    var users = (props.users || []).slice(0, 3);
    var fired = useRef(false);

    useEffect(function() {
      if (fired.current || users.length < 3) return;
      fired.current = true;
      var t1 = setTimeout(function() { window.CBSfx && window.CBSfx.play('pop'); }, 250);
      var t2 = setTimeout(function() { window.CBSfx && window.CBSfx.play('pop'); }, 550);
      var t3 = setTimeout(function() { window.CBSfx && window.CBSfx.play('pop'); }, 880);
      var t4 = setTimeout(function() {
        window.CBSfx && window.CBSfx.play('xp');
        window.CBConfetti && window.CBConfetti.burst({ count: 90, power: 11 });
      }, 1250);
      return function() { [t1, t2, t3, t4].forEach(clearTimeout); };
    }, [users.length]);

    if (users.length < 3) return null;

    var GRADS = [
      'linear-gradient(135deg,var(--violet),var(--cyan))',
      'linear-gradient(135deg,var(--lime),var(--cyan))',
      'linear-gradient(135deg,var(--amber),var(--rose))',
    ];
    function initials(name) {
      return (name || '').split(' ').map(function(n) { return n[0] || ''; }).join('').slice(0, 2).toUpperCase();
    }

    // Visual order: 2nd · 1st · 3rd
    var slots = [
      { u: users[1], rank: 2, cls: 'pod-2' },
      { u: users[0], rank: 1, cls: 'pod-1' },
      { u: users[2], rank: 3, cls: 'pod-3' },
    ];

    return (
      <div className="podium">
        {slots.map(function(s) {
          return (
            <div key={s.rank} className={'pod-col ' + s.cls}
              onMouseEnter={function(){ document.body.classList.add('hov'); }}
              onMouseLeave={function(){ document.body.classList.remove('hov'); }}
              onClick={function(){ window.navigate('profile', { userId: s.u._id }); }}>
              {s.rank === 1 && (
                <React.Fragment>
                  <span className="pod-crown"><Icon name="crown" size={26} /></span>
                  <span className="pod-spark ps-a" /><span className="pod-spark ps-b" /><span className="pod-spark ps-c" />
                </React.Fragment>
              )}
              <div className="pod-avatar" style={{ background: GRADS[s.rank - 1] }}>{initials(s.u.name)}</div>
              <div className="pod-name">{s.u.name}</div>
              <div className="pod-rep"><CountUp value={s.u.reputation || 0} delay={400 + s.rank * 200} /></div>
              <div className="pod-pillar">
                <Medal rank={s.rank} size={30} />
              </div>
            </div>
          );
        })}
      </div>
    );
  }

  /* Daily reward chest — refills every day (Candy Crush economy).
     Claim id is date-stamped so CBGame's one-shot dedup naturally
     resets at midnight.                                            */
  function chestIdToday() {
    var d = new Date();
    return 'lb-chest-' + d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate();
  }
  function RewardChest() {
    var _claimed = useState(window.CBGame && window.CBGame.has(chestIdToday()));
    var claimed = _claimed[0], setClaimed = _claimed[1];
    var _opening = useState(false); var opening = _opening[0], setOpening = _opening[1];

    var onOpen = function(e) {
      if (claimed) {
        window.showUserToast && window.showUserToast('Daily reward claimed — come back tomorrow!', 'amber');
        return;
      }
      var r = e.currentTarget.getBoundingClientRect();
      setOpening(true);
      window.CBSfx && window.CBSfx.play('levelup');
      window.CBConfetti && window.CBConfetti.burst({ x: r.left + r.width / 2, y: r.top, count: 80, power: 11 });
      setTimeout(function() {
        window.CBGame && window.CBGame.award(chestIdToday(), 20, 'Daily Treasure');
        setClaimed(true);
        setOpening(false);
      }, 550);
    };

    return (
      <button className={'lb-chest' + (claimed ? ' claimed' : '') + (opening ? ' opening' : '')}
        aria-label={claimed ? 'Daily reward claimed — refills tomorrow' : 'Open your daily league reward'}
        title={claimed ? 'Refills tomorrow' : 'Open me!'}
        onMouseEnter={function(){ document.body.classList.add('hov'); }}
        onMouseLeave={function(){ document.body.classList.remove('hov'); }}
        onClick={onOpen}>
        <Icon name={claimed ? 'clock' : 'gift'} size={17} />
        <span>{claimed ? 'Back Tomorrow' : 'Daily Reward'}</span>
      </button>
    );
  }

  window.CBCountUp     = CountUp;
  window.CBMedal       = Medal;
  window.CBPodium      = Podium;
  window.CBRewardChest = RewardChest;
})();
