import type { Tables } from "~/db/tables";
import * as Seasons from "~/features/mmr/core/Seasons";
import type { ModeShort, StageId } from "~/modules/in-game-lists/types";
import invariant from "~/utils/invariant";
import { winnersArrayToWinner } from "../q-match-utils";

type MatchForSummarizing = {
	mapList: Array<{ mode: ModeShort; stageId: StageId }>;
	groupAlpha: { id: number };
	groupBravo: { id: number };
};

export function summarizeMaps({
	match,
	winners,
	members,
}: {
	match: MatchForSummarizing;
	winners: ("ALPHA" | "BRAVO")[];
	members: { id: number; groupId: number }[];
}) {
	const season = Seasons.currentOrPrevious()?.nth;
	invariant(typeof season === "number", "No ranked season for skills");

	const result: Array<Tables["MapResult"]> = [];

	const playedMaps = match.mapList.slice(0, winners.length);

	for (const [i, map] of playedMaps.entries()) {
		const winnerSide = winners[i];
		const winnerGroupId =
			winnerSide === "ALPHA" ? match.groupAlpha.id : match.groupBravo.id;

		const winnerPlayers = members.filter((p) => p.groupId === winnerGroupId);
		const loserPlayers = members.filter((p) => p.groupId !== winnerGroupId);

		for (const winner of winnerPlayers) {
			result.push({
				userId: winner.id,
				wins: 1,
				losses: 0,
				mode: map.mode,
				stageId: map.stageId,
				season,
			});
		}

		for (const loser of loserPlayers) {
			result.push({
				userId: loser.id,
				wins: 0,
				losses: 1,
				mode: map.mode,
				stageId: map.stageId,
				season,
			});
		}
	}

	return result;
}

export function summarizePlayerResults({
	match,
	winners,
	members,
}: {
	match: MatchForSummarizing;
	winners: ("ALPHA" | "BRAVO")[];
	members: { id: number; groupId: number }[];
}) {
	const season = Seasons.currentOrPrevious()?.nth;
	invariant(typeof season === "number", "No ranked season for skills");

	const result: Array<Tables["PlayerResult"]> = [];

	const addMapResult = ({
		outcome,
		type,
		ownerUserId,
		otherUserId,
	}: {
		outcome: "win" | "loss";
		type: "MATE" | "ENEMY";
		ownerUserId: number;
		otherUserId: number;
	}) => {
		const existing = result.find(
			(r) => r.ownerUserId === ownerUserId && r.otherUserId === otherUserId,
		);
		if (existing) {
			if (outcome === "win") {
				existing.mapWins++;
			} else existing.mapLosses++;
		} else {
			result.push({
				ownerUserId,
				otherUserId,
				type,
				mapWins: outcome === "win" ? 1 : 0,
				mapLosses: outcome === "win" ? 0 : 1,
				season,
				setLosses: 0,
				setWins: 0,
			});
		}
	};

	for (const winner of winners) {
		for (const member of members) {
			for (const member2 of members) {
				if (member.id === member2.id) continue;

				const type = member.groupId === member2.groupId ? "MATE" : "ENEMY";
				const won =
					winner === "ALPHA"
						? member.groupId === match.groupAlpha.id
						: member.groupId === match.groupBravo.id;

				addMapResult({
					ownerUserId: member.id,
					otherUserId: member2.id,
					type,
					outcome: won ? "win" : "loss",
				});
			}
		}
	}

	const winner = winnersArrayToWinner(winners);

	for (const member of members) {
		for (const member2 of members) {
			if (member.id === member2.id) continue;

			const type = member.groupId === member2.groupId ? "MATE" : "ENEMY";
			const won =
				winner === "ALPHA"
					? member.groupId === match.groupAlpha.id
					: member.groupId === match.groupBravo.id;

			result.push({
				ownerUserId: member.id,
				otherUserId: member2.id,
				type,
				mapWins: 0,
				mapLosses: 0,
				season,
				setWins: won ? 1 : 0,
				setLosses: won ? 0 : 1,
			});
		}
	}

	return result;
}
