export type TeamSearchTarget = | "all" | "team" | "character" | "weapon" | "artifact"; export interface TeamSearchValues { team: string[]; character: string[]; weapon: string[]; artifact: string[]; } export interface DpsTeam { rotationSeconds: string | number; members: Array<{ damage: string | number }>; } export type DpsOrder = "best" | "worst" | null; export function teamDps(team: DpsTeam): number { const seconds = Number(team.rotationSeconds); if (!(seconds > 0)) return 0; return team.members.reduce((sum, member) => sum + Number(member.damage), 0) / seconds; } export function sortTeamsByDps( teams: readonly Team[], order: DpsOrder, ): Team[] { if (!order) return [...teams]; return teams .map((team, index) => ({ team, index })) .sort((left, right) => { const difference = order === "best" ? teamDps(right.team) - teamDps(left.team) : teamDps(left.team) - teamDps(right.team); return difference || left.index - right.index; }) .map(({ team }) => team); } export function matchesTeamSearch( values: TeamSearchValues, query: string, target: TeamSearchTarget, ): boolean { const normalizedQuery = query.trim().toLocaleLowerCase(); if (!normalizedQuery) return true; const candidates = target === "all" ? Object.values(values).flat() : values[target]; return candidates.some((value) => value.toLocaleLowerCase().includes(normalizedQuery), ); }