import { test, expect } from "@playwright/test";
import crossSpawn from "cross-spawn";
import z from "zod";
import { getApps, isProblemApp } from "./apps.server.js";
async function getInBrowserTestPages() {
  const apps = (await getApps()).filter((a) => !isProblemApp(a)).filter((a) => a.test.type === "browser");
  const pages = apps.map((app) => {
    if (app.test.type !== "browser")
      return null;
    const { pathname } = app.test;
    return app.test.testFiles.map((testFile) => {
      return {
        path: `${pathname}${testFile}`,
        testFile
      };
    });
  });
  return pages.filter(Boolean).flat();
}
const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));
async function waitFor(cb, { timeout = 1e3, interval = 30 } = {}) {
  const timeEnd = Date.now() + timeout;
  let lastError = null;
  while (Date.now() < timeEnd) {
    try {
      const result = await cb();
      if (result)
        return result;
    } catch (error) {
      lastError = error;
    }
    await sleep(interval);
  }
  throw lastError || new Error(`waitFor timed out after ${timeout}ms`);
}
function setupInBrowserTests() {
  const code = `import('@kentcdodds/workshop-app/playwright').then(({ getInBrowserTestPages }) => getInBrowserTestPages().then(r => console.log(JSON.stringify(r))))`;
  const result = crossSpawn.sync("node", ["--eval", code], {
    encoding: "utf-8"
  });
  if (result.status !== 0) {
    console.error(result.output.join("\n"));
    throw new Error(
      `Failed to get in-browser test pages. Status: ${result.status}.`
    );
  }
  const testPages = z.array(z.object({ path: z.string() })).parse(JSON.parse(result.stdout));
  for (const testPage of testPages) {
    test(testPage.path, async ({ page }) => {
      const errors = [];
      const logs = [];
      const infos = [];
      page.on("console", (message) => {
        switch (message.type()) {
          case "error": {
            errors.push(message.text());
            break;
          }
          case "log": {
            logs.push(message.text());
            break;
          }
          case "info": {
            infos.push(message.text());
            break;
          }
        }
      });
      await page.goto(testPage.path);
      await page.waitForLoadState();
      await waitFor(
        () => infos.find((info) => info.includes("status: pending")),
        { timeout: 1e4 }
      );
      const result2 = await Promise.race([
        waitFor(() => logs.find((log) => log.includes("status: pass")), {
          timeout: 1e4
        }),
        waitFor(() => errors.length > 0 ? errors : null, {
          timeout: 1e4
        }).then((errors2) => {
          throw errors2;
        })
      ]);
      expect(result2).toContain("status: pass");
    });
  }
}
export {
  getInBrowserTestPages,
  setupInBrowserTests
};
