/* ═══════════════════════════════════════════════════════════
   TourGuide — spotlight walkthrough with pixel-accurate,
   responsive targeting. Tracks getBoundingClientRect live via
   ResizeObserver + scroll/resize + rAF so the mask always hugs
   the real component on any viewport.
   ═══════════════════════════════════════════════════════════ */
(function() {
  var useState  = React.useState;
  var useEffect = React.useEffect;
  var useRef    = React.useRef;
  var useCallback = React.useCallback;
  var useLayoutEffect = React.useLayoutEffect;

  var CARD_W = 320;
  var CARD_H_EST = 200;
  var VIEW_PAD = 12;

  function isUsable(el) {
    if (!el || !el.getBoundingClientRect) return false;
    var style = window.getComputedStyle(el);
    if (style.display === 'none' || style.visibility === 'hidden' || Number(style.opacity) === 0) {
      return false;
    }
    var r = el.getBoundingClientRect();
    return r.width >= 4 && r.height >= 4;
  }

  /** Visible area of rect inside the viewport. */
  function visibleArea(r) {
    var vw = window.innerWidth;
    var vh = window.innerHeight;
    var left = Math.max(0, r.left);
    var top = Math.max(0, r.top);
    var right = Math.min(vw, r.right);
    var bottom = Math.min(vh, r.bottom);
    var w = Math.max(0, right - left);
    var h = Math.max(0, bottom - top);
    return w * h;
  }

  function dataTourKey(selectorPart) {
    var m = /\[data-tour=["']([^"']+)["']\]/.exec(selectorPart || '');
    return m ? m[1] : null;
  }

  /** Prefer the most visible match; skip zero-size / hidden. */
  function bestMatch(selector) {
    if (!selector) return null;
    var parts = String(selector).split(',').map(function(s) { return s.trim(); }).filter(Boolean);
    var best = null;
    var bestScore = -1;

    for (var i = 0; i < parts.length; i++) {
      var wantKey = dataTourKey(parts[i]);
      var nodes;
      try { nodes = document.querySelectorAll(parts[i]); }
      catch (e) { continue; }
      for (var j = 0; j < nodes.length; j++) {
        var el = nodes[j];
        if (!isUsable(el)) continue;
        var r = el.getBoundingClientRect();
        var area = visibleArea(r);
        if (area <= 0) continue;
        var full = r.width * r.height;
        var ratio = full > 0 ? area / full : 0;
        // Prefer compact, fully-on-screen controls over huge wrappers.
        var sizePenalty = Math.max(0, Math.sqrt(full) - 280) * 2;
        var score = area + ratio * 6000 - sizePenalty;
        // Strong preference for the exact data-tour the step asked for.
        if (wantKey && el.getAttribute && el.getAttribute('data-tour') === wantKey) {
          score += 50000;
        } else if (el.hasAttribute && el.hasAttribute('data-tour')) {
          score += 1200;
        }
        // Prefer earlier selector parts (primary target first).
        score -= i * 400;
        // Prefer first matching sibling when scores are close (first card).
        score -= j * 8;
        if (score > bestScore) {
          bestScore = score;
          best = el;
        }
      }
    }
    return best;
  }

  function readRadius(el) {
    var cs = window.getComputedStyle(el);
    var tl = parseFloat(cs.borderTopLeftRadius) || 0;
    var tr = parseFloat(cs.borderTopRightRadius) || 0;
    var br = parseFloat(cs.borderBottomRightRadius) || 0;
    var bl = parseFloat(cs.borderBottomLeftRadius) || 0;
    if (cs.borderRadius && /999|50%|100%/.test(cs.borderRadius)) return 999;
    var max = Math.max(tl, tr, br, bl);
    if (!max) return 12;
    return Math.min(max + 2, 32);
  }

  /** Exact live rect of the target — do not shrink to viewport. */
  function measureEl(el) {
    var r = el.getBoundingClientRect();
    var minSide = Math.min(r.width, r.height);
    var maxSide = Math.max(r.width, r.height);
    // Tight pad on chips/buttons; slightly more on larger panels.
    var pad = Math.round(Math.min(10, Math.max(3, minSide * 0.04 + (maxSide > 420 ? 2 : 0))));

    return {
      top: r.top,
      left: r.left,
      width: Math.max(8, r.width),
      height: Math.max(8, r.height),
      pad: pad,
      radius: readRadius(el),
    };
  }

  function placeCard(box, preferred, cardH, cardW) {
    var vw = window.innerWidth;
    var vh = window.innerHeight;
    var CW = Math.min(cardW || CARD_W, vw - 24);
    var CH = cardH || CARD_H_EST;
    var gap = 12;
    var pad = box.pad || 6;
    var spotTop = box.top - pad;
    var spotBottom = box.top + box.height + pad;
    var spotLeft = box.left - pad;
    var spotRight = box.left + box.width + pad;
    var spotMidX = box.left + box.width / 2;

    var spaceBelow = vh - spotBottom;
    var spaceAbove = spotTop;
    var place = preferred || 'bottom';

    if (place.indexOf('bottom') === 0 && spaceBelow < CH + 16 && spaceAbove > spaceBelow) {
      place = place.replace('bottom', 'top');
    } else if (place.indexOf('top') === 0 && spaceAbove < CH + 16 && spaceBelow > spaceAbove) {
      place = place.replace('top', 'bottom');
    }

    var below = place.indexOf('top') !== 0;
    var top;
    if (below) {
      top = spotBottom + gap;
      if (top + CH > vh - VIEW_PAD) top = Math.max(VIEW_PAD, vh - CH - VIEW_PAD);
    } else {
      top = spotTop - gap - CH;
      if (top < VIEW_PAD) top = VIEW_PAD;
    }

    var left = spotMidX - CW / 2;
    if (place.indexOf('-end') > -1) left = spotRight - CW;
    if (place.indexOf('-start') > -1) left = spotLeft;
    left = Math.max(VIEW_PAD, Math.min(left, vw - CW - VIEW_PAD));

    // Avoid covering the spotlight when both sides are tight.
    var cardBottom = top + CH;
    var overlaps = !(cardBottom < spotTop || top > spotBottom);
    if (overlaps) {
      if (spaceBelow >= spaceAbove && spaceBelow >= CH * 0.55) {
        top = Math.min(spotBottom + gap, vh - CH - VIEW_PAD);
        below = true;
      } else if (spaceAbove >= CH * 0.55) {
        top = Math.max(VIEW_PAD, spotTop - gap - CH);
        below = false;
      }
    }

    return {
      style: {
        top: Math.round(top) + 'px',
        left: Math.round(left) + 'px',
        width: CW + 'px',
        maxWidth: 'calc(100vw - 24px)',
        transform: 'none',
      },
      place: below ? 'bottom' : 'top',
    };
  }

  function TourGuide(props) {
    var user = props.user;
    var tourId = props.tourId || '_welcome';
    var _i = useState(0);
    var i = _i[0], setI = _i[1];
    var _steps = useState([]);
    var steps = _steps[0], setSteps = _steps[1];
    var _box = useState(null);
    var box = _box[0], setBox = _box[1];
    var _card = useState({ style: { top: '50%', left: '50%', transform: 'translate(-50%,-50%)' } });
    var card = _card[0], setCard = _card[1];
    var targetRef = useRef(null);
    var cardElRef = useRef(null);
    var rafRef = useRef(0);

    useEffect(function() {
      setI(0);
      setBox(null);
      setSteps([]);
      targetRef.current = null;

      var timer = setTimeout(function() {
        var all = (window.CB_TOURS && window.CB_TOURS[tourId]) || [];
        var live = all.filter(function(s) {
          if (!s.target) return true;
          return Boolean(bestMatch(s.target));
        });
        if (!live.length && all.length) {
          live = all.filter(function(s) { return !s.target; });
          if (!live.length) live = [all[0]];
        }
        setSteps(live);
      }, tourId === '_welcome' ? 280 : 600);

      return function() { clearTimeout(timer); };
    }, [tourId]);

    var step = steps[i];

    var sync = useCallback(function() {
      if (!step) return;
      if (!step.target) {
        targetRef.current = null;
        setBox(null);
        setCard({ style: { top: '50%', left: '50%', transform: 'translate(-50%,-50%)' } });
        return;
      }
      var el = bestMatch(step.target);
      targetRef.current = el;
      if (!el) {
        setBox(null);
        return;
      }
      var m = measureEl(el);
      var ch = cardElRef.current ? cardElRef.current.offsetHeight : CARD_H_EST;
      var cw = cardElRef.current ? cardElRef.current.offsetWidth : CARD_W;
      setBox(m);
      setCard(placeCard(m, step.place, ch, cw));
    }, [step]);

    useLayoutEffect(function() {
      if (!step) return;

      var cancelled = false;
      function bringIntoViewThenMeasure() {
        var el = step.target ? bestMatch(step.target) : null;
        if (el) {
          try {
            el.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'auto' });
          } catch (e) {}
        }
        requestAnimationFrame(function() {
          requestAnimationFrame(function() {
            if (!cancelled) sync();
          });
        });
      }

      bringIntoViewThenMeasure();

      function onScrollOrResize() {
        if (rafRef.current) cancelAnimationFrame(rafRef.current);
        rafRef.current = requestAnimationFrame(function() {
          rafRef.current = 0;
          sync();
        });
      }

      window.addEventListener('resize', onScrollOrResize);
      window.addEventListener('orientationchange', onScrollOrResize);
      window.addEventListener('scroll', onScrollOrResize, true);
      if (window.visualViewport) {
        window.visualViewport.addEventListener('resize', onScrollOrResize);
        window.visualViewport.addEventListener('scroll', onScrollOrResize);
      }

      var ro = null;
      var el = step.target ? bestMatch(step.target) : null;
      if (el && typeof ResizeObserver !== 'undefined') {
        ro = new ResizeObserver(onScrollOrResize);
        ro.observe(el);
        if (el.parentElement) ro.observe(el.parentElement);
      }

      var pulse = setInterval(sync, 350);

      return function() {
        cancelled = true;
        clearInterval(pulse);
        if (rafRef.current) cancelAnimationFrame(rafRef.current);
        window.removeEventListener('resize', onScrollOrResize);
        window.removeEventListener('orientationchange', onScrollOrResize);
        window.removeEventListener('scroll', onScrollOrResize, true);
        if (window.visualViewport) {
          window.visualViewport.removeEventListener('resize', onScrollOrResize);
          window.visualViewport.removeEventListener('scroll', onScrollOrResize);
        }
        if (ro) ro.disconnect();
      };
    }, [step, sync]);

    function finish(how) {
      if (window.CBTour) {
        if (tourId === '_welcome') {
          window.CBTour.markSeen(user, how);
          window.CBTour.markScreenSeen('home', user);
        } else {
          window.CBTour.markScreenSeen(tourId, user);
        }
      }
      if (props.onClose) props.onClose(how);
    }

    function next() {
      if (!steps.length) return;
      if (i >= steps.length - 1) finish('done');
      else setI(i + 1);
    }

    useEffect(function() {
      if (!steps.length) return;
      function onKey(e) {
        if (e.key === 'Escape') finish('skipped');
      }
      document.addEventListener('keydown', onKey);
      return function() { document.removeEventListener('keydown', onKey); };
    }, [steps.length, tourId]);

    if (!steps.length || !step) return null;

    var label = tourId === '_welcome' ? 'Getting started' : 'Screen guide';
    var pad = box ? box.pad : 8;
    var radius = box ? (box.radius >= 999 ? 999 : box.radius + pad) : 12;

    return (
      <div className="tour-root" role="dialog" aria-modal="true" aria-label={label}>
        <div className="tour-block" />

        {box ? (
          <div
            className="tour-mask"
            data-tour-target={step.target || ''}
            style={{
              top: (box.top - pad) + 'px',
              left: (box.left - pad) + 'px',
              width: (box.width + pad * 2) + 'px',
              height: (box.height + pad * 2) + 'px',
              borderRadius: radius >= 999 ? '999px' : radius + 'px',
            }}
          />
        ) : (
          <div className="tour-mask-plain" />
        )}

        <div
          ref={cardElRef}
          className={'tour-card' + (card.place ? ' tour-card--' + card.place : '')}
          style={card.style}
        >
          <div className="tour-card-top">
            <span className="tour-step">Step {i + 1} of {steps.length}</span>
            <button type="button" className="tour-skip" onClick={function(){ finish('skipped'); }}>
              Skip tour
            </button>
          </div>

          <h3 className="tour-title">{step.title}</h3>
          <p className="tour-body">{step.body}</p>

          <div className="tour-dots">
            {steps.map(function(_, n) {
              return <span key={n} className={'tour-dot' + (n === i ? ' on' : '')} />;
            })}
          </div>

          <div className="tour-actions">
            {i > 0 && (
              <button type="button" className="tour-back" onClick={function(){ setI(i - 1); }}>
                Back
              </button>
            )}
            <button type="button" className="tour-next" onClick={next}>
              {i >= steps.length - 1
                ? (tourId === '_welcome' ? 'Start exploring' : 'Got it')
                : 'Next'}
            </button>
          </div>
        </div>
      </div>
    );
  }

  window.CBTourGuide = TourGuide;
})();
