'use strict';

var React = require('react');
var core = require('@linaria/core');
var xterm = require('@xterm/xterm');
var addonSearch = require('@xterm/addon-search');
var addonFit = require('@xterm/addon-fit');
var iconsReact = require('@cloudtower/icons-react');
var useParrotTranslation = require('../../hooks/useParrotTranslation.js');
var LogView_style = require('./LogView.style.js');
var LogView_utils = require('./LogView.utils.js');
var color = require('../../styles/token/color.js');
var index = require('../../coreX/Show/index.js');
var SearchInput = require('../SearchInput/SearchInput.js');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var React__default = /*#__PURE__*/_interopDefault(React);

var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    }
  return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
const useLogViewEventSource = ({
  enabled,
  terminal,
  options,
  setHasData,
  setEventSourceError
}) => {
  const reconnectFnRef = React.useRef(null);
  const optionsRef = React.useRef(options);
  optionsRef.current = options;
  const {
    url,
    closeEventName,
    errorEventName,
    messageEventName,
    openEventName,
    reconnect,
    reconnectWait
  } = options;
  React.useEffect(() => {
    var _a, _b;
    let closeEventSource;
    if (!enabled) {
      setEventSourceError(null);
      reconnectFnRef.current = null;
      return;
    }
    if (!terminal)
      return;
    const setupEventSource = () => {
      var _a2;
      closeEventSource == null ? void 0 : closeEventSource();
      setEventSourceError(null);
      closeEventSource = LogView_utils.eventsource(
        ((_a2 = optionsRef.current) == null ? void 0 : _a2.url) || "",
        __spreadProps(__spreadValues({}, optionsRef.current), {
          onOpen: (...props) => {
            var _a3, _b2;
            (_b2 = (_a3 = optionsRef.current) == null ? void 0 : _a3.onOpen) == null ? void 0 : _b2.call(_a3, ...props);
          },
          onClose: (...props) => {
            var _a3, _b2;
            (_b2 = (_a3 = optionsRef.current) == null ? void 0 : _a3.onClose) == null ? void 0 : _b2.call(_a3, ...props);
          },
          onMessage: (...props) => {
            var _a3, _b2;
            (_b2 = (_a3 = optionsRef.current) == null ? void 0 : _a3.onMessage) == null ? void 0 : _b2.call(_a3, ...props);
            setEventSourceError(null);
          },
          // 注入数据检测
          formatMessage: (data) => {
            var _a3;
            const formatMessage = (_a3 = optionsRef.current) == null ? void 0 : _a3.formatMessage;
            const message = formatMessage ? formatMessage(data) : data;
            if (typeof message === "string" && message.length > 0)
              setHasData(true);
            return message;
          },
          // 增强错误处理
          onError: (err) => {
            var _a3, _b2;
            setEventSourceError(err);
            (_b2 = (_a3 = optionsRef.current) == null ? void 0 : _a3.onError) == null ? void 0 : _b2.call(_a3, err);
          }
        }),
        terminal
      );
    };
    reconnectFnRef.current = setupEventSource;
    (_b = (_a = optionsRef.current) == null ? void 0 : _a.onSetupEventSource) == null ? void 0 : _b.call(_a, {
      setupFn: setupEventSource
    });
    setupEventSource();
    return () => {
      closeEventSource == null ? void 0 : closeEventSource();
      if (reconnectFnRef.current === setupEventSource)
        reconnectFnRef.current = null;
    };
  }, [
    enabled,
    terminal,
    url,
    closeEventName,
    errorEventName,
    messageEventName,
    openEventName,
    reconnect,
    reconnectWait
  ]);
  return {
    reconnectFnRef
  };
};
const LogView = ({
  className,
  content = "",
  showSearch = true,
  eventSource = false,
  eventSourceOptions = {},
  rows = 23,
  scrollback = 9999999,
  searchHighlightLimit = 1e3,
  enableKeyboardShortcuts = true,
  emptyRenderer,
  errorRenderer,
  searchInputProps
}) => {
  const { t } = useParrotTranslation();
  const terminalContainerRef = React.useRef(null);
  const terminalRef = React.useRef({ enableKeyboardShortcuts });
  terminalRef.current.enableKeyboardShortcuts = enableKeyboardShortcuts;
  const [readyTerminal, setReadyTerminal] = React.useState(null);
  const [hasData, setHasData] = React.useState(!!content);
  const [searchCount, setSearchCount] = React.useState(0);
  const [current, setCurrent] = React.useState(1);
  const [eventSourceError, setEventSourceError] = React.useState(null);
  React.useEffect(() => {
    var _a;
    if (!terminalContainerRef.current)
      return;
    const terminal = new xterm.Terminal({
      fontFamily: "Roboto Mono, monospace",
      fontSize: 12,
      scrollOnUserInput: false,
      lineHeight: 1.5,
      theme: {
        background: "#00122E",
        foreground: "#FFFFFF",
        cursor: "#FFFFFF"
      },
      rows,
      convertEol: true,
      cursorBlink: false,
      disableStdin: true,
      allowProposedApi: true,
      scrollback
    });
    terminal.attachCustomKeyEventHandler((event) => {
      if (!terminalRef.current.enableKeyboardShortcuts)
        return true;
      const target = event.target;
      const isXtermEvent = target instanceof HTMLElement && target.closest(".xterm");
      if (!isXtermEvent)
        return true;
      const shortcuts = LogView_utils.isMacOS() ? LogView_utils.customShortcutsForMac : LogView_utils.customShortcutsForWin;
      if (event.type === "keydown" && LogView_utils.isCustomKeyboardAction(event, shortcuts)) {
        event.stopPropagation();
        event.preventDefault();
        const keyActions = {
          arrowup: () => LogView_utils.scrollLines("up", terminal),
          arrowdown: () => LogView_utils.scrollLines("down", terminal),
          pageup: () => LogView_utils.scrollPages("up", terminal),
          pagedown: () => LogView_utils.scrollPages("down", terminal),
          c: () => LogView_utils.copySelectLines(terminal),
          a: () => LogView_utils.selectAll(terminal)
        };
        const action = keyActions[event.key.toLowerCase()];
        if (action)
          action();
        return false;
      }
      return true;
    });
    const search = new addonSearch.SearchAddon({
      highlightLimit: searchHighlightLimit
    });
    terminal.loadAddon(search);
    const fit = new addonFit.FitAddon();
    terminal.loadAddon(fit);
    terminalRef.current = {
      searchAddon: search,
      fitAddon: fit
    };
    terminal.open(terminalContainerRef.current);
    setReadyTerminal(terminal);
    try {
      fit.fit();
    } catch (e) {
      console.error("Error fitting terminal:", e);
    }
    if (content) {
      terminal.write(content);
      terminalRef.current.previousContent = content;
      setHasData(true);
    } else {
      setHasData(false);
    }
    (_a = terminalRef.current.searchAddon) == null ? void 0 : _a.onDidChangeResults(
      ({ resultCount, resultIndex }) => {
        setSearchCount(resultCount);
        setCurrent(resultIndex + 1);
      }
    );
    return () => {
      terminal.dispose();
    };
  }, [rows, scrollback, searchHighlightLimit]);
  React.useEffect(() => {
    if (!readyTerminal || !terminalContainerRef.current)
      return;
    const fitTerminal = () => {
      var _a;
      if ((_a = terminalRef.current) == null ? void 0 : _a.fitAddon)
        try {
          terminalRef.current.fitAddon.fit();
        } catch (e) {
          console.error("Error resizing terminal:", e);
        }
    };
    if (typeof ResizeObserver !== "undefined") {
      const resizeObserver = new ResizeObserver(fitTerminal);
      resizeObserver.observe(terminalContainerRef.current);
      return () => {
        resizeObserver.disconnect();
      };
    }
    window.addEventListener("resize", fitTerminal);
    return () => {
      window.removeEventListener("resize", fitTerminal);
    };
  }, [readyTerminal]);
  React.useEffect(() => {
    var _a;
    if (!readyTerminal)
      return;
    if (content) {
      const previousContent = (_a = terminalRef.current) == null ? void 0 : _a.previousContent;
      if (content !== previousContent) {
        if (previousContent && content.startsWith(previousContent)) {
          const appendedContent = content.slice(previousContent.length);
          if (appendedContent)
            readyTerminal.write(appendedContent);
        } else {
          readyTerminal.clear();
          readyTerminal.write(content);
        }
      }
      terminalRef.current = __spreadProps(__spreadValues({}, terminalRef.current), {
        previousContent: content
      });
      setHasData(true);
    } else if (!eventSource) {
      readyTerminal.clear();
      terminalRef.current = __spreadProps(__spreadValues({}, terminalRef.current), { previousContent: "" });
      setHasData(false);
    }
  }, [readyTerminal, content, eventSource]);
  const { searchNext, searchPrevious } = React.useMemo(() => {
    const searchOptions = {
      caseSensitive: false,
      decorations: {
        activeMatchColorOverviewRuler: "#000000",
        matchOverviewRuler: "#000000",
        activeMatchBackground: color.Color.chart.yellow["yellow-5"],
        matchBackground: color.Color.chart.yellow["yellow-1"]
      }
    };
    return {
      searchNext: (search) => {
        var _a, _b;
        (_b = (_a = terminalRef.current) == null ? void 0 : _a.searchAddon) == null ? void 0 : _b.findNext(search || "", searchOptions);
      },
      searchPrevious: (search) => {
        var _a, _b;
        (_b = (_a = terminalRef.current) == null ? void 0 : _a.searchAddon) == null ? void 0 : _b.findPrevious(
          search || "",
          searchOptions
        );
      }
    };
  }, []);
  const { reconnectFnRef: eventSourceReconnectFnRef } = useLogViewEventSource({
    enabled: eventSource,
    terminal: readyTerminal,
    options: eventSourceOptions,
    setHasData,
    setEventSourceError
  });
  const reconnect = React.useCallback(() => {
    if (eventSourceReconnectFnRef.current) {
      setEventSourceError(null);
      eventSourceReconnectFnRef.current();
    }
  }, []);
  const renderCustomContent = () => {
    if (eventSourceError && errorRenderer && readyTerminal)
      return /* @__PURE__ */ React__default.default.createElement(LogView_style.CustomContentOverlay, null, errorRenderer(readyTerminal, eventSourceError, reconnect));
    if (!hasData && emptyRenderer && readyTerminal)
      return /* @__PURE__ */ React__default.default.createElement(LogView_style.CustomContentOverlay, null, emptyRenderer(readyTerminal));
    return null;
  };
  return /* @__PURE__ */ React__default.default.createElement(LogView_style.LogViewContainer, { className: core.cx("log-view-container", className) }, /* @__PURE__ */ React__default.default.createElement(LogView_style.LogViewInnerContaier, { className: "log-view-inner-container" }, /* @__PURE__ */ React__default.default.createElement(index.Show, { condition: showSearch }, /* @__PURE__ */ React__default.default.createElement(
    SearchInput.SearchInput,
    __spreadValues({
      type: "text",
      className: LogView_style.SearchInputStyle,
      width: "100%",
      debounceWait: 100,
      placeholder: t("common.search_log"),
      searchIcon: iconsReact.Search16OntintIcon,
      prefixIcon: iconsReact.ArrowChevronUp16OntintIcon,
      prefixHoverIcon: iconsReact.ArrowChevronUp16BlueIcon,
      nextIcon: iconsReact.ArrowChevronDown16OntintIcon,
      nextHoverIcon: iconsReact.ArrowChevronDown16BlueIcon,
      clearIcon: iconsReact.XmarkCloseCircleFill16OntintIcon,
      clearHoverIcon: iconsReact.XmarkCloseCircleFill16OntintLightIcon,
      total: searchCount,
      current,
      onChange: searchNext,
      onSearchNext: searchNext,
      onSearchPrev: searchPrevious
    }, searchInputProps)
  )), /* @__PURE__ */ React__default.default.createElement(LogView_style.LogTerminal, { className: "log-terminal", ref: terminalContainerRef }, renderCustomContent())));
};

exports.LogView = LogView;
