import fs from "node:fs/promises";
import path from "node:path";

const debugBase = "http://127.0.0.1:9223";
const appBase = "http://127.0.0.1:8080/mikrotik/admin";
const artifactsDir = path.resolve("mikrotik/admin/tests/artifacts");

await fs.mkdir(artifactsDir, { recursive: true });

const pageInfo = await fetch(`${debugBase}/json/new?${encodeURIComponent("about:blank")}`, {
  method: "PUT",
}).then((response) => response.json());

const socket = new WebSocket(pageInfo.webSocketDebuggerUrl);
await new Promise((resolve, reject) => {
  socket.addEventListener("open", resolve, { once: true });
  socket.addEventListener("error", reject, { once: true });
});

let commandId = 0;
const pending = new Map();
socket.addEventListener("message", (event) => {
  const message = JSON.parse(event.data);
  if (!message.id || !pending.has(message.id)) return;
  const { resolve, reject } = pending.get(message.id);
  pending.delete(message.id);
  if (message.error) reject(new Error(message.error.message));
  else resolve(message.result);
});

function send(method, params = {}) {
  const id = ++commandId;
  socket.send(JSON.stringify({ id, method, params }));
  return new Promise((resolve, reject) => pending.set(id, { resolve, reject }));
}

const delay = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));

async function navigate(url) {
  await send("Page.navigate", { url });
  await delay(1800);
}

async function evaluate(expression) {
  const result = await send("Runtime.evaluate", {
    expression,
    awaitPromise: true,
    returnByValue: true,
  });
  if (result.exceptionDetails) throw new Error(result.exceptionDetails.text);
  return result.result.value;
}

async function capture(name) {
  const screenshot = await send("Page.captureScreenshot", {
    format: "png",
    captureBeyondViewport: false,
  });
  const outputPath = path.join(artifactsDir, `${name}.png`);
  await fs.writeFile(outputPath, Buffer.from(screenshot.data, "base64"));
  return outputPath;
}

async function audit(rootSelector) {
  return evaluate(`(() => {
    const root = document.querySelector(${JSON.stringify(rootSelector)});
    if (!root) return { error: "root-not-found", url: location.href, title: document.title };
    const parseColor = (value) => {
      const match = value.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*([\\d.]+))?\\)/);
      if (!match) return null;
      return { r:+match[1], g:+match[2], b:+match[3], a:match[4] === undefined ? 1 : +match[4] };
    };
    const light = [];
    for (const element of root.querySelectorAll("*")) {
      const rect = element.getBoundingClientRect();
      if (rect.width < 2 || rect.height < 2) continue;
      const color = parseColor(getComputedStyle(element).backgroundColor);
      if (!color || color.a < .2) continue;
      if (color.r > 230 && color.g > 230 && color.b > 230) {
        light.push({
          tag: element.tagName,
          className: String(element.className || "").slice(0, 100),
          background: getComputedStyle(element).backgroundColor,
          width: Math.round(rect.width),
          height: Math.round(rect.height)
        });
      }
    }
    const rootStyle = getComputedStyle(root);
    return {
      url: location.href,
      title: document.title,
      rootBackground: rootStyle.backgroundColor,
      lightSurfaceCount: light.length,
      lightSurfaces: light.slice(0, 15),
      viewport: [document.documentElement.clientWidth, document.documentElement.clientHeight],
      scroll: [document.documentElement.scrollWidth, document.documentElement.scrollHeight],
      horizontalOverflow: document.documentElement.scrollWidth > document.documentElement.clientWidth + 2,
      bodyText: document.body.innerText.slice(0, 180)
    };
  })()`);
}

await send("Page.enable");
await send("Runtime.enable");
await send("Emulation.setDeviceMetricsOverride", {
  width: 1920,
  height: 1080,
  deviceScaleFactor: 1,
  mobile: false,
});

await navigate(`${appBase}/index.php?next=agents_portal_preview.php`);
await evaluate(`(() => {
  const user = document.querySelector('[name="user"]');
  const pass = document.querySelector('[name="pass"]');
  if (!user || !pass) return false;
  user.value = "admin";
  pass.value = "1234";
  user.form.requestSubmit();
  return true;
})()`);
await delay(2200);

const pages = [
  ["agents-preview", "agents_portal_preview.php"],
  ["agents-management", "agents.php"],
  ["agents-activity", "agents_activity.php"],
  ["agents-balances", "agents_balances.php"],
];
const report = {};

for (const [name, relativeUrl] of pages) {
  await navigate(`${appBase}/${relativeUrl}`);
  report[name] = await audit(".ua-agents-page");
  report[name].screenshot = await capture(name);
}

await navigate(`${appBase}/agent_portal.php?agent=25`);
await evaluate(`(() => {
  const password = document.querySelector('[name="password"]');
  if (!password) return false;
  password.value = "Accept@1234";
  const submit = password.form.querySelector('[name="login"]');
  if (submit) submit.click();
  return true;
})()`);
await delay(1800);
report["agent-portal"] = await audit(".ap-shell");
report["agent-portal"].screenshot = await capture("agent-portal");

console.log(JSON.stringify(report, null, 2));
socket.close();
