import type { Product } from "@/lib/headless/types"; // Taxonomia Franquicia > Saga > Personaje (ej. Disney > Toy Story > Rex, // Marvel > Spider-Man > Spider-Man). Vive en los tags de Medusa con // prefijo ("franquicia:Disney", "saga:Toy Story", "personaje:Rex") porque // la coleccion de Medusa es una sola por producto y mezclaba niveles // ("Disney" y "Toy Story" como pares). Los tags son muchos-a-muchos: un // producto puede tener varios personajes ("Minnie y Mickey"). export type TaxonomyKind = "franquicia" | "saga" | "personaje"; export const TAXONOMY_KINDS: TaxonomyKind[] = ["franquicia", "saga", "personaje"]; export function taxonomyValues(product: Product, kind: TaxonomyKind): string[] { const prefix = `${kind}:`; return product.tags.filter((tag) => tag.startsWith(prefix)).map((tag) => tag.slice(prefix.length)); } export type TaxonomyFilter = Partial>; export function matchesTaxonomy(product: Product, filter: TaxonomyFilter): boolean { return TAXONOMY_KINDS.every((kind) => { const value = filter[kind]; return !value || taxonomyValues(product, kind).includes(value); }); } export type SagaNode = { name: string; count: number; characters: { name: string; count: number }[] }; export type FranchiseNode = { name: string; count: number; sagas: SagaNode[] }; function byCountThenName(a: T, b: T): number { return b.count - a.count || a.name.localeCompare(b.name, "es"); } export function buildFranchiseTree(products: Product[]): FranchiseNode[] { const franchises = new Map }> }>(); for (const product of products) { const sagas = taxonomyValues(product, "saga"); const characters = taxonomyValues(product, "personaje"); for (const franchise of taxonomyValues(product, "franquicia")) { const node = franchises.get(franchise) ?? { count: 0, sagas: new Map() }; node.count += 1; for (const saga of sagas) { const sagaNode = node.sagas.get(saga) ?? { count: 0, characters: new Map() }; sagaNode.count += 1; for (const character of characters) sagaNode.characters.set(character, (sagaNode.characters.get(character) ?? 0) + 1); node.sagas.set(saga, sagaNode); } franchises.set(franchise, node); } } return [...franchises.entries()] .map(([name, node]) => ({ name, count: node.count, sagas: [...node.sagas.entries()] .map(([sagaName, sagaNode]) => ({ name: sagaName, count: sagaNode.count, characters: [...sagaNode.characters.entries()].map(([characterName, count]) => ({ name: characterName, count })).sort(byCountThenName), })) .sort(byCountThenName), })) .sort(byCountThenName); } export function taxonomyHref(kind: TaxonomyKind, value: string): string { return `/catalog?${kind}=${encodeURIComponent(value)}`; }