"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __getProtoOf = Object.getPrototypeOf;
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));
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __async = (__this, __arguments, generator) => {
  return new Promise((resolve, reject) => {
    var fulfilled = (value) => {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    };
    var rejected = (value) => {
      try {
        step(generator.throw(value));
      } catch (e) {
        reject(e);
      }
    };
    var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
    step((generator = generator.apply(__this, __arguments)).next());
  });
};
var timeline_exports = {};
__export(timeline_exports, {
  default: () => timeline_default
});
module.exports = __toCommonJS(timeline_exports);
var import_buffer = __toESM(require("buffer"));
var import_browser = __toESM(require("process/browser"));
var import_console_browserify = __toESM(require("console-browserify"));
var buffer = {
  Buffer: import_buffer.default
};
var import_jsx_runtime = require("react/jsx-runtime");
var PIXI = __toESM(require("pixi.js-legacy"));
var import_react = require("react");
var import_store = require("./store");
var import_timeline = require("./timeline.css");
function cloneSprite(sprite) {
  const clonedSprite = new PIXI.Sprite(sprite.texture);
  clonedSprite.position.copyFrom(sprite.position);
  clonedSprite.scale.copyFrom(sprite.scale);
  clonedSprite.rotation = sprite.rotation;
  clonedSprite.alpha = sprite.alpha;
  clonedSprite.visible = sprite.visible;
  return clonedSprite;
}
const TimelineWidget = (props) => {
  var _a, _b, _c, _d;
  const titleBg = 16316664;
  const sideBg = 16777215;
  const gridTextColor = 0;
  const shotBorderColor = 7829367;
  const gridLineColor = 15066597;
  const gridHighlightColor = 12567770;
  const highlightMaskAlpha = 0.6;
  const timeContentFontSize = 20;
  const commonPadding = 12;
  const domRef = (0, import_react.useRef)(null);
  const app = (0, import_react.useMemo)(
    () => new PIXI.Application({
      backgroundColor: sideBg
    }),
    []
  );
  const gridsContainer = (0, import_react.useMemo)(() => new PIXI.Container(), []);
  const screenshotsContainer = (0, import_react.useMemo)(() => new PIXI.Container(), []);
  const highlightMaskContainer = (0, import_react.useMemo)(() => new PIXI.Container(), []);
  const containerUpdaterRef = (0, import_react.useRef)(
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    (_s, _e, _hs, _he) => {
    }
  );
  const indicatorContainer = (0, import_react.useMemo)(() => new PIXI.Container(), []);
  const allScreenshots = props.screenshots || [];
  const maxTime = allScreenshots.length > 0 ? allScreenshots[allScreenshots.length - 1].timeOffset : 0;
  const sizeRatio = 2;
  const timeTextTop = commonPadding;
  const timeTitleBottom = timeTextTop * 2 + timeContentFontSize;
  const hoverMaskColor = 14474460;
  const hoverMaskAlpha = 0.3;
  const closestScreenshotItemOnXY = (x, _y) => {
    let closestScreenshot;
    let closestIndex = -1;
    for (let i = 0; i < allScreenshots.length; i++) {
      const shot = allScreenshots[i];
      if (shot.x <= x) {
        closestScreenshot = allScreenshots[i];
        closestIndex = i;
      } else {
        break;
      }
    }
    return {
      closestScreenshot,
      closestIndex
    };
  };
  (0, import_react.useMemo)(() => {
    const { startMs, endMs } = props.highlightMask || {};
    const { startMs: hoverStartMs, endMs: hoverEndMs } = props.hoverMask || {};
    const fn = containerUpdaterRef.current;
    fn(startMs, endMs, hoverStartMs, hoverEndMs);
  }, [
    (_a = props.highlightMask) == null ? void 0 : _a.startMs,
    (_b = props.highlightMask) == null ? void 0 : _b.endMs,
    (_c = props.hoverMask) == null ? void 0 : _c.startMs,
    (_d = props.hoverMask) == null ? void 0 : _d.endMs
  ]);
  (0, import_react.useEffect)(() => {
    Promise.resolve(
      (() => __async(void 0, null, function* () {
        var _a2, _b2;
        if (!domRef.current) {
          return;
        }
        const { clientWidth, clientHeight } = domRef.current;
        const canvasWidth = clientWidth * sizeRatio;
        const canvasHeight = clientHeight * sizeRatio;
        let singleGridWidth = 100 * sizeRatio;
        let gridCount = Math.floor(canvasWidth / singleGridWidth);
        const stepCandidate = [
          50,
          100,
          200,
          300,
          500,
          1e3,
          2e3,
          3e3,
          5e3,
          6e3,
          8e3,
          9e3,
          1e4,
          2e4,
          3e4,
          4e4,
          6e4,
          9e4,
          12e3,
          3e5
        ];
        let timeStep = stepCandidate[0];
        for (let i = stepCandidate.length - 1; i >= 0; i--) {
          if (gridCount * stepCandidate[i] >= maxTime) {
            timeStep = stepCandidate[i];
          }
        }
        const gridRatio = maxTime / (gridCount * timeStep);
        if (gridRatio <= 0.8) {
          singleGridWidth = Math.floor(singleGridWidth * (1 / gridRatio) * 0.9);
          gridCount = Math.floor(canvasWidth / singleGridWidth);
        }
        const leftForTimeOffset = (timeOffset) => {
          return Math.floor(singleGridWidth * timeOffset / timeStep);
        };
        const timeOffsetForLeft = (left) => {
          return Math.floor(left * timeStep / singleGridWidth);
        };
        app.renderer.resize(canvasWidth, canvasHeight);
        if (!domRef.current) {
          app.destroy();
          return;
        }
        domRef.current.replaceChildren(
          app.view
        );
        const pixiTextForNumber = (num) => {
          const textContent = `${num}ms`;
          const text = new PIXI.Text(`${textContent}`, {
            fontSize: timeContentFontSize,
            fill: gridTextColor
          });
          return text;
        };
        gridsContainer.removeChildren();
        const titleBgSection = new PIXI.Graphics();
        titleBgSection.beginFill(titleBg);
        titleBgSection.drawRect(0, 0, canvasWidth, timeTitleBottom);
        titleBgSection.endFill();
        gridsContainer.addChild(titleBgSection);
        const titleBottomBorder = new PIXI.Graphics();
        titleBottomBorder.beginFill(gridLineColor);
        titleBottomBorder.drawRect(0, timeTitleBottom, canvasWidth, sizeRatio);
        titleBottomBorder.endFill();
        gridsContainer.addChild(titleBottomBorder);
        const gridHeight = canvasHeight;
        for (let i = 1; i <= gridCount; i++) {
          const gridLine = new PIXI.Graphics();
          const gridLineLeft = leftForTimeOffset(i * timeStep);
          gridLine.beginFill(gridLineColor);
          gridLine.drawRect(gridLineLeft, 0, sizeRatio, gridHeight);
          gridLine.endFill();
          gridsContainer.addChild(gridLine);
          const text = pixiTextForNumber(i * timeStep);
          const textLeft = gridLineLeft - text.width - commonPadding;
          text.x = textLeft;
          text.y = timeTextTop;
          gridsContainer.addChild(text);
        }
        app.stage.addChild(gridsContainer);
        if (!allScreenshots.length) {
          import_console_browserify.default.warn("No screenshots found");
          return;
        }
        const shotContainers = [];
        screenshotsContainer.removeChildren();
        const screenshotTop = timeTitleBottom + commonPadding * 1.5;
        const screenshotMaxHeight = canvasHeight - screenshotTop - commonPadding * 1.5;
        allScreenshots.forEach((screenshot, index) => {
          const container = new PIXI.Container();
          shotContainers.push(container);
          app.stage.addChild(container);
          const img = new Image();
          img.src = screenshot.img;
          img.onload = () => {
            const screenshotTexture = PIXI.Texture.from(img);
            const screenshotSprite = new PIXI.Sprite(screenshotTexture);
            const originalWidth = img.width;
            const originalHeight = img.height;
            const screenshotHeight = screenshotMaxHeight;
            const screenshotWidth = Math.floor(
              screenshotHeight / originalHeight * originalWidth
            );
            const screenshotX = leftForTimeOffset(screenshot.timeOffset);
            allScreenshots[index].x = screenshotX;
            allScreenshots[index].y = screenshotTop;
            allScreenshots[index].width = screenshotWidth;
            allScreenshots[index].height = screenshotMaxHeight;
            const border = new PIXI.Graphics();
            border.lineStyle(sizeRatio, shotBorderColor, 1);
            border.drawRect(
              screenshotX,
              screenshotTop,
              screenshotWidth,
              screenshotMaxHeight
            );
            border.endFill();
            container.addChild(border);
            screenshotSprite.x = screenshotX;
            screenshotSprite.y = screenshotTop;
            screenshotSprite.width = screenshotWidth;
            screenshotSprite.height = screenshotMaxHeight;
            container.addChild(screenshotSprite);
          };
        });
        const highlightMaskUpdater = (start, end, hoverStart, hoverEnd) => {
          highlightMaskContainer.removeChildren();
          const mask = (start2, end2, color, alpha) => {
            if (typeof start2 === "undefined" || typeof end2 === "undefined" || end2 === 0) {
              return;
            }
            const leftBorder = new PIXI.Graphics();
            leftBorder.beginFill(gridHighlightColor, 1);
            leftBorder.drawRect(
              leftForTimeOffset(start2),
              0,
              sizeRatio,
              canvasHeight
            );
            leftBorder.endFill();
            highlightMaskContainer.addChild(leftBorder);
            const rightBorder = new PIXI.Graphics();
            rightBorder.beginFill(gridHighlightColor, 1);
            rightBorder.drawRect(
              leftForTimeOffset(end2),
              0,
              sizeRatio,
              canvasHeight
            );
            rightBorder.endFill();
            highlightMaskContainer.addChild(rightBorder);
            const mask2 = new PIXI.Graphics();
            mask2.beginFill(gridHighlightColor, alpha);
            mask2.drawRect(
              leftForTimeOffset(start2),
              0,
              leftForTimeOffset(end2) - leftForTimeOffset(start2),
              canvasHeight
            );
            mask2.endFill();
            highlightMaskContainer.addChild(mask2);
          };
          mask(start, end, gridHighlightColor, highlightMaskAlpha);
          mask(hoverStart, hoverEnd, hoverMaskColor, hoverMaskAlpha);
        };
        highlightMaskUpdater(
          (_a2 = props.highlightMask) == null ? void 0 : _a2.startMs,
          (_b2 = props.highlightMask) == null ? void 0 : _b2.endMs,
          0,
          0
        );
        containerUpdaterRef.current = highlightMaskUpdater;
        app.stage.interactive = true;
        const onPointerMove = (event) => {
          var _a3, _b3;
          const x = event.offsetX * sizeRatio;
          const y = event.offsetY * sizeRatio;
          indicatorContainer.removeChildren();
          const { closestScreenshot, closestIndex } = closestScreenshotItemOnXY(
            x,
            y
          );
          if (closestIndex < 0) {
            (_a3 = props.onUnhighlight) == null ? void 0 : _a3.call(props);
            return;
          }
          const closestContainer = shotContainers[closestIndex];
          closestContainer.children.forEach((child) => {
            if (child instanceof PIXI.Sprite) {
              const newSpirit = new PIXI.Graphics();
              newSpirit.lineStyle(2, gridHighlightColor, 1);
              newSpirit.drawRect(
                x,
                // follow mouse
                closestScreenshot == null ? void 0 : closestScreenshot.y,
                closestScreenshot == null ? void 0 : closestScreenshot.width,
                closestScreenshot == null ? void 0 : closestScreenshot.height
              );
              newSpirit.endFill();
              indicatorContainer.addChild(newSpirit);
              const screenshotSpirit = cloneSprite(child);
              screenshotSpirit.x = x;
              indicatorContainer.addChild(screenshotSpirit);
            }
          });
          const indicator = new PIXI.Graphics();
          indicator.beginFill(gridHighlightColor, 1);
          indicator.drawRect(x - 1, 0, 3, canvasHeight);
          indicator.endFill();
          indicatorContainer.addChild(indicator);
          const text = pixiTextForNumber(timeOffsetForLeft(x));
          text.x = x + 5;
          text.y = timeTextTop;
          const textBg = new PIXI.Graphics();
          textBg.beginFill(titleBg, 1);
          textBg.drawRect(text.x, text.y, text.width + 10, text.height);
          textBg.endFill();
          indicatorContainer.addChild(textBg);
          indicatorContainer.addChild(text);
          (_b3 = props.onHighlight) == null ? void 0 : _b3.call(props, {
            mouseX: x / sizeRatio,
            mouseY: y / sizeRatio,
            item: closestScreenshot
          });
        };
        const onPointerOut = () => {
          var _a3;
          indicatorContainer.removeChildren();
          (_a3 = props.onUnhighlight) == null ? void 0 : _a3.call(props);
        };
        const onPointerTap = (event) => {
          var _a3;
          const x = event.offsetX * sizeRatio;
          const y = event.offsetY * sizeRatio;
          const { closestScreenshot } = closestScreenshotItemOnXY(x, y);
          if (closestScreenshot) {
            (_a3 = props.onTap) == null ? void 0 : _a3.call(props, closestScreenshot);
          }
        };
        app.stage.addChild(screenshotsContainer);
        app.stage.addChild(highlightMaskContainer);
        app.stage.addChild(indicatorContainer);
        const canvas = app.view;
        canvas.addEventListener("pointermove", onPointerMove);
        canvas.addEventListener("pointerout", onPointerOut);
        canvas.addEventListener("pointerdown", onPointerTap);
      }))()
    );
  }, []);
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "timeline-canvas-wrapper", ref: domRef });
};
const Timeline = () => {
  const allTasks = (0, import_store.useAllCurrentTasks)();
  const wrapper = (0, import_react.useRef)(null);
  const setActiveTask = (0, import_store.useExecutionDump)((store) => store.setActiveTask);
  const activeTask = (0, import_store.useExecutionDump)((store) => store.activeTask);
  const hoverTask = (0, import_store.useExecutionDump)((store) => store.hoverTask);
  const setHoverTask = (0, import_store.useExecutionDump)((store) => store.setHoverTask);
  const setHoverPreviewConfig = (0, import_store.useExecutionDump)(
    (store) => store.setHoverPreviewConfig
  );
  let startingTime = -1;
  let idCount = 1;
  const idTaskMap = {};
  const allScreenshots = allTasks.reduce((acc, current) => {
    var _a;
    const recorders = current.recorder || [];
    recorders.forEach((item) => {
      if (startingTime === -1 || startingTime > item.ts) {
        startingTime = item.ts;
      }
    });
    if (((_a = current.timing) == null ? void 0 : _a.start) && (startingTime === -1 || startingTime > current.timing.start)) {
      startingTime = current.timing.start;
    }
    const recorderItemWithId = recorders.map((item) => {
      const idStr = `id_${idCount++}`;
      idTaskMap[idStr] = current;
      return __spreadProps(__spreadValues({}, item), {
        id: idStr
      });
    });
    return acc.concat(recorderItemWithId || []);
  }, []).filter((item) => {
    return item.screenshot;
  }).map((recorderItem) => {
    return {
      id: recorderItem.id,
      img: recorderItem.screenshot,
      timeOffset: recorderItem.ts - startingTime
    };
  }).sort((a, b) => a.timeOffset - b.timeOffset);
  const itemOnTap = (item) => {
    const task = idTaskMap[item.id];
    if (task) {
      setActiveTask(task);
    }
  };
  const onHighlightItem = (param) => {
    var _a;
    const { mouseX, item } = param;
    const refBounding = (_a = wrapper.current) == null ? void 0 : _a.getBoundingClientRect();
    const task = idTaskMap[item.id];
    if (task) {
      setHoverTask(task, item.timeOffset + startingTime);
      setHoverPreviewConfig({
        x: mouseX + ((refBounding == null ? void 0 : refBounding.left) || 0),
        y: ((refBounding == null ? void 0 : refBounding.bottom) || 1) - 1
      });
    } else {
      setHoverTask(null);
      setHoverPreviewConfig(null);
    }
  };
  const unhighlight = () => {
    setHoverTask(null);
    setHoverPreviewConfig(null);
  };
  const maskConfigForTask = (task) => {
    var _a, _b;
    if (!task) {
      return void 0;
    }
    return ((_a = task.timing) == null ? void 0 : _a.start) && ((_b = task.timing) == null ? void 0 : _b.end) ? {
      startMs: task.timing.start - startingTime || 0,
      endMs: task.timing.end - startingTime || 0
    } : void 0;
  };
  const highlightMaskConfig = maskConfigForTask(activeTask);
  const hoverMaskConfig = maskConfigForTask(hoverTask);
  const itemIdList = allScreenshots.map((item) => item.id).join(",");
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "timeline-wrapper", ref: wrapper, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
    TimelineWidget,
    {
      screenshots: allScreenshots,
      onTap: itemOnTap,
      onHighlight: onHighlightItem,
      onUnhighlight: unhighlight,
      highlightMask: highlightMaskConfig,
      hoverMask: hoverMaskConfig
    },
    itemIdList
  ) });
};
var timeline_default = Timeline;
