"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var ScrollProvider_exports = {};
__export(ScrollProvider_exports, {
  ScrollProvider: () => ScrollProvider,
  useScrollable: () => useScrollable
});
module.exports = __toCommonJS(ScrollProvider_exports);
var import_jsx_runtime = require("react/jsx-runtime");
var import_react = require("react");
var import_ink = require("ink");
var import_MouseContext = require("./MouseContext.js");
const ScrollContext = (0, import_react.createContext)(null);
const findScrollableCandidates = (mouseEvent, scrollables) => {
  const candidates = [];
  for (const entry of scrollables.values()) {
    if (!entry.ref.current || !entry.hasFocus()) {
      continue;
    }
    const boundingBox = (0, import_ink.getBoundingBox)(entry.ref.current);
    if (!boundingBox) continue;
    const { x, y, width, height } = boundingBox;
    const isInside = mouseEvent.col >= x && mouseEvent.col < x + width + 1 && mouseEvent.row >= y && mouseEvent.row < y + height;
    if (isInside) {
      candidates.push({ ...entry, area: width * height });
    }
  }
  candidates.sort((a, b) => a.area - b.area);
  return candidates;
};
function useDragDetection(onSelectionAttempt) {
  const isLeftButtonDownRef = (0, import_react.useRef)(false);
  const selectionHintShownRef = (0, import_react.useRef)(false);
  const handleDragDetection = (0, import_react.useCallback)(
    (event) => {
      if (event.name === "left-press") {
        isLeftButtonDownRef.current = true;
        selectionHintShownRef.current = false;
      } else if (event.name === "left-release") {
        isLeftButtonDownRef.current = false;
      } else if (event.name === "move" && isLeftButtonDownRef.current) {
        if (!selectionHintShownRef.current && onSelectionAttempt) {
          selectionHintShownRef.current = true;
          onSelectionAttempt();
        }
      }
    },
    [onSelectionAttempt]
  );
  return handleDragDetection;
}
const ScrollProvider = ({ children, onSelectionAttempt }) => {
  const [scrollables, setScrollables] = (0, import_react.useState)(/* @__PURE__ */ new Map());
  const handleDragDetection = useDragDetection(onSelectionAttempt);
  const register = (0, import_react.useCallback)((entry) => {
    setScrollables((prev) => new Map(prev).set(entry.id, entry));
  }, []);
  const unregister = (0, import_react.useCallback)((id) => {
    setScrollables((prev) => {
      const next = new Map(prev);
      next.delete(id);
      return next;
    });
  }, []);
  const scrollablesRef = (0, import_react.useRef)(scrollables);
  (0, import_react.useEffect)(() => {
    scrollablesRef.current = scrollables;
  }, [scrollables]);
  const pendingScrollsRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
  const flushScheduledRef = (0, import_react.useRef)(false);
  const scheduleFlush = (0, import_react.useCallback)(() => {
    if (!flushScheduledRef.current) {
      flushScheduledRef.current = true;
      setTimeout(() => {
        flushScheduledRef.current = false;
        for (const [id, delta] of pendingScrollsRef.current.entries()) {
          const entry = scrollablesRef.current.get(id);
          if (entry) {
            entry.scrollBy(delta);
          }
        }
        pendingScrollsRef.current.clear();
      }, 0);
    }
  }, []);
  const handleScroll = (0, import_react.useCallback)(
    (direction, mouseEvent) => {
      const delta = direction === "up" ? -1 : 1;
      const candidates = findScrollableCandidates(mouseEvent, scrollablesRef.current);
      for (const candidate of candidates) {
        const { scrollTop, scrollHeight, innerHeight } = candidate.getScrollState();
        const pendingDelta = pendingScrollsRef.current.get(candidate.id) || 0;
        const effectiveScrollTop = scrollTop + pendingDelta;
        const canScrollUp = effectiveScrollTop > 1e-3;
        const canScrollDown = effectiveScrollTop < scrollHeight - innerHeight - 1e-3;
        if (direction === "up" && canScrollUp) {
          pendingScrollsRef.current.set(candidate.id, pendingDelta + delta);
          scheduleFlush();
          return true;
        }
        if (direction === "down" && canScrollDown) {
          pendingScrollsRef.current.set(candidate.id, pendingDelta + delta);
          scheduleFlush();
          return true;
        }
      }
      return false;
    },
    [scheduleFlush]
  );
  (0, import_MouseContext.useMouse)(
    (0, import_react.useCallback)(
      (event) => {
        if (event.name === "scroll-up") {
          return handleScroll("up", event);
        } else if (event.name === "scroll-down") {
          return handleScroll("down", event);
        }
        handleDragDetection(event);
        return false;
      },
      [handleScroll, handleDragDetection]
    ),
    { isActive: true }
  );
  const contextValue = (0, import_react.useMemo)(() => ({ register, unregister }), [register, unregister]);
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollContext.Provider, { value: contextValue, children });
};
let nextId = 0;
const useScrollable = (entry, isActive) => {
  const context = (0, import_react.useContext)(ScrollContext);
  if (!context) {
    throw new Error("useScrollable must be used within a ScrollProvider");
  }
  const [id] = (0, import_react.useState)(() => `scrollable-${nextId++}`);
  const entryRef = (0, import_react.useRef)(entry);
  entryRef.current = entry;
  (0, import_react.useEffect)(() => {
    if (isActive) {
      const registrationEntry = {
        id,
        ref: entryRef.current.ref,
        getScrollState: () => entryRef.current.getScrollState(),
        scrollBy: (delta) => entryRef.current.scrollBy(delta),
        hasFocus: () => entryRef.current.hasFocus()
      };
      if (entryRef.current.scrollTo) {
        registrationEntry.scrollTo = (scrollTop, duration) => {
          entryRef.current.scrollTo?.(scrollTop, duration);
        };
      }
      context.register(registrationEntry);
      return () => {
        context.unregister(id);
      };
    }
    return;
  }, [context, id, isActive]);
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  ScrollProvider,
  useScrollable
});
