import { describe, it, expect, beforeEach, vi } from "vitest";

// Each test imports registerFont fresh so the module-level Set resets.

describe("registerFont", () => {
  beforeEach(() => {
    // Remove any <style data-font> elements created by previous runs
    document.head.querySelectorAll("style[data-font]").forEach((el) => el.remove());
    // Reset modules so _registadas Set is fresh
    vi.resetModules();
    // Stub document.fonts.load to avoid real font loading
    if (!document.fonts) {
      Object.defineProperty(document, "fonts", {
        value: { load: vi.fn().mockResolvedValue([]) },
        configurable: true,
      });
    } else {
      vi.spyOn(document.fonts, "load").mockResolvedValue([]);
    }
  });

  async function freshRegisterFont() {
    const mod = await import("../loadFont?v=" + Math.random());
    return mod.registerFont;
  }

  it("appends a <style> element with @font-face to document.head", async () => {
    const registerFont = await freshRegisterFont();
    registerFont("TestFont", "/fonts/test.ttf");
    const el = document.head.querySelector('style[data-font="TestFont"]');
    expect(el).not.toBeNull();
    expect(el.textContent).toContain("@font-face");
    expect(el.textContent).toContain("TestFont");
    expect(el.textContent).toContain("/fonts/test.ttf");
  });

  it("includes the url and format in the @font-face rule", async () => {
    const registerFont = await freshRegisterFont();
    registerFont("MyFont", "/fonts/my.woff2", "woff2");
    const el = document.head.querySelector('style[data-font="MyFont"]');
    expect(el.textContent).toContain("format('woff2')");
  });

  it("includes font-weight and font-style with provided values", async () => {
    const registerFont = await freshRegisterFont();
    registerFont("BoldFont", "/fonts/bold.ttf", "truetype", "bold", "italic");
    const el = document.head.querySelector('style[data-font="BoldFont"]');
    expect(el.textContent).toContain("font-weight: bold");
    expect(el.textContent).toContain("font-style: italic");
  });

  it("defaults to truetype format, normal weight and normal style", async () => {
    const registerFont = await freshRegisterFont();
    registerFont("DefaultFont", "/fonts/default.ttf");
    const el = document.head.querySelector('style[data-font="DefaultFont"]');
    expect(el.textContent).toContain("format('truetype')");
    expect(el.textContent).toContain("font-weight: normal");
    expect(el.textContent).toContain("font-style: normal");
  });

  it("is idempotent — second call with same family name is a no-op", async () => {
    const registerFont = await freshRegisterFont();
    registerFont("UniqueFont", "/fonts/unique.ttf");
    registerFont("UniqueFont", "/fonts/unique-other.ttf");
    const els = document.head.querySelectorAll('style[data-font="UniqueFont"]');
    expect(els.length).toBe(1);
  });

  it("registers different family names independently", async () => {
    const registerFont = await freshRegisterFont();
    registerFont("FontA", "/fonts/a.ttf");
    registerFont("FontB", "/fonts/b.ttf");
    const a = document.head.querySelector('style[data-font="FontA"]');
    const b = document.head.querySelector('style[data-font="FontB"]');
    expect(a).not.toBeNull();
    expect(b).not.toBeNull();
  });

  it("calls document.fonts.load to preload the font", async () => {
    const registerFont = await freshRegisterFont();
    const spy = vi.spyOn(document.fonts, "load").mockResolvedValue([]);
    registerFont("PreloadFont", "/fonts/pre.ttf");
    expect(spy).toHaveBeenCalledWith(expect.stringContaining("PreloadFont"));
  });
});
