import { createContext, type ReactNode, useContext, useEffect, useRef, useState } from 'react';

import type { ChatBskyConvoDefs } from '@atcute/bluesky';

/** How long a message stays highlighted after scrolling to it, before the flash fades out. */
export const MESSAGE_HIGHLIGHT_DURATION_MS = 1500;

type HighlightedMessage = {
	id: string;
	/**
	 * Bumped on every highlight so that re-tapping the same reply re-triggers the flash even while the previous
	 * highlight is still active.
	 */
	key: number;
};

type MessageRepliesContextType = {
	/** The message currently staged for reply in the composer, or null. */
	replyTo: ChatBskyConvoDefs.MessageView | null;
	setReply: (message: ChatBskyConvoDefs.MessageView) => void;
	clearReply: () => void;
	/** Scroll the list to a message, if it's currently loaded, and flash it. No-op otherwise. */
	scrollToMessage: (messageId: string) => void;
	/** The message to flash, or null. Consumers compare against their own id. */
	highlightedMessage: HighlightedMessage | null;
};

const Context = createContext<MessageRepliesContextType | null>(null);

export function useMessageReplies() {
	const ctx = useContext(Context);
	if (!ctx) {
		throw new Error('useMessageReplies must be used within a MessageRepliesProvider');
	}
	return ctx;
}

export function MessageRepliesProvider({
	children,
	scrollToMessage: scrollToMessageRaw,
}: {
	children: ReactNode;
	/**
	 * scrolls to the message if loaded.
	 *
	 * @returns true if the message was found and scrolled to, false otherwise.
	 */
	scrollToMessage: (messageId: string) => boolean;
}) {
	const [replyTo, setReplyTo] = useState<ChatBskyConvoDefs.MessageView | null>(null);
	const [highlightedMessage, setHighlightedMessage] = useState<HighlightedMessage | null>(null);
	const highlightKey = useRef(0);
	const clearHighlightTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);

	const setReply = (message: ChatBskyConvoDefs.MessageView) => {
		setReplyTo(message);
	};

	const clearReply = () => {
		setReplyTo(null);
	};

	const scrollToMessage = (messageId: string) => {
		const didScroll = scrollToMessageRaw(messageId);
		if (!didScroll) {
			return;
		}

		highlightKey.current += 1;
		setHighlightedMessage({ id: messageId, key: highlightKey.current });
		if (clearHighlightTimeout.current) {
			clearTimeout(clearHighlightTimeout.current);
		}
		clearHighlightTimeout.current = setTimeout(() => {
			setHighlightedMessage(null);
		}, MESSAGE_HIGHLIGHT_DURATION_MS);
	};

	useEffect(() => {
		return () => {
			if (clearHighlightTimeout.current) {
				clearTimeout(clearHighlightTimeout.current);
			}
		};
	}, []);

	const ctx: MessageRepliesContextType = {
		replyTo,
		setReply,
		clearReply,
		scrollToMessage,
		highlightedMessage,
	};

	return <Context.Provider value={ctx}>{children}</Context.Provider>;
}
