import { describe, test, expect } from "bun:test";
import {
  CATEGORY_TREE,
  ECOSYSTEM_TREE,
  isCategoryGroup,
  getSubcategoriesForCategory,
  getSubcategoriesForGroup,
  getCategoryNames,
  getGroupForSubcategory,
  serializeCategoryTree,
  serializeEcosystemTree,
  getAllSubcategoryNames,
  getCategoryForSubcategory,
  getEcosystemsForManufacturer,
  matchesEcosystem,
} from "../../src/modules/catalog-categories/catalogCategories";

describe("catalogCategories", () => {
  // -------------------------------------------------------------------
  // Data validation
  // -------------------------------------------------------------------
  describe("CATEGORY_TREE", () => {
    test("exports a non-empty array", () => {
      expect(Array.isArray(CATEGORY_TREE)).toBe(true);
      expect(CATEGORY_TREE.length).toBeGreaterThan(0);
    });

    test("contains Technology, General, and Field categories", () => {
      const names = CATEGORY_TREE.map((c) => c.name);
      expect(names).toContain("Technology");
      expect(names).toContain("General");
      expect(names).toContain("Field");
    });

    test("each category has a name and entries", () => {
      for (const cat of CATEGORY_TREE) {
        expect(typeof cat.name).toBe("string");
        expect(Array.isArray(cat.entries)).toBe(true);
        expect(cat.entries.length).toBeGreaterThan(0);
      }
    });
  });

  describe("ECOSYSTEM_TREE", () => {
    test("exports a non-empty array", () => {
      expect(Array.isArray(ECOSYSTEM_TREE)).toBe(true);
      expect(ECOSYSTEM_TREE.length).toBeGreaterThan(0);
    });

    test("contains Networking, Video Surveillance, and Burg/Alarm", () => {
      const names = ECOSYSTEM_TREE.map((e) => e.name);
      expect(names).toContain("Networking");
      expect(names).toContain("Video Surveillance");
      expect(names).toContain("Burg/Alarm");
    });

    test("each ecosystem has manufacturers with required fields", () => {
      for (const eco of ECOSYSTEM_TREE) {
        expect(eco.manufacturers.length).toBeGreaterThan(0);
        for (const mfg of eco.manufacturers) {
          expect(typeof mfg.name).toBe("string");
          expect(typeof mfg.category).toBe("string");
          expect(typeof mfg.subcategoryPrefix).toBe("string");
        }
      }
    });
  });

  // -------------------------------------------------------------------
  // isCategoryGroup
  // -------------------------------------------------------------------
  describe("isCategoryGroup()", () => {
    test("returns true for group entries", () => {
      const group = { name: "Network", children: [{ name: "Network-Switch" }] };
      expect(isCategoryGroup(group)).toBe(true);
    });

    test("returns false for subcategory entries", () => {
      const leaf = { name: "Batteries", cwId: 80 };
      expect(isCategoryGroup(leaf)).toBe(false);
    });
  });

  // -------------------------------------------------------------------
  // getSubcategoriesForCategory
  // -------------------------------------------------------------------
  describe("getSubcategoriesForCategory()", () => {
    test("returns subcategories for Technology", () => {
      const subcats = getSubcategoriesForCategory("Technology");
      expect(subcats.length).toBeGreaterThan(0);
      expect(subcats).toContain("GeneralEquip");
      expect(subcats).toContain("Network-Switch");
    });

    test("returns subcategories for Field", () => {
      const subcats = getSubcategoriesForCategory("Field");
      expect(subcats).toContain("Conduit");
      expect(subcats).toContain("AlarmBurg-Panels");
      expect(subcats).toContain("Surveillance-CamerasIP");
    });

    test("returns empty for unknown category", () => {
      expect(getSubcategoriesForCategory("NonExistent")).toEqual([]);
    });
  });

  // -------------------------------------------------------------------
  // getSubcategoriesForGroup
  // -------------------------------------------------------------------
  describe("getSubcategoriesForGroup()", () => {
    test("returns subcategories for Technology/Network", () => {
      const subcats = getSubcategoriesForGroup("Technology", "Network");
      expect(subcats).toContain("Network-Other");
      expect(subcats).toContain("Network-Router");
      expect(subcats).toContain("Network-Switch");
      expect(subcats).toContain("Network-Wireless");
    });

    test("returns subcategories for Field/AlarmBurg", () => {
      const subcats = getSubcategoriesForGroup("Field", "AlarmBurg");
      expect(subcats).toContain("AlarmBurg-Panels");
      expect(subcats).toContain("AlarmBurg-Keypads");
    });

    test("returns empty for unknown group", () => {
      expect(getSubcategoriesForGroup("Technology", "NonExistent")).toEqual([]);
    });

    test("returns empty for unknown category", () => {
      expect(getSubcategoriesForGroup("NonExistent", "Network")).toEqual([]);
    });
  });

  // -------------------------------------------------------------------
  // getCategoryNames
  // -------------------------------------------------------------------
  describe("getCategoryNames()", () => {
    test("returns all top-level category names", () => {
      const names = getCategoryNames();
      expect(names).toContain("Technology");
      expect(names).toContain("General");
      expect(names).toContain("Field");
    });
  });

  // -------------------------------------------------------------------
  // getGroupForSubcategory
  // -------------------------------------------------------------------
  describe("getGroupForSubcategory()", () => {
    test("returns group for a grouped subcategory", () => {
      const result = getGroupForSubcategory("Network-Switch");
      expect(result).toEqual({ category: "Technology", group: "Network" });
    });

    test("returns group for AlarmBurg subcategory", () => {
      const result = getGroupForSubcategory("AlarmBurg-Panels");
      expect(result).toEqual({ category: "Field", group: "AlarmBurg" });
    });

    test("returns null for a direct subcategory", () => {
      const result = getGroupForSubcategory("GeneralEquip");
      expect(result).toBeNull();
    });

    test("returns null for unknown subcategory", () => {
      const result = getGroupForSubcategory("Unknown");
      expect(result).toBeNull();
    });
  });

  // -------------------------------------------------------------------
  // getCategoryForSubcategory
  // -------------------------------------------------------------------
  describe("getCategoryForSubcategory()", () => {
    test("resolves grouped subcategory to its category", () => {
      expect(getCategoryForSubcategory("Network-Switch")).toBe("Technology");
    });

    test("resolves direct subcategory to its category", () => {
      expect(getCategoryForSubcategory("Batteries")).toBe("General");
    });

    test("resolves Field subcategories", () => {
      expect(getCategoryForSubcategory("Conduit")).toBe("Field");
    });

    test("returns null for unknown subcategory", () => {
      expect(getCategoryForSubcategory("Unknown")).toBeNull();
    });
  });

  // -------------------------------------------------------------------
  // getAllSubcategoryNames
  // -------------------------------------------------------------------
  describe("getAllSubcategoryNames()", () => {
    test("returns non-empty array", () => {
      const names = getAllSubcategoryNames();
      expect(names.length).toBeGreaterThan(0);
    });

    test("includes direct and grouped subcategories", () => {
      const names = getAllSubcategoryNames();
      expect(names).toContain("GeneralEquip");
      expect(names).toContain("Network-Switch");
      expect(names).toContain("Batteries");
      expect(names).toContain("AlarmBurg-Panels");
    });

    test("does not include top-level categories", () => {
      const names = getAllSubcategoryNames();
      expect(names).not.toContain("Technology");
      expect(names).not.toContain("General");
      expect(names).not.toContain("Field");
    });
  });

  // -------------------------------------------------------------------
  // getEcosystemsForManufacturer
  // -------------------------------------------------------------------
  describe("getEcosystemsForManufacturer()", () => {
    test("returns Networking for Ubiquiti", () => {
      const ecosystems = getEcosystemsForManufacturer("Ubiquiti");
      expect(ecosystems).toContain("Networking");
    });

    test("returns Video Surveillance for Uniview", () => {
      const ecosystems = getEcosystemsForManufacturer("Uniview");
      expect(ecosystems).toContain("Video Surveillance");
    });

    test("returns empty for unknown manufacturer", () => {
      expect(getEcosystemsForManufacturer("Unknown")).toEqual([]);
    });

    test("is case-insensitive", () => {
      const result = getEcosystemsForManufacturer("ubiquiti");
      expect(result).toContain("Networking");
    });
  });

  // -------------------------------------------------------------------
  // matchesEcosystem
  // -------------------------------------------------------------------
  describe("matchesEcosystem()", () => {
    test("matches Ubiquiti Network-Switch to Networking", () => {
      expect(matchesEcosystem("Networking", "Ubiquiti", "Network-Switch")).toBe(
        true,
      );
    });

    test("matches Uniview Surveillance-CamerasIP to Video Surveillance", () => {
      expect(
        matchesEcosystem(
          "Video Surveillance",
          "Uniview",
          "Surveillance-CamerasIP",
        ),
      ).toBe(true);
    });

    test("does not match wrong ecosystem", () => {
      expect(
        matchesEcosystem("Networking", "Uniview", "Surveillance-CamerasIP"),
      ).toBe(false);
    });

    test("returns false for unknown ecosystem", () => {
      expect(matchesEcosystem("Unknown", "Ubiquiti", "Network-Switch")).toBe(
        false,
      );
    });

    test("handles null manufacturer", () => {
      expect(matchesEcosystem("Networking", null, "Network-Switch")).toBe(
        false,
      );
    });

    test("handles null subcategory", () => {
      expect(matchesEcosystem("Networking", "Ubiquiti", null)).toBe(false);
    });
  });

  // -------------------------------------------------------------------
  // serializeCategoryTree
  // -------------------------------------------------------------------
  describe("serializeCategoryTree()", () => {
    test("returns array with same length as CATEGORY_TREE", () => {
      const result = serializeCategoryTree();
      expect(result).toHaveLength(CATEGORY_TREE.length);
    });

    test("entries have type 'group' or 'subcategory'", () => {
      const result = serializeCategoryTree();
      for (const cat of result) {
        for (const entry of cat.entries) {
          expect(["group", "subcategory"]).toContain(entry.type);
        }
      }
    });

    test("group entries have subcategories array", () => {
      const result = serializeCategoryTree();
      const techCat = result.find((c) => c.name === "Technology")!;
      const networkGroup = techCat.entries.find(
        (e) => e.type === "group" && e.name === "Network",
      );
      expect(networkGroup).toBeDefined();
      if (networkGroup && "subcategories" in networkGroup) {
        expect(networkGroup.subcategories.length).toBeGreaterThan(0);
      }
    });
  });

  // -------------------------------------------------------------------
  // serializeEcosystemTree
  // -------------------------------------------------------------------
  describe("serializeEcosystemTree()", () => {
    test("returns array with same length as ECOSYSTEM_TREE", () => {
      const result = serializeEcosystemTree();
      expect(result).toHaveLength(ECOSYSTEM_TREE.length);
    });

    test("each ecosystem has manufacturers with category and prefix", () => {
      const result = serializeEcosystemTree();
      for (const eco of result) {
        expect(eco.manufacturers.length).toBeGreaterThan(0);
        for (const mfg of eco.manufacturers) {
          expect(typeof mfg.name).toBe("string");
          expect(typeof mfg.category).toBe("string");
          expect(typeof mfg.subcategoryPrefix).toBe("string");
        }
      }
    });
  });
});
