import { test as base, expect } from "@playwright/test";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";

interface AllowlistEntry {
  pattern: string;
  reason: string;
}

interface Allowlist {
  patterns: AllowlistEntry[];
}

const FIXTURE_DIR = path.dirname(fileURLToPath(import.meta.url));
const ALLOWLIST_PATH = path.join(FIXTURE_DIR, "console-allowlist.json");

function loadAllowlist(): RegExp[] {
  const raw = fs.readFileSync(ALLOWLIST_PATH, "utf8");
  const parsed: Allowlist = JSON.parse(raw);
  for (const entry of parsed.patterns) {
    if (!entry.reason || entry.reason.trim() === "") {
      throw new Error(
        `console-allowlist.json: pattern ${JSON.stringify(entry.pattern)} has no reason`
      );
    }
  }
  return parsed.patterns.map((e) => new RegExp(e.pattern));
}

const allowlist = loadAllowlist();

function isAllowed(message: string): boolean {
  return allowlist.some((re) => re.test(message));
}

interface ConsoleGateFixtures {
  consoleMessages: string[];
}

export const test = base.extend<ConsoleGateFixtures>({
  consoleMessages: async ({ page }, use, testInfo) => {
    const messages: string[] = [];
    page.on("console", (msg) => {
      const type = msg.type();
      if (type !== "error" && type !== "warning") return;
      const text = `[${type}] ${msg.text()}`;
      if (isAllowed(text)) return;
      messages.push(text);
    });
    page.on("pageerror", (err) => {
      const text = `[pageerror] ${err.message}`;
      if (!isAllowed(text)) messages.push(text);
    });

    await use(messages);

    if (messages.length > 0) {
      testInfo.attachments.push({
        name: "console-violations.txt",
        contentType: "text/plain",
        body: Buffer.from(messages.join("\n"), "utf8"),
      });
      throw new Error(
        `Console gate: ${messages.length} disallowed message(s):\n` +
          messages.map((m) => `  ${m}`).join("\n")
      );
    }
  },
});

export { expect };
