import { uniqueBy } from '@mary/array-fns';

import { cleanError } from '#/lib/errors';
import { targetToShareUrl } from '#/lib/routes/app-links';
import { enforceLen } from '#/lib/utils/text';

import { useSearchPostsQuery } from '#/state/queries/search-posts';
import { useTitle } from '#/state/use-title';

import { List } from '#/components/List/List';
import { ListEmpty } from '#/components/List/ListEmpty';
import { ListError } from '#/components/List/ListError';
import * as ListTail from '#/components/List/ListTail';
import { Post } from '#/components/Post/Post';
import { PostFeedLoadingPlaceholder } from '#/components/PostFeed/PostFeedLoadingPlaceholder';
import { shareUrl } from '#/components/sharing';
import { type Section, Tabs } from '#/components/Tabs';
import { Button, ButtonIcon } from '#/components/web/Button';
import * as Layout from '#/components/web/Layout';

import Share from '#/icons/central/ArrowOutOfBox_round_outlined_radius1_stroke2.svg';
import MagnifyingGlassIcon from '#/icons/central/MagnifyingGlass_round_outlined_radius1_stroke2.svg';
import { m } from '#/paraglide/messages';
import { useParams } from '#/router';

export default function TopicScreen() {
	const [{ tab, topic }, replaceParams] = useParams('Topic');
	useTitle(m['navigation.topic.title']());
	const headerTitle = enforceLen(topic, 24, true, 'middle');

	const onShare = () => {
		void shareUrl(targetToShareUrl({ name: 'Topic', topic }));
	};

	const sections: Section<'latest' | 'top'>[] = [
		{
			id: 'top',
			label: m['common.search.top'](),
			children: <TopicScreenTab topic={topic} sort="top" />,
		},
		{
			id: 'latest',
			label: m['common.search.latest'](),
			children: <TopicScreenTab topic={topic} sort="latest" />,
		},
	];

	return (
		<Layout.Screen>
			<Tabs
				sections={sections}
				value={tab ?? 'top'}
				onValueChange={(next) => replaceParams({ tab: next })}
				header={
					<Layout.Header.Outer noBottomBorder sticky={false}>
						<Layout.Header.BackButton />
						<Layout.Header.Content>
							<Layout.Header.TitleText>{headerTitle}</Layout.Header.TitleText>
						</Layout.Header.Content>
						<Layout.Header.EndSlot>
							<Button
								color="primary"
								label={m['common.share.action.share']()}
								onClick={onShare}
								shape="round"
								size="small"
								variant="ghost"
							>
								<ButtonIcon icon={Share} />
							</Button>
						</Layout.Header.EndSlot>
					</Layout.Header.Outer>
				}
			/>
		</Layout.Screen>
	);
}

const POST_ITEM_HEIGHT_ESTIMATE = 300;

function TopicScreenTab({ topic, sort }: { topic: string; sort: 'top' | 'latest' }) {
	const { data, isFetchingNextPage, isPending, isError, error, refetch, fetchNextPage } = useSearchPostsQuery(
		{
			query: topic,
			sort,
		},
	);

	const posts = uniqueBy(data?.pages.flatMap((page) => page.posts) ?? [], (post) => post.uri);

	if (posts.length < 1) {
		if (isError) {
			return <ListError message={cleanError(error)} onRetry={() => void refetch()} />;
		}

		if (isPending) {
			return <PostFeedLoadingPlaceholder />;
		}

		return <ListEmpty icon={MagnifyingGlassIcon} message={m['screens.topic.empty']()} />;
	}

	return (
		<List
			data={posts}
			estimateHeight={POST_ITEM_HEIGHT_ESTIMATE}
			keyExtractor={(item) => item.uri}
			renderItem={({ index, item }) => <Post hideTopBorder={index === 0} post={item} />}
			ListFooterComponent={
				<ListTail.Frame>
					{isFetchingNextPage ? (
						<ListTail.Pending />
					) : isError ? (
						<ListTail.Error message={cleanError(error)} onRetry={() => void fetchNextPage()} />
					) : null}
				</ListTail.Frame>
			}
			onEndReached={() => {
				if (isError) {
					return;
				}
				void fetchNextPage();
			}}
			onEndReachedThreshold={2}
		/>
	);
}
