import * as R from "remeda";
import { PLUS_VOTING_CRITERIA } from "../plus-voting-constants";

interface RawVotingResult {
	votedId: number;
	tier: number;
	score: number;
	wasSuggested: number;
}

interface VotingResultWithPassed extends RawVotingResult {
	passedVoting: number;
}

export function computePassedVoting(
	results: RawVotingResult[],
): VotingResultWithPassed[] {
	const byTier = R.groupBy(results, (r) => r.tier);

	return Object.entries(byTier).flatMap(([tierStr, tierResults]) => {
		const tier = Number(tierStr) as keyof typeof PLUS_VOTING_CRITERIA;
		const criteria = PLUS_VOTING_CRITERIA[tier];

		const passAvg = percentageToDbAvg(criteria.passPercentage);
		const failAvg = percentageToDbAvg(criteria.failPercentage);

		const autoPassers = tierResults.filter((r) => r.score >= passAvg);
		const autoFailers = tierResults.filter((r) => r.score <= failAvg);
		const middleZone = tierResults
			.filter((r) => r.score > failAvg && r.score < passAvg)
			.sort((a, b) => b.score - a.score);

		const remainingSlots = Math.max(0, criteria.quota - autoPassers.length);
		const lastPassingScore = middleZone[remainingSlots - 1]?.score;

		return [
			...autoPassers.map((r) => ({ ...r, passedVoting: 1 as number })),
			...autoFailers.map((r) => ({ ...r, passedVoting: 0 as number })),
			...middleZone.map((r, i) => ({
				...r,
				passedVoting:
					i < remainingSlots || r.score === lastPassingScore
						? (1 as number)
						: (0 as number),
			})),
		];
	});
}

export function computeFreshPlusTiers(
	results: VotingResultWithPassed[],
): { userId: number; plusTier: number }[] {
	const byUser = R.groupBy(results, (r) => r.votedId);

	const output: { userId: number; plusTier: number }[] = [];

	for (const [userIdStr, userResults] of Object.entries(byUser)) {
		const effectiveTiers: number[] = [];

		for (const r of userResults) {
			if (r.passedVoting) {
				effectiveTiers.push(r.tier);
			} else if (!r.wasSuggested && r.tier !== 3) {
				effectiveTiers.push(r.tier + 1);
			}
		}

		if (effectiveTiers.length === 0) continue;

		output.push({
			userId: Number(userIdStr),
			plusTier: Math.min(...effectiveTiers),
		});
	}

	return output;
}

function percentageToDbAvg(percentage: number) {
	return (2 * percentage - 100) / 100;
}
