import { describe, it, expect } from "vitest";
import {
  RULES,
  RULE_CATEGORIES,
  TAB_GROUPS,
  getRulesByCategory,
  getRulesByTabGroup,
  getRuleByKey,
} from "../rules";

describe("rules", () => {
  it("has 16 rules total", () => {
    expect(RULES.length).toBe(16);
  });

  it("has unique keys", () => {
    const keys = RULES.map((r) => r.key);
    expect(new Set(keys).size).toBe(keys.length);
  });

  it("has unique priorities within categories", () => {
    for (const cat of RULE_CATEGORIES) {
      const rules = getRulesByCategory(cat.key);
      const priorities = rules.map((r) => r.priority);
      expect(new Set(priorities).size).toBe(priorities.length);
    }
  });

  it("all rules have valid category", () => {
    const validCategories = RULE_CATEGORIES.map((c) => c.key);
    for (const rule of RULES) {
      expect(validCategories).toContain(rule.category);
    }
  });

  it("all rules default to disabled", () => {
    for (const rule of RULES) {
      expect(rule.defaultEnabled).toBe(false);
    }
  });

  it("only collection ALL is free, all others are paid", () => {
    for (const rule of RULES) {
      if (rule.key === "noindex_nofollow_collection_all") {
        expect(rule.isFree).toBe(true);
        expect(rule.tier).toBe("free");
      } else {
        expect(rule.isFree).toBe(false);
      }
    }
  });

  it("custom rules are tier pro, native rules are standard or free", () => {
    for (const rule of RULES) {
      if (rule.category === "custom") {
        expect(rule.tier).toBe("pro");
      } else if (rule.key !== "noindex_nofollow_collection_all") {
        expect(rule.tier).toBe("standard");
      }
    }
  });

  it("custom rules have customValue fields", () => {
    const customRules = RULES.filter((r) => r.category === "custom");
    for (const rule of customRules) {
      expect(rule.hasCustomValue).toBe(true);
      expect(rule.customValueLabel).toBeDefined();
      expect(rule.customValuePlaceholder).toBeDefined();
    }
  });

  it("non-custom rules do not have customValue", () => {
    const nonCustom = RULES.filter((r) => r.category !== "custom");
    for (const rule of nonCustom) {
      expect(rule.hasCustomValue).toBe(false);
    }
  });

  it("native rules have SERP preview", () => {
    const native = RULES.filter((r) => r.category !== "custom");
    for (const rule of native) {
      expect(rule.serpPreview).toBeDefined();
      expect(rule.serpPreview!.siteTitle).toBeTruthy();
      expect(rule.serpPreview!.pageTitle).toBeTruthy();
      expect(rule.serpPreview!.faviconLetter).toHaveLength(1);
    }
  });

  it("native rules have googleCheckUrl", () => {
    const native = RULES.filter((r) => r.category !== "custom");
    for (const rule of native) {
      expect(rule.googleCheckUrl).toBeDefined();
      expect(rule.googleCheckUrl).toContain("{domain}");
    }
  });
});

describe("RULE_CATEGORIES", () => {
  it("has 4 categories", () => {
    expect(RULE_CATEGORIES.length).toBe(4);
  });

  it("categories are security, duplicate_content, technical, custom", () => {
    const keys = RULE_CATEGORIES.map((c) => c.key);
    expect(keys).toEqual(["security", "duplicate_content", "technical", "custom"]);
  });
});

describe("TAB_GROUPS", () => {
  it("has 2 groups", () => {
    expect(TAB_GROUPS.length).toBe(2);
  });

  it("native group covers security + duplicate + technical", () => {
    const native = TAB_GROUPS.find((g) => g.key === "native");
    expect(native!.categories).toEqual(["security", "duplicate_content", "technical"]);
  });

  it("custom group covers custom only", () => {
    const custom = TAB_GROUPS.find((g) => g.key === "custom");
    expect(custom!.categories).toEqual(["custom"]);
  });

  it("all categories are covered by tab groups", () => {
    const allCats = TAB_GROUPS.flatMap((g) => g.categories);
    for (const cat of RULE_CATEGORIES) {
      expect(allCats).toContain(cat.key);
    }
  });
});

describe("getRulesByCategory", () => {
  it("returns rules sorted by priority", () => {
    const security = getRulesByCategory("security");
    for (let i = 1; i < security.length; i++) {
      expect(security[i].priority).toBeGreaterThan(security[i - 1].priority);
    }
  });

  it("returns 4 security rules", () => {
    expect(getRulesByCategory("security").length).toBe(4);
  });

  it("returns 6 duplicate_content rules", () => {
    expect(getRulesByCategory("duplicate_content").length).toBe(6);
  });

  it("returns 3 technical rules", () => {
    expect(getRulesByCategory("technical").length).toBe(3);
  });

  it("returns 3 custom rules", () => {
    expect(getRulesByCategory("custom").length).toBe(3);
  });
});

describe("getRulesByTabGroup", () => {
  it("native group returns 13 rules", () => {
    expect(getRulesByTabGroup("native").length).toBe(13);
  });

  it("custom group returns 3 rules", () => {
    expect(getRulesByTabGroup("custom").length).toBe(3);
  });

  it("unknown group returns empty", () => {
    expect(getRulesByTabGroup("unknown").length).toBe(0);
  });

  it("collection ALL is first in native group", () => {
    const native = getRulesByTabGroup("native");
    expect(native[0].key).toBe("noindex_nofollow_collection_all");
  });
});

describe("getRuleByKey", () => {
  it("finds existing rule", () => {
    const rule = getRuleByKey("noindex_nofollow_cart_page");
    expect(rule).toBeDefined();
    expect(rule!.label).toBe("Page panier");
  });

  it("returns undefined for unknown key", () => {
    expect(getRuleByKey("nonexistent")).toBeUndefined();
  });

  it("tagged collections and blogs are separate rules", () => {
    expect(getRuleByKey("noindex_tagged_collections")).toBeDefined();
    expect(getRuleByKey("noindex_tagged_blogs")).toBeDefined();
    expect(getRuleByKey("noindex_tagged_collections_and_blogs")).toBeUndefined();
  });
});
