/* Hover-details card. Shows full event metadata on hover; "Edit" button
   opens the right-side slide-over via the existing openEvent callback.

   Usage: spread `triggerProps` on any element you want to be hoverable, and
   render `portal` once anywhere in your tree. The portal renders via
   ReactDOM.createPortal to document.body so it doesn't get clipped by parent
   overflow:hidden.
*/

const { useState: useStateH, useRef: useRefH, useEffect: useEffectH } = React;
const UH = window.mcalUtils;

/* Singleton "active hover" registry. Only ONE card can be visible at any time.
   When a new pill takes over, all other cards hide immediately — no flicker. */
let _activeId = 0;
const _listeners = new Set();
function _setActive(id) {
  _activeId = id;
  _listeners.forEach(fn => fn(id));
}
let _idCounter = 1;
function _nextId() { return _idCounter++; }

/* Global hover-disabled flag. Set by App when the right detail slide-over is
   open, so hovering pills doesn't spawn a competing card. */
let _hoverDisabled = false;
function setHoverDisabled(v) {
  _hoverDisabled = !!v;
  if (_hoverDisabled) _setActive(0);  // force any visible card to close
}
window.mcalSetHoverDisabled = setHoverDisabled;

function useHoverCard(event, options, onEdit, subtask) {
  const myIdRef = useRefH(null);
  if (myIdRef.current == null) myIdRef.current = _nextId();
  const [show, setShow] = useStateH(false);
  const [coords, setCoords] = useStateH({ x: 0, y: 0, fromLeft: true });
  const hideTimer = useRefH(null);
  const triggerRef = useRefH(null);
  const cardRef = useRefH(null);

  // Subscribe to singleton — hide immediately when another pill takes over.
  useEffectH(() => {
    const onActive = id => {
      if (id !== myIdRef.current) {
        clearTimeout(hideTimer.current);
        setShow(false);
      }
    };
    _listeners.add(onActive);
    return () => { _listeners.delete(onActive); };
  }, []);

  const recompute = () => {
    const el = triggerRef.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const cardW = 380;
    // Use measured card height when available, otherwise estimate
    const cardH = (cardRef.current && cardRef.current.offsetHeight) || 460;
    const margin = 12;
    let x = r.right + 10;
    let fromLeft = true;
    if (x + cardW + margin > window.innerWidth) {
      x = r.left - cardW - 10;
      fromLeft = false;
    }
    if (x < 8) x = 8;
    let y = r.top;
    // Clamp so the full card fits within viewport, with margin top + bottom
    const maxY = window.innerHeight - cardH - margin;
    if (y > maxY) y = maxY;
    if (y < margin) y = margin;
    setCoords({ x, y, fromLeft });
  };

  // Re-measure after card mounts so we use real height (avoids bottom clip)
  useEffectH(() => {
    if (!show) return;
    const raf = requestAnimationFrame(() => recompute());
    return () => cancelAnimationFrame(raf);
  }, [show]);

  // Reposition on resize while visible
  useEffectH(() => {
    if (!show) return;
    const onR = () => recompute();
    window.addEventListener('resize', onR);
    window.addEventListener('scroll', onR, true);
    return () => {
      window.removeEventListener('resize', onR);
      window.removeEventListener('scroll', onR, true);
    };
  }, [show]);

  const onEnter = e => {
    if (_hoverDisabled) return;
    // Don't spawn hover cards on touch / coarse-pointer devices — mouseenter
    // fires on tap which is annoying and clips around panel close behaviors.
    if (typeof window !== 'undefined' && window.matchMedia) {
      if (window.matchMedia('(hover: none), (pointer: coarse)').matches) return;
    }
    clearTimeout(hideTimer.current);
    triggerRef.current = e.currentTarget;
    _setActive(myIdRef.current);
    recompute();
    setShow(true);
  };
  const onLeave = () => {
    hideTimer.current = setTimeout(() => {
      setShow(false);
      if (_activeId === myIdRef.current) _activeId = 0;
    }, 100);
  };
  const cancelHide = () => clearTimeout(hideTimer.current);

  const triggerProps = {
    onMouseEnter: onEnter,
    onMouseLeave: onLeave,
  };

  const portal = show && event
    ? ReactDOM.createPortal(
        <EventHoverCard
          event={event}
          subtask={subtask}
          options={options}
          coords={coords}
          cardRef={cardRef}
          onEdit={onEdit}
          onMouseEnter={cancelHide}
          onMouseLeave={onLeave}
        />,
        document.body
      )
    : null;

  return { triggerProps, portal };
}

function EventHoverCard({ event, subtask, options, coords, cardRef, onEdit, onMouseEnter, onMouseLeave }) {
  // Effective values for sub-tasks fall back to the parent event when unset.
  const ef = key => subtask ? (subtask[key] !== undefined && subtask[key] !== null && subtask[key] !== '' ? subtask[key] : event[key]) : event[key];
  const cat = options.categories.find(c => c.id === ef('category'));
  const channel = options.channels.find(c => c.id === ef('channel'));
  const parentOwners = UH.ownerIdsOf(event);
  const ownerIds = subtask ? UH.ownerIdsOf(subtask, parentOwners) : parentOwners;
  const owners = ownerIds
    .map(id => (options.owners || []).find(o => o.id === id))
    .filter(Boolean);
  const product = options.products.find(p => p.id === ef('product'));
  const subId = ef('subproduct');
  const app = subId
    ? (options.apps || options.subproducts || []).find(a => a.id === subId)
    : null;
  const format = options.formats.find(f => f.id === ef('format'));
  const stageId = subtask ? (subtask.stage || 'ideation') : event.stage;
  const StageChip = window.mcalStageChip;
  const isPastDue = !subtask && !event.tbd && event.end < (window.MCAL_TODAY || UH.todayISO()) && UH.stageOrder(options, event.stage) < 2;

  return (
    <div
      ref={cardRef}
      className="hover-card"
      style={{ left: coords.x, top: coords.y }}
      onMouseEnter={onMouseEnter}
      onMouseLeave={onMouseLeave}
    >
      <div className="hc-head">
        <div className="hc-tags">
          {subtask && <span className="hc-tag" style={{ color: 'var(--fg-2)' }}>SUB-TASK</span>}
          {cat && <span className="hc-tag" style={{ background: cat.color, color: '#19191A', borderColor: cat.color }}>{cat.name}</span>}
          {!subtask && event.tbd && <span className="hc-tag" style={{ color: 'var(--danger)', borderColor: 'var(--danger)' }}>TBD</span>}
          {!subtask && event.needsReview && event.stage !== 'done' && (
            <span className="hc-tag" style={{ background: 'var(--needs-review, #9B6FBC)', color: '#fff', borderColor: 'var(--needs-review, #9B6FBC)' }}>NEEDS REVIEW</span>
          )}
          {subtask && subtask.needsReview && (subtask.stage || 'ideation') !== 'done' && (
            <span className="hc-tag" style={{ background: 'var(--needs-review, #9B6FBC)', color: '#fff', borderColor: 'var(--needs-review, #9B6FBC)' }}>NEEDS REVIEW</span>
          )}
          {isPastDue && (
            <span className="hc-tag" style={{ background: 'var(--danger)', color: '#fff', borderColor: 'var(--danger)', display: 'inline-flex', alignItems: 'center', gap: 4 }}>
              <svg width="10" height="10" viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                <path d="M6 2v4.5" />
                <circle cx="6" cy="9" r="0.6" fill="currentColor" stroke="none" />
              </svg>
              PAST DUE
            </span>
          )}
        </div>
        <div className="hc-title">{
          subtask
            ? (window.mcalRichText ? window.mcalRichText(subtask.title, options) : subtask.title)
            : (event.title ? (window.mcalRichText ? window.mcalRichText(event.title, options) : event.title) : 'Untitled event')
        }</div>
        {subtask && (
          <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10.5, letterSpacing: '0.04em', color: 'var(--fg-3)', marginBottom: 4 }}>
            ↳ part of <span style={{ color: 'var(--fg)' }}>{window.mcalRichText ? window.mcalRichText(event.title, options) : event.title}</span>
          </div>
        )}
        <div className="hc-date">
          {subtask
            ? UH.longDate(subtask.date)
            : <>{UH.longDate(event.start)}{event.end !== event.start && <><span className="dr-arrow">→</span>{UH.longDate(event.end)}<span className="hc-days"> · {UH.diffDays(event.start, event.end) + 1} days</span></>}</>}
        </div>
      </div>

      <div className="hc-rows">
        {channel && <HCRow label="Channel" value={channel.name} color={channel.color} />}
        {owners.length === 1 && <HCRow label="Owner" value={owners[0].name} color={owners[0].color} />}
        {owners.length > 1 && (
          <div className="hc-row">
            <span className="hc-lbl">Owners</span>
            <span className="hc-val" style={{ display: 'flex', flexWrap: 'wrap', gap: '4px 12px', alignItems: 'center' }}>
              {owners.map(o => (
                <span key={o.id} style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                  <span className="hc-swatch" style={{ background: o.color }}></span>
                  <span>{o.name}</span>
                </span>
              ))}
            </span>
          </div>
        )}
        {product && <HCRow label="Product" value={product.name} color={product.color} />}
        {app && <HCRow label={cat ? `${cat.name} App` : 'App'} value={app.name} color={app.color} />}
        {format && <HCRow label="Format" value={format.name} />}
        <div className="hc-row">
          <span className="hc-lbl">Stage</span>
          <span className="hc-val"><StageChip stageId={stageId} options={options} bigger full /></span>
        </div>
      </div>

      {!subtask && (event.subtasks || []).length > 0 && (
        <div className="hc-section">
          <div className="hc-section-h">Sub-tasks · {event.subtasks.length}</div>
          <div className="hc-subs">
            {event.subtasks.slice(0, 6).map(st => {
              const stStage = UH.stageById(options, st.stage || 'ideation');
              return (
                <div key={st.id} className="hc-sub">
                  <span className="hc-sub-glyph" style={{ color: stStage.color }}>{stStage.glyph}</span>
                  <span className="hc-sub-date">{UH.shortDate(st.date)}</span>
                  <span className="hc-sub-title">{window.mcalRichText ? window.mcalRichText(st.title, options) : st.title}</span>
                </div>
              );
            })}
            {event.subtasks.length > 6 && (
              <div className="hc-sub-more">+{event.subtasks.length - 6} more…</div>
            )}
          </div>
        </div>
      )}

      {/* Notes / URL / media — show for both events and sub-tasks. For
          sub-tasks we read from the sub-task's own fields (they're not
          inherited from the parent for content). result_url stays parent-
          only since it's an event-level "what shipped" marker. */}
      {(() => {
        const item = subtask || event;
        return (
          <>
            {item.notes && (
              <div className="hc-section">
                <div className="hc-section-h">Notes</div>
                <div className="hc-notes">{window.mcalRichText ? window.mcalRichText(item.notes, options) : item.notes}</div>
              </div>
            )}
            {item.url && window.mcalMediaCard && (
              <div className="hc-section">
                <div className="hc-section-h">Primary link</div>
                <div className="hc-cards">
                  <window.mcalMediaCard url={item.url.startsWith('http') ? item.url : 'https://' + item.url} compact />
                </div>
              </div>
            )}
            {!subtask && event.result_url && window.mcalMediaCard && (
              <div className="hc-section">
                <div className="hc-section-h">Result · what shipped</div>
                <div className="hc-cards">
                  <window.mcalMediaCard url={event.result_url.startsWith('http') ? event.result_url : 'https://' + event.result_url} compact />
                </div>
              </div>
            )}
            {(item.media || []).length > 0 && (
              <div className="hc-section">
                <div className="hc-section-h">Media · {item.media.length} {item.media.length === 1 ? 'link' : 'links'}</div>
                <div className="hc-cards">
                  {item.media.slice(0, 4).map(url => (
                    window.mcalMediaCard
                      ? <window.mcalMediaCard key={url} url={url} compact />
                      : null
                  ))}
                  {item.media.length > 4 && <div className="hc-sub-more">+{item.media.length - 4} more…</div>}
                </div>
              </div>
            )}
          </>
        );
      })()}
    </div>
  );
}

function HCRow({ label, value, color }) {
  return (
    <div className="hc-row">
      <span className="hc-lbl">{label}</span>
      <span className="hc-val">
        {color && <span className="hc-swatch" style={{ background: color }}></span>}
        <span>{value}</span>
      </span>
    </div>
  );
}

window.mcalHoverCard = { useHoverCard, HoverWrap };

function HoverWrap({ event, options, onEdit, subtask, children }) {
  const { triggerProps, portal } = useHoverCard(event, options, onEdit, subtask);
  // Children can be a function (triggerProps => ReactNode) or a React element.
  const node = typeof children === 'function'
    ? children(triggerProps)
    : React.cloneElement(children, {
        ...triggerProps,
        onMouseEnter: (e) => {
          triggerProps.onMouseEnter(e);
          if (children.props.onMouseEnter) children.props.onMouseEnter(e);
        },
        onMouseLeave: (e) => {
          triggerProps.onMouseLeave(e);
          if (children.props.onMouseLeave) children.props.onMouseLeave(e);
        },
      });
  return <>{node}{portal}</>;
}
