import type { PublicGuide } from "@/lib/guides/queries"; import { searchTeams, sortTeamsByDps, type DpsOrder, type TeamSearchTarget, } from "@/lib/guides/team-search"; export type GuideSearchParams = Record; export interface PublicGuideFilters { conditionIndex: number; recommendedIndex: number; setsIndex: number; targetsIndex: number; query: string; field: TeamSearchTarget; sort: DpsOrder; recommendedLabels: string[]; setsLabels: string[]; targetsLabels: string[]; } type GuideTeam = PublicGuide["teams"][number]; type GuideMember = GuideTeam["members"][number]; type GuideItem = NonNullable; export type PublicTeamCardData = Pick & { members: Array & { character: Pick & { aliases?: string[] }; weapon: (Pick & { aliases?: string[] }) | null; artifact: (Pick & { aliases?: string[] }) | null; secondArtifact: (Pick & { aliases?: string[] }) | null; }>; }; export type PublicTeamConditionGroup = Pick & { teams: PublicTeamCardData[]; }; export function firstSearchValue(value: string | string[] | undefined): string | undefined { return Array.isArray(value) ? value[0] : value; } export function resolveOneBasedIndex(value: string | undefined, length: number): number { if (length <= 0 || !value || !/^\d+$/u.test(value)) return 0; const index = Number(value) - 1; return Number.isSafeInteger(index) && index >= 0 && index < length ? index : 0; } export function resolvePublicGuideFilters( guide: PublicGuide, section: string, params: GuideSearchParams, ): PublicGuideFilters { const profile = guide.artifactProfile; const recommended = profile?.recommendedConditions ?? []; const sets = guide.artifactGroups; const targets = profile?.targetConditions.filter((condition) => condition.rows.length) ?? []; const fieldValue = firstSearchValue(params.field); const sortValue = firstSearchValue(params.sort); return { conditionIndex: resolveOneBasedIndex( firstSearchValue(params.condition), section === "weapon" ? guide.weaponGroups.filter((group) => group.rows.length > 0).length : section === "constellations" ? guide.constellationGroups.filter((group) => group.rows.length > 0).length : guide.teamGroups.length, ), recommendedIndex: resolveOneBasedIndex(firstSearchValue(params.recommended), recommended.length), setsIndex: resolveOneBasedIndex(firstSearchValue(params.sets), sets.length), targetsIndex: resolveOneBasedIndex(firstSearchValue(params.targets), targets.length), query: firstSearchValue(params.q)?.trim() ?? "", field: fieldValue === "team" || fieldValue === "character" || fieldValue === "weapon" || fieldValue === "artifact" ? fieldValue : "all", sort: sortValue === "best" || sortValue === "worst" ? sortValue : null, recommendedLabels: recommended.map((condition, index) => condition.name || `เงื่อนไข ${index + 1}`), setsLabels: sets.map((condition, index) => condition.name || `เงื่อนไข ${index + 1}`), targetsLabels: targets.map((condition, index) => condition.name || `เงื่อนไข ${index + 1}`), }; } export function filterPublicTeamGroups( guide: PublicGuide, filters: PublicGuideFilters, ): PublicTeamConditionGroup[] { const activeGroup = guide.teamGroups[filters.conditionIndex] ?? guide.teamGroups[0]; if (!activeGroup) return []; const matches = searchTeams(activeGroup.teams, (team) => ({ team: [team.title], character: team.members.flatMap((member) => [member.character.name, ...member.character.aliases]), weapon: team.members.flatMap((member) => member.weapon ? [member.weapon.name, ...member.weapon.aliases] : []), artifact: team.members.flatMap((member) => [member.artifact, member.secondArtifact].flatMap((artifact) => artifact ? [artifact.name, ...artifact.aliases] : [])), }), filters.query, filters.field); const teams = sortTeamsByDps(matches.items, filters.sort).map((team) => ({ id: team.id, title: team.title, rotationSeconds: team.rotationSeconds, combo: team.combo, members: team.members.map((member) => ({ position: member.position, damage: member.damage, constellation: member.constellation, refinement: member.refinement, character: { key: member.character.key, name: member.character.name, imageUrl: member.character.imageUrl, element: member.character.element, rarity: member.character.rarity, }, weapon: member.weapon ? { key: member.weapon.key, name: member.weapon.name, imageUrl: member.weapon.imageUrl, rarity: member.weapon.rarity, } : null, artifact: member.artifact ? { key: member.artifact.key, name: member.artifact.name, imageUrl: member.artifact.imageUrl, rarity: member.artifact.rarity, } : null, secondArtifact: member.secondArtifact ? { key: member.secondArtifact.key, name: member.secondArtifact.name, imageUrl: member.secondArtifact.imageUrl, rarity: member.secondArtifact.rarity, } : null, })), })); return guide.teamGroups.map((group, index) => ({ id: group.id, name: group.name, note: index === filters.conditionIndex ? group.note : null, teams: index === filters.conditionIndex ? teams : [], })); }