import {
	type ComponentType,
	createContext,
	type MouseEvent,
	type ReactNode,
	type Ref,
	type SVGProps,
	useContext,
} from 'react';

import { clsx } from 'clsx';

import { formatPostStatCount } from '#/locale/intl/number';

import { AnimatedLikeIcon } from '#/components/PostControls/AnimatedLikeIcon';
import { CountWheel } from '#/components/PostControls/CountWheel';
import { Text } from '#/components/Text';
import { Tooltip } from '#/components/Tooltip';
import * as Skele from '#/components/web/Skeleton';

import ArrowShareRightIcon from '#/icons/central/ArrowShareRight_round_outlined_radius1_stroke2.svg';
import Repost from '#/icons/central/ArrowsRepeatRightLeft_round_outlined_radius1_stroke2.svg';
import Bubble from '#/icons/central/Bubble2_round_outlined_radius1_stroke2.svg';
import { m } from '#/paraglide/messages';
import { colors } from '#/styles/colors';

import * as css from './index.css';
import { RepostMenu } from './RepostMenu';
import { type PostControlsProps, usePostControlsActions } from './shared';
import { ShareMenu } from './ShareMenu';

const PostControlContext = createContext<{ active?: boolean }>({});
PostControlContext.displayName = 'PostControlContext';

type PostControlButtonProps = {
	/** Accessible name; becomes the `aria-label`. */
	label: string;
	/** Visible hover/focus hint. Pass `null` to suppress it (e.g. when a wrapping menu owns the tooltip). */
	tooltip: string | null;
	children: ReactNode;
	active?: boolean;
	/** Color applied when `active`; icon + count inherit it via `currentColor`. */
	activeColor?: string;
	onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
	ref?: Ref<HTMLButtonElement>;
};

/**
 * a compact post-control action button that renders as a plain button. can render standalone or back a
 * Menu.Trigger.
 */
function PostControlButton({
	active,
	activeColor,
	children,
	label,
	onClick,
	tooltip,
	...rest
}: PostControlButtonProps) {
	const button = (
		// Base UI's `Menu.Trigger render={...}` and `Tooltip` both clone this with their own props
		// (aria/data/handlers/id/ref) merged in, so spread them all onto the button — forwarding only the
		// ref wouldn't open the menu.
		<button
			type="button"
			aria-label={label}
			className={css.button}
			style={active && activeColor ? { color: activeColor } : undefined}
			onClick={onClick}
			{...rest}
		>
			<PostControlContext.Provider value={{ active }}>{children}</PostControlContext.Provider>
		</button>
	);

	if (tooltip === null) {
		return button;
	}
	return <Tooltip label={tooltip}>{button}</Tooltip>;
}

/**
 * wraps a control's icon in a hover-highlighted circle so the hover/focus chrome lands on the icon alone. use
 * directly for a custom icon; see {@link PostControlButtonIcon} for a plain icon.
 */
function PostControlButtonIconBox({ children }: { children: ReactNode }) {
	return <span className={css.iconCircle}>{children}</span>;
}

/** A plain icon in the hover circle, inheriting the button color via `currentColor`. */
function PostControlButtonIcon({ icon: Icon }: { icon: ComponentType<SVGProps<SVGSVGElement>> }) {
	return (
		<PostControlButtonIconBox>
			<Icon className={css.icon} />
		</PostControlButtonIconBox>
	);
}

/** A count/label beside the icon, inheriting the button color and bolding when active. */
function PostControlButtonText({ children }: { children: ReactNode }) {
	const { active } = useContext(PostControlContext);
	return (
		<Text
			className={css.text}
			leading="none"
			selectable={false}
			size="md_sub"
			weight={active ? 'semiBold' : undefined}
		>
			{children}
		</Text>
	);
}

/** The compact post action bar used on the feed and thread rows. */
export function PostControls({
	post,
	feedContext,
	reqId,
	onPressReply,
	onPostReply,
	viaRepost,
}: PostControlsProps): ReactNode {
	const {
		hasLikeIconBeenToggled,
		onPressToggleLike,
		onQuote,
		onRepost,
		onShare,
		replyDisabled,
		requireAuth,
	} = usePostControlsActions({ post, feedContext, reqId, viaRepost, onPostReply });

	const repostCount = (post.repostCount ?? 0) + (post.quoteCount ?? 0);

	return (
		<div className={css.root}>
			<div className={css.primaryGroup}>
				<div className={clsx(css.primaryItem, replyDisabled && css.replyDisabled)}>
					<PostControlButton
						onClick={
							!replyDisabled
								? () =>
										requireAuth(() => {
											onPressReply();
										})
								: undefined
						}
						label={m['components.postControls.reply.a11y']({ count: post.replyCount || 0 })}
						tooltip={m['common.action.reply']()}
					>
						<PostControlButtonIcon icon={Bubble} />
						{typeof post.replyCount !== 'undefined' && post.replyCount > 0 && (
							<PostControlButtonText>{formatPostStatCount(post.replyCount)}</PostControlButtonText>
						)}
					</PostControlButton>
				</div>

				<div className={css.primaryItem}>
					<RepostMenu
						isReposted={!!post.viewer?.repost}
						onRepost={() => void onRepost()}
						onQuote={onQuote}
						embeddingDisabled={!!post.viewer?.embeddingDisabled}
						tooltip={m['components.postControls.repost.action.repost']()}
						render={
							<PostControlButton
								label={m['components.postControls.repost.a11y']()}
								tooltip={null}
								active={!!post.viewer?.repost}
								activeColor={colors.positive_500}
							>
								<PostControlButtonIcon icon={Repost} />
								{repostCount > 0 && (
									<PostControlButtonText>{formatPostStatCount(repostCount)}</PostControlButtonText>
								)}
							</PostControlButton>
						}
					/>
				</div>

				<div className={css.primaryItem}>
					<PostControlButton
						active={!!post.viewer?.like}
						activeColor={colors.pink}
						tooltip={m['common.action.like']()}
						onClick={() => requireAuth(() => onPressToggleLike())}
						label={
							post.viewer?.like
								? m['components.postControls.like.a11y.unlike']({ count: post.likeCount || 0 })
								: m['components.postControls.like.a11y.like']({ count: post.likeCount || 0 })
						}
					>
						<PostControlButtonIconBox>
							<AnimatedLikeIcon isLiked={!!post.viewer?.like} hasBeenToggled={hasLikeIconBeenToggled} />
						</PostControlButtonIconBox>
						<CountWheel
							count={post.likeCount ?? 0}
							isToggled={!!post.viewer?.like}
							hasBeenToggled={hasLikeIconBeenToggled}
							renderCount={({ count }) => (
								<PostControlButtonText>{formatPostStatCount(count)}</PostControlButtonText>
							)}
						/>
					</PostControlButton>
				</div>
			</div>
			<div className={css.secondaryGroup}>
				<ShareMenu
					post={post}
					onShare={onShare}
					tooltip={m['common.share.action.share']()}
					render={
						<PostControlButton label={m['components.postControls.share.a11y']()} tooltip={null}>
							<PostControlButtonIcon icon={ArrowShareRightIcon} />
						</PostControlButton>
					}
				/>
			</div>
		</div>
	);
}

export function PostControlsSkeleton() {
	// the rest-state row shows the bare icons, so the bars stand in at `ICON_SIZE` — the live `iconCircle` is
	// only the hover target and pulls itself back to that footprint with a negative margin. the trailing share
	// control reuses `secondaryGroup` verbatim so it pins to the same edge as the live row.
	return (
		<div className={css.root}>
			<div className={css.primaryGroup}>
				<div className={css.primaryItem}>
					<Skele.Pill blend size={css.ICON_SIZE} />
				</div>
				<div className={css.primaryItem}>
					<Skele.Pill blend size={css.ICON_SIZE} />
				</div>
				<div className={css.primaryItem}>
					<Skele.Pill blend size={css.ICON_SIZE} />
				</div>
			</div>
			<div className={css.secondaryGroup}>
				<Skele.Circle blend size={css.ICON_SIZE} />
			</div>
		</div>
	);
}
