import { jsx } from "react/jsx-runtime";
import { useStdin } from "ink";
import { createContext, useCallback, useContext, useEffect, useRef } from "react";
import { ESC } from "../utils/input.js";
import {
  parseMouseEvent,
  isIncompleteMouseSequence,
  enableMouseEvents,
  disableMouseEvents
} from "../utils/mouse.js";
const MAX_MOUSE_BUFFER_SIZE = 4096;
const MouseContext = createContext(void 0);
function useMouseContext() {
  const context = useContext(MouseContext);
  if (!context) {
    throw new Error("useMouseContext must be used within a MouseProvider");
  }
  return context;
}
function useMouse(handler, { isActive = true } = {}) {
  const { subscribe, unsubscribe } = useMouseContext();
  useEffect(() => {
    if (!isActive) {
      return;
    }
    subscribe(handler);
    return () => unsubscribe(handler);
  }, [isActive, handler, subscribe, unsubscribe]);
}
function MouseProvider({ children, mouseEventsEnabled = true }) {
  const { stdin } = useStdin();
  const subscribers = useRef(/* @__PURE__ */ new Set()).current;
  const subscribe = useCallback(
    (handler) => {
      subscribers.add(handler);
    },
    [subscribers]
  );
  const unsubscribe = useCallback(
    (handler) => {
      subscribers.delete(handler);
    },
    [subscribers]
  );
  useEffect(() => {
    if (!mouseEventsEnabled) {
      return;
    }
    enableMouseEvents();
    return () => {
      disableMouseEvents();
    };
  }, [mouseEventsEnabled]);
  useEffect(() => {
    if (!mouseEventsEnabled) {
      return;
    }
    let mouseBuffer = "";
    const broadcast = (event) => {
      for (const handler of subscribers) {
        if (handler(event) === true) {
          break;
        }
      }
    };
    const handleData = (data) => {
      mouseBuffer += typeof data === "string" ? data : data.toString("utf-8");
      if (mouseBuffer.length > MAX_MOUSE_BUFFER_SIZE) {
        mouseBuffer = mouseBuffer.slice(-MAX_MOUSE_BUFFER_SIZE);
      }
      while (mouseBuffer.length > 0) {
        const parsed = parseMouseEvent(mouseBuffer);
        if (parsed) {
          broadcast(parsed.event);
          mouseBuffer = mouseBuffer.slice(parsed.length);
          continue;
        }
        if (isIncompleteMouseSequence(mouseBuffer)) {
          break;
        }
        const nextEsc = mouseBuffer.indexOf(ESC, 1);
        if (nextEsc !== -1) {
          mouseBuffer = mouseBuffer.slice(nextEsc);
        } else {
          mouseBuffer = "";
          break;
        }
      }
    };
    stdin.on("data", handleData);
    return () => {
      stdin.removeListener("data", handleData);
    };
  }, [stdin, mouseEventsEnabled, subscribers]);
  return /* @__PURE__ */ jsx(MouseContext.Provider, { value: { subscribe, unsubscribe }, children });
}
export {
  MouseProvider,
  useMouse,
  useMouseContext
};
