import type { MouseEvent } from 'react';

import type { Handle } from '@atcute/lexicons';

import { clsx } from 'clsx';

import { isInvalidHandle } from '#/lib/display-names';

import {
	usePreferencesQuery,
	useRemoveMutedWordsMutation,
	useUpsertMutedWordsMutation,
} from '#/state/queries/preferences';

import * as Menu from '#/components/Menu';
import * as Prompt from '#/components/Prompt';
import { atomicSegment } from '#/components/RichText.css';
import { Spinner } from '#/components/Spinner';
import type { TextProps } from '#/components/Text';
import * as textStyles from '#/components/Text.css';
import { type InlineLinkUnderline, useInternalLink } from '#/components/web/Link';
import * as linkStyles from '#/components/web/Link.css';

import Search from '#/icons/central/MagnifyingGlass_round_outlined_radius1_stroke2.svg';
import Mute from '#/icons/central/Mute_round_outlined_radius1_stroke2.svg';
import Person from '#/icons/central/People_round_outlined_radius1_stroke2.svg';
import { m } from '#/paraglide/messages';
import { useRouter } from '#/router';

const preventDefault = (e: MouseEvent) => e.preventDefault();

export type RichTextTagProps = Pick<TextProps, 'color' | 'leading' | 'size'> & {
	authorHandle?: Handle;
	display: string;
	tag: string;
	underline?: InlineLinkUnderline;
};

/**
 * a link to a hashtag or cashtag feed within {@link RichText} that opens a context menu on click.
 *
 * @param props the component props
 */
const MenuSpinner = () => <Spinner color="default" label={m['common.status.loading']()} size="lg" />;

export function RichTextTag({
	authorHandle,
	color = 'textLink',
	display,
	leading,
	size,
	tag,
	underline = 'hover',
}: RichTextTagProps) {
	const router = useRouter();
	const { isLoading: isPreferencesLoading, data: preferences } = usePreferencesQuery();
	const {
		mutateAsync: upsertMutedWord,
		variables: optimisticUpsert,
		reset: resetUpsert,
	} = useUpsertMutedWordsMutation();
	const {
		mutateAsync: removeMutedWords,
		variables: optimisticRemove,
		reset: resetRemove,
	} = useRemoveMutedWordsMutation();
	const { href } = useInternalLink({ to: { name: 'Hashtag', tag } });
	const muteConfirmHandle = Prompt.usePromptHandle();

	const isCashtag = tag.startsWith('$');
	const label = isCashtag
		? m['components.richTextTag.a11y.cashtag']({ tag })
		: m['components.richTextTag.a11y.hashtag']({ tag });
	const prefixedTag = isCashtag ? tag : `#${tag}`;

	const isMuted = !!(
		(preferences?.moderationPrefs.mutedWords?.find(
			(word) => word.value === tag && word.targets.includes('tag'),
		) ??
			optimisticUpsert?.find((word) => word.value === tag && word.targets.includes('tag'))) &&
		!optimisticRemove?.find((word) => word?.value === tag)
	);

	// mute records that exactly match the tag in question
	const removeableMuteWords =
		preferences?.moderationPrefs.mutedWords?.filter((word) => word.value === tag) ?? [];

	const toggleMute = () => {
		if (isMuted) {
			resetUpsert();
			void removeMutedWords(removeableMuteWords);
		} else {
			resetRemove();
			void upsertMutedWord([{ actorTarget: 'all', targets: ['tag'], value: tag }]);
		}
	};

	return (
		<>
			<Menu.Root>
				<Menu.Trigger
					aria-label={label}
					className={clsx(
						textStyles.text({ color, leading, size }),
						linkStyles.inlineLink({ underline }),
						atomicSegment,
					)}
					nativeButton={false}
					// the anchor exists only for its href (hover preview, middle/right-click "open in new tab"); a
					// plain left-click always opens the menu, so suppress the native navigation it would trigger
					onClick={preventDefault}
					render={<a href={href} />}
				>
					{display}
				</Menu.Trigger>
				<Menu.Popup label={label}>
					<Menu.Group>
						<Menu.Item
							label={m['components.richTextTag.seePosts.prefixed']({ prefixedTag })}
							onClick={() => router.navigate({ to: { name: 'Hashtag', tag } })}
						>
							<Menu.ItemText>
								{isCashtag
									? m['components.richTextTag.seePosts.tag']({ tag })
									: m['components.richTextTag.seePosts.hash']({ tag })}
							</Menu.ItemText>
							<Menu.ItemIcon icon={Search} />
						</Menu.Item>
						{authorHandle && !isInvalidHandle(authorHandle) && (
							<Menu.Item
								label={m['components.richTextTag.seePosts.prefixedByUser']({ prefixedTag })}
								onClick={() => router.navigate({ to: { name: 'Hashtag', author: authorHandle, tag } })}
							>
								<Menu.ItemText>
									{isCashtag
										? m['components.richTextTag.seePosts.tagByUser']({ tag })
										: m['components.richTextTag.seePosts.hashByUser']({ tag })}
								</Menu.ItemText>
								<Menu.ItemIcon icon={Person} />
							</Menu.Item>
						)}
					</Menu.Group>
					<Menu.Separator />
					<Menu.Item
						label={
							isMuted
								? m['components.richTextTag.unmute']({ prefixedTag })
								: m['components.richTextTag.mute']({ prefixedTag })
						}
						onClick={() => muteConfirmHandle.open(null)}
					>
						<Menu.ItemText>
							{isMuted
								? m['components.richTextTag.unmute']({ prefixedTag })
								: m['components.richTextTag.mute']({ prefixedTag })}
						</Menu.ItemText>
						<Menu.ItemIcon icon={isPreferencesLoading ? MenuSpinner : Mute} />
					</Menu.Item>
				</Menu.Popup>
			</Menu.Root>

			<Prompt.Basic
				handle={muteConfirmHandle}
				title={
					isMuted
						? m['components.richTextTag.unmuteConfirm.title']({ prefixedTag })
						: m['components.richTextTag.muteConfirm.title']({ prefixedTag })
				}
				description={
					isMuted
						? m['components.richTextTag.unmuteConfirm.description']()
						: m['components.richTextTag.muteConfirm.description']()
				}
				onConfirm={toggleMute}
				confirmButtonCta={
					isMuted
						? m['components.richTextTag.unmute']({ prefixedTag })
						: m['components.richTextTag.mute']({ prefixedTag })
				}
				confirmButtonColor={isMuted ? 'primary' : 'negative'}
			/>
		</>
	);
}
