import { didFromUri, rkeyFromUri } from "$lib/api/uri";
import type { ReactionRecord, RecordView } from "$lib/api/records";

export const ORDERED_REACTION_KINDS = ["👍", "👎", "😆", "🎉", "🫤", "❤️", "🚀", "👀"] as const;
export type ReactionKind = (typeof ORDERED_REACTION_KINDS)[number];

const KIND_SET = new Set<string>(ORDERED_REACTION_KINDS);

export interface ReactionGroup {
	kind: ReactionKind;
	count: number;
	users: string[];
	isReacted: boolean;
	viewerRkey?: string;
}

// groups flat reaction records by emoji, keeping OrderedReactionKinds order and
// dropping kinds nobody used. handleOf resolves a reactor did to a display handle.
export function buildReactions(
	items: RecordView<ReactionRecord>[],
	viewerDid?: string,
	handleOf?: (did: string) => string
): ReactionGroup[] {
	const groups = new Map<ReactionKind, ReactionGroup>();

	for (const item of items) {
		const kind = item.value.reaction;
		if (!KIND_SET.has(kind)) continue;
		const did = didFromUri(item.uri);
		let group = groups.get(kind as ReactionKind);
		if (!group) {
			group = { kind: kind as ReactionKind, count: 0, users: [], isReacted: false };
			groups.set(kind as ReactionKind, group);
		}
		group.count++;
		group.users.push(handleOf ? handleOf(did) : did);
		if (viewerDid && did === viewerDid) {
			group.isReacted = true;
			group.viewerRkey = rkeyFromUri(item.uri);
		}
	}

	return ORDERED_REACTION_KINDS.filter((k) => groups.has(k)).map((k) => groups.get(k)!);
}

// optimistic addition for a reaction group
export function withViewerReaction(
	group: ReactionGroup,
	viewerHandle: string,
	rkey: string
): ReactionGroup {
	return {
		...group,
		count: group.count + 1,
		users: [...group.users, viewerHandle],
		isReacted: true,
		viewerRkey: rkey
	};
}

// optimistic removal for a reaction group
export function withoutViewerReaction(group: ReactionGroup, viewerHandle: string): ReactionGroup {
	// drop one occurrence of the viewer; count never dips below zero
	const idx = group.users.indexOf(viewerHandle);
	const users = idx === -1 ? group.users : group.users.filter((_, i) => i !== idx);
	return {
		...group,
		count: Math.max(0, group.count - 1),
		users,
		isReacted: false,
		viewerRkey: undefined
	};
}

// optimistic add of a fresh reaction (e.g. from the picker): bumps the group if the
// kind is already present, otherwise inserts a new one, keeping canonical emoji order.
export function upsertViewerReaction(
	groups: ReactionGroup[],
	kind: ReactionKind,
	viewerHandle: string,
	rkey: string
): ReactionGroup[] {
	const exists = groups.some((g) => g.kind === kind);
	const next = exists
		? groups.map((g) => (g.kind === kind ? withViewerReaction(g, viewerHandle, rkey) : g))
		: [...groups, { kind, count: 1, users: [viewerHandle], isReacted: true, viewerRkey: rkey }];
	return ORDERED_REACTION_KINDS.filter((k) => next.some((g) => g.kind === k)).map((k) =>
		next.find((g) => g.kind === k)!
	);
}
