// src/common/utils.ts
import { elementByPositionWithElementInfo } from "@midscene_spp/core/ai-model";
import { uploadTestInfoToServer } from "@midscene_spp/core/utils";
import { MIDSCENE_REPORT_TAG_NAME, getAIConfig } from "@midscene_spp/shared/env";
import {
  generateElementByPosition,
  getNodeFromCacheList,
  traverseTree,
  treeToList
} from "@midscene_spp/shared/extractor";
import { resizeImgBase64 } from "@midscene_spp/shared/img";
import { assert, logMsg, uuid } from "@midscene_spp/shared/utils";
import dayjs from "dayjs";

// src/web-element.ts
var WebElementInfo = class {
  constructor({
    content,
    rect,
    // page,
    locator,
    id,
    attributes,
    indexId,
    xpaths
  }) {
    this.content = content;
    this.rect = rect;
    this.center = [
      Math.floor(rect.left + rect.width / 2),
      Math.floor(rect.top + rect.height / 2)
    ];
    this.locator = locator;
    this.id = id;
    this.attributes = attributes;
    this.indexId = indexId;
    this.xpaths = xpaths;
  }
};

// src/common/utils.ts
async function parseContextFromWebPage(page, _opt) {
  assert(page, "page is required");
  if (page._forceUsePageContext) {
    return await page._forceUsePageContext();
  }
  const url = await page.url();
  uploadTestInfoToServer({ testUrl: url });
  let screenshotBase64;
  let tree;
  await Promise.all([
    page.screenshotBase64().then((base64) => {
      screenshotBase64 = base64;
    }),
    page.getElementsNodeTree().then(async (treeRoot) => {
      tree = treeRoot;
    })
  ]);
  const webTree = traverseTree(tree, (elementInfo) => {
    const { rect, id, content, attributes, locator, indexId } = elementInfo;
    return new WebElementInfo({
      rect,
      locator,
      id,
      content,
      attributes,
      indexId
    });
  });
  assert(screenshotBase64, "screenshotBase64 is required");
  const elementsInfo = treeToList(webTree);
  const size = await page.size();
  if (size.dpr && size.dpr > 1) {
    screenshotBase64 = await resizeImgBase64(screenshotBase64, {
      width: size.width,
      height: size.height
    });
  }
  return {
    content: elementsInfo,
    tree: webTree,
    size,
    screenshotBase64,
    url
  };
}
function reportFileName(tag = "web") {
  const reportTagName = getAIConfig(MIDSCENE_REPORT_TAG_NAME);
  const dateTimeInFileName = dayjs().format("YYYY-MM-DD_HH-mm-ss");
  const uniqueId = uuid().substring(0, 8);
  return `${reportTagName || tag}-${dateTimeInFileName}-${uniqueId}`;
}
function printReportMsg(filepath) {
  logMsg(`Midscene - report file updated: ${filepath}`);
}
function getCurrentExecutionFile(trace) {
  const error = new Error();
  const stackTrace = trace || error.stack;
  const pkgDir = process.cwd() || "";
  if (stackTrace) {
    const stackLines = stackTrace.split("\n");
    for (const line of stackLines) {
      if (line.includes(".spec.") || line.includes(".test.") || line.includes(".ts") || line.includes(".js")) {
        const match = line.match(/(?:at\s+)?(.*?\.(?:spec|test)\.[jt]s)/);
        if (match?.[1]) {
          const targetFileName = match[1].replace(pkgDir, "").trim().replace("at ", "");
          return targetFileName;
        }
      }
    }
  }
  return false;
}
var testFileIndex = /* @__PURE__ */ new Map();
function generateCacheId(fileName) {
  let taskFile = fileName || getCurrentExecutionFile();
  if (!taskFile) {
    taskFile = uuid();
    console.warn(
      "Midscene - using random UUID for cache id. Cache may be invalid."
    );
  }
  if (testFileIndex.has(taskFile)) {
    const currentIndex = testFileIndex.get(taskFile);
    if (currentIndex !== void 0) {
      testFileIndex.set(taskFile, currentIndex + 1);
    }
  } else {
    testFileIndex.set(taskFile, 1);
  }
  return `${taskFile}-${testFileIndex.get(taskFile)}`;
}
var ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED = "NOT_IMPLEMENTED_AS_DESIGNED";
function replaceIllegalPathCharsAndSpace(str) {
  return str.replace(/[/\\:*?"<>| ]/g, "-");
}
function forceClosePopup(page, debug) {
  page.on("popup", async (popup) => {
    if (!popup) {
      console.warn("got a popup event, but the popup is not ready yet, skip");
      return;
    }
    const url = await popup.url();
    console.log(`Popup opened: ${url}`);
    if (!popup.isClosed()) {
      try {
        await popup.close();
      } catch (error) {
        debug(`failed to close popup ${url}, error: ${error}`);
      }
    } else {
      debug(`popup is already closed, skip close ${url}`);
    }
    if (!page.isClosed()) {
      try {
        await page.goto(url);
      } catch (error) {
        debug(`failed to goto ${url}, error: ${error}`);
      }
    } else {
      debug(`page is already closed, skip goto ${url}`);
    }
  });
}
function matchElementFromPlan(planLocateParam, tree) {
  if (!planLocateParam) {
    return void 0;
  }
  if (planLocateParam.id) {
    return getNodeFromCacheList(planLocateParam.id);
  }
  if (planLocateParam.bbox) {
    const centerPosition = {
      x: Math.floor((planLocateParam.bbox[0] + planLocateParam.bbox[2]) / 2),
      y: Math.floor((planLocateParam.bbox[1] + planLocateParam.bbox[3]) / 2)
    };
    let element = elementByPositionWithElementInfo(tree, centerPosition);
    if (!element) {
      element = generateElementByPosition(centerPosition);
    }
    return element;
  }
  return void 0;
}
export {
  ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED,
  forceClosePopup,
  generateCacheId,
  getCurrentExecutionFile,
  matchElementFromPlan,
  parseContextFromWebPage,
  printReportMsg,
  replaceIllegalPathCharsAndSpace,
  reportFileName
};

//# sourceMappingURL=utils.js.map