/**
 * Catalog Categories & Ecosystems
 *
 * This module defines the complete category/subcategory hierarchy and
 * ecosystem decision trees used for product filtering in the UI.
 *
 * --- Terminology ---
 *
 * Category:     Top-level CW category (e.g. "Technology", "Field", "General").
 *               A category is NEVER a subcategory.
 *
 * Subcategory:  The CW subcategory name stored on each catalog item.
 *               At the second level of the tree, if there are no children
 *               beneath it then the node name IS the subcategory.
 *               If children exist, the second-level node is an *umbrella*
 *               that groups related subcategories — the children are the
 *               actual subcategory names.
 *
 * Ecosystem:    A cross-cutting product grouping defined by manufacturer +
 *               category + subcategory-prefix rules. Ecosystems let the UI
 *               present a "Networking" or "Video Surveillance" view that
 *               spans manufacturers regardless of where CW filed them.
 *
 * --- Data shapes ---
 *
 * SubcategoryNode  – a leaf: `{ name, cwId? }`
 * CategoryGroup    – an umbrella with children: `{ name, children[] }`
 * CategoryEntry    – either a leaf OR a group at the 2nd level
 * TopLevelCategory – `{ name, cwId?, entries[] }`
 *
 * The `CATEGORY_TREE` export is the single source of truth; helpers derive
 * flat lists, lookup maps, and search predicates from it.
 */

// ─── Data types ──────────────────────────────────────────────────────────────

export interface SubcategoryNode {
  /** The exact CW subcategory name */
  name: string;
  /** CW subcategory id (optional, for reference) */
  cwId?: number;
}

export interface CategoryGroup {
  /** Display name of the umbrella (e.g. "Network", "Cables", "AlarmBurg") */
  name: string;
  /** The subcategories that belong to this umbrella */
  children: SubcategoryNode[];
}

/** A second-level entry is either a direct subcategory or an umbrella group */
export type CategoryEntry = SubcategoryNode | CategoryGroup;

export interface TopLevelCategory {
  /** The CW category name */
  name: string;
  /** CW category id (optional, for reference) */
  cwId?: number;
  /** Second-level entries under this category */
  entries: CategoryEntry[];
}

/** Helper type guard */
export function isCategoryGroup(entry: CategoryEntry): entry is CategoryGroup {
  return "children" in entry;
}

// ─── Ecosystem types ─────────────────────────────────────────────────────────

export interface EcosystemManufacturer {
  /** Manufacturer name as stored in CW */
  name: string;
  /** CW manufacturer id */
  cwId?: number;
  /** Which CW category these products fall under */
  category: string;
  /** Subcategory prefix — matches any subcategory starting with this string */
  subcategoryPrefix: string;
}

export interface Ecosystem {
  /** Display name (e.g. "Networking", "Video Surveillance") */
  name: string;
  /** Manufacturers that belong to this ecosystem */
  manufacturers: EcosystemManufacturer[];
}

// ─── Category Tree ───────────────────────────────────────────────────────────

export const CATEGORY_TREE: TopLevelCategory[] = [
  {
    name: "Technology",
    cwId: 18,
    entries: [
      { name: "GeneralEquip", cwId: 57 },
      { name: "Home Entertainment", cwId: 114 },
      { name: "Monitor", cwId: 115 },
      { name: "Printers", cwId: 120 },
      { name: "Storage", cwId: 108 },
      {
        name: "Network",
        children: [
          { name: "Network-Other", cwId: 174 },
          { name: "Network-Router", cwId: 119 },
          { name: "Network-Switch", cwId: 112 },
          { name: "Network-Wireless", cwId: 111 },
        ],
      },
      {
        name: "Computer",
        children: [
          { name: "Computer-Components", cwId: 109 },
          { name: "Computer-Desktop", cwId: 106 },
          { name: "Computer-Laptop", cwId: 107 },
        ],
      },
      {
        name: "Recurring",
        children: [
          { name: "Recurring - Online", cwId: 83 },
          { name: "Recurring - Other", cwId: 84 },
          { name: "Recurring - Protection", cwId: 81 },
          { name: "Recurring - Telephone", cwId: 133 },
        ],
      },
      {
        name: "Telephone",
        children: [
          { name: "Tele-HSet-Digital", cwId: 116 },
          { name: "Tele-HSet-IP", cwId: 206 },
          { name: "Tele-HSet-SLT" },
          { name: "Tele-Misc", cwId: 75 },
          { name: "Tele-Paging", cwId: 76 },
          { name: "Tele-SystemCards", cwId: 135 },
          { name: "Tele-Systems", cwId: 78 },
        ],
      },
    ],
  },
  {
    name: "General",
    cwId: 25,
    entries: [
      { name: "Batteries", cwId: 80 },
      { name: "Battery Backups", cwId: 144 },
      { name: "BulkWire", cwId: 200 },
      {
        name: "Cables",
        children: [
          { name: "Cables-Adapters", cwId: 182 },
          { name: "Cables-HDMI", cwId: 176 },
          { name: "Cables-Network", cwId: 87 },
          { name: "Cables-Other", cwId: 177 },
          { name: "Cables-USB", cwId: 178 },
          { name: "Cables-VGA", cwId: 179 },
        ],
      },
      { name: "Elec Cords & Adapters", cwId: 142 },
      { name: "Enclosures", cwId: 141 },
      { name: "PowerSupply", cwId: 167 },
      {
        name: "RackEquip",
        children: [
          { name: "RackEquip-Rack", cwId: 143 },
          { name: "RackEquip-Shelves", cwId: 190 },
        ],
      },
    ],
  },
  {
    name: "Field",
    cwId: 28,
    entries: [
      { name: "Conduit" },
      { name: "Electric", cwId: 199 },
      { name: "GateControl", cwId: 45 },
      { name: "Locksets" },
      { name: "Other", cwId: 46 },
      { name: "Relays", cwId: 168 },
      {
        name: "AccessControl",
        children: [
          { name: "AccessControl-Controllers", cwId: 137 },
          { name: "AccessControl-Credential", cwId: 183 },
          { name: "AccessControl-LockDevices", cwId: 138 },
          { name: "AccessControl-Other", cwId: 44 },
          { name: "AccessControl-Readers", cwId: 136 },
          { name: "AccessControl-VideoEntry", cwId: 139 },
        ],
      },
      {
        name: "AlarmBurg",
        children: [
          { name: "AlarmBurg-Communicators", cwId: 96 },
          { name: "AlarmBurg-Keypads", cwId: 93 },
          { name: "AlarmBurg-Modules", cwId: 140 },
          { name: "AlarmBurg-Other", cwId: 92 },
          { name: "AlarmBurg-Panels", cwId: 42 },
          { name: "AlarmBurg-Sensors-Wireless", cwId: 147 },
          { name: "AlarmBurg-Sensors-Wired", cwId: 146 },
          { name: "AlarmBurg-Siren", cwId: 145 },
        ],
      },
      {
        name: "AlarmFire",
        children: [
          { name: "AlarmFire-Communicators", cwId: 97 },
          { name: "AlarmFire-Devices", cwId: 169 },
          { name: "AlarmFire-Modules", cwId: 170 },
          { name: "AlarmFire-Other", cwId: 98 },
          { name: "AlarmFire-Panels", cwId: 95 },
          { name: "AlarmFire-Sensors", cwId: 94 },
        ],
      },
      {
        name: "Automation",
        children: [
          { name: "Automation-General", cwId: 99 },
          { name: "Automation-HVAC", cwId: 181 },
          { name: "Automation-Lights", cwId: 180 },
          { name: "Automation-Locks", cwId: 192 },
          { name: "Automation-Thermostat" },
        ],
      },
      {
        name: "AV",
        children: [
          { name: "AV-Adapters&Cables", cwId: 171 },
          { name: "AV-Components", cwId: 172 },
          { name: "AV-Mounts", cwId: 191 },
          { name: "AV-Other", cwId: 184 },
          { name: "AV-Speakers", cwId: 173 },
          { name: "AV-Television", cwId: 175 },
        ],
      },
      {
        name: "StrCbl",
        children: [
          { name: "StrCbl-Jacks", cwId: 186 },
          { name: "StrCbl-PatchPanel", cwId: 187 },
          { name: "StrCbl-Plates", cwId: 185 },
        ],
      },
      {
        name: "Surveillance",
        children: [
          { name: "Surveillance-Accs", cwId: 90 },
          { name: "Surveillance-CamerasAnalog", cwId: 89 },
          { name: "Surveillance-CamerasIP", cwId: 88 },
          { name: "Surveillance-NVR", cwId: 43 },
        ],
      },
    ],
  },
];

// ─── Ecosystem Tree ──────────────────────────────────────────────────────────

export const ECOSYSTEM_TREE: Ecosystem[] = [
  {
    name: "Networking",
    manufacturers: [
      {
        name: "Ubiquiti",
        cwId: 248,
        category: "Technology",
        subcategoryPrefix: "Network-",
      },
      {
        name: "TP-Link",
        cwId: 259,
        category: "Technology",
        subcategoryPrefix: "Network-",
      },
    ],
  },
  {
    name: "Video Surveillance",
    manufacturers: [
      {
        name: "Uniview",
        cwId: 239,
        category: "Field",
        subcategoryPrefix: "Surveillance-",
      },
      {
        name: "Hikvision",
        cwId: 299,
        category: "Field",
        subcategoryPrefix: "Surveillance-",
      },
      {
        name: "Alarm.com",
        cwId: 294,
        category: "Field",
        subcategoryPrefix: "Surveillance-",
      },
    ],
  },
  {
    name: "Burg/Alarm",
    manufacturers: [
      {
        name: "Qolsys",
        cwId: 376,
        category: "Field",
        subcategoryPrefix: "AlarmBurg-",
      },
      {
        name: "DSC",
        cwId: 287,
        category: "Field",
        subcategoryPrefix: "AlarmBurg-",
      },
    ],
  },
];

// ─── Derived helpers ─────────────────────────────────────────────────────────

/**
 * Returns a flat list of all subcategory names under a given category.
 */
export function getSubcategoriesForCategory(categoryName: string): string[] {
  const category = CATEGORY_TREE.find((c) => c.name === categoryName);
  if (!category) return [];

  const subcats: string[] = [];
  for (const entry of category.entries) {
    if (isCategoryGroup(entry)) {
      for (const child of entry.children) {
        subcats.push(child.name);
      }
    } else {
      subcats.push(entry.name);
    }
  }
  return subcats;
}

/**
 * Returns all subcategory names under a given umbrella group within a category.
 * e.g. getSubcategoriesForGroup("Field", "AlarmBurg") → ["AlarmBurg-Communicators", ...]
 */
export function getSubcategoriesForGroup(
  categoryName: string,
  groupName: string,
): string[] {
  const category = CATEGORY_TREE.find((c) => c.name === categoryName);
  if (!category) return [];

  const group = category.entries.find(
    (e) => isCategoryGroup(e) && e.name === groupName,
  );
  if (!group || !isCategoryGroup(group)) return [];

  return group.children.map((c) => c.name);
}

/**
 * Returns all top-level category names.
 */
export function getCategoryNames(): string[] {
  return CATEGORY_TREE.map((c) => c.name);
}

/**
 * Returns the umbrella group name for a given subcategory, or null if it's a
 * direct entry (not under an umbrella).
 */
export function getGroupForSubcategory(
  subcategoryName: string,
): { category: string; group: string } | null {
  for (const cat of CATEGORY_TREE) {
    for (const entry of cat.entries) {
      if (isCategoryGroup(entry)) {
        if (entry.children.some((c) => c.name === subcategoryName)) {
          return { category: cat.name, group: entry.name };
        }
      }
    }
  }
  return null;
}

/**
 * Returns the full tree serialized for the API / UI consumption.
 * Each top-level category includes its entries, with umbrella groups
 * expanded to show children.
 */
export function serializeCategoryTree() {
  return CATEGORY_TREE.map((cat) => ({
    name: cat.name,
    cwId: cat.cwId ?? null,
    entries: cat.entries.map((entry) => {
      if (isCategoryGroup(entry)) {
        return {
          type: "group" as const,
          name: entry.name,
          subcategories: entry.children.map((c) => ({
            name: c.name,
            cwId: c.cwId ?? null,
          })),
        };
      }
      return {
        type: "subcategory" as const,
        name: entry.name,
        cwId: (entry as SubcategoryNode).cwId ?? null,
      };
    }),
  }));
}

/**
 * Returns the ecosystem tree serialized for the API / UI consumption.
 */
export function serializeEcosystemTree() {
  return ECOSYSTEM_TREE.map((eco) => ({
    name: eco.name,
    manufacturers: eco.manufacturers.map((m) => ({
      name: m.name,
      cwId: m.cwId ?? null,
      category: m.category,
      subcategoryPrefix: m.subcategoryPrefix,
    })),
  }));
}

/**
 * Returns a flat list of every known subcategory name across all categories.
 */
export function getAllSubcategoryNames(): string[] {
  const names: string[] = [];
  for (const cat of CATEGORY_TREE) {
    for (const entry of cat.entries) {
      if (isCategoryGroup(entry)) {
        for (const child of entry.children) {
          names.push(child.name);
        }
      } else {
        names.push(entry.name);
      }
    }
  }
  return names;
}

/**
 * Given a CW subcategory name, resolves which top-level category it belongs to.
 */
export function getCategoryForSubcategory(
  subcategoryName: string,
): string | null {
  for (const cat of CATEGORY_TREE) {
    for (const entry of cat.entries) {
      if (isCategoryGroup(entry)) {
        if (entry.children.some((c) => c.name === subcategoryName)) {
          return cat.name;
        }
      } else if (entry.name === subcategoryName) {
        return cat.name;
      }
    }
  }
  return null;
}

/**
 * Given a CW manufacturer name, returns which ecosystems it belongs to.
 */
export function getEcosystemsForManufacturer(
  manufacturerName: string,
): string[] {
  return ECOSYSTEM_TREE.filter((eco) =>
    eco.manufacturers.some(
      (m) => m.name.toLowerCase() === manufacturerName.toLowerCase(),
    ),
  ).map((eco) => eco.name);
}

/**
 * Checks if a catalog item (by manufacturer + subcategory) matches a given ecosystem.
 */
export function matchesEcosystem(
  ecosystemName: string,
  manufacturer: string | null,
  subcategory: string | null,
): boolean {
  const eco = ECOSYSTEM_TREE.find((e) => e.name === ecosystemName);
  if (!eco) return false;

  return eco.manufacturers.some(
    (m) =>
      m.name.toLowerCase() === (manufacturer ?? "").toLowerCase() &&
      (subcategory ?? "").startsWith(m.subcategoryPrefix),
  );
}
