import { FlashList } from '@shopify/flash-list'
import { useInfiniteQuery, useQuery } from '@tanstack/react-query'
import type { ErrorBoundaryProps } from 'expo-router'
import { Link, useLocalSearchParams } from 'expo-router'
import { memo, useCallback, useMemo } from 'react'
import { Pressable } from 'react-native'
import { EmptyState } from 'src/components/common/EmptyState'
import { ErrorState } from 'src/components/common/ErrorState'
import { ListFooter as SharedListFooter } from 'src/components/common/ListFooter'
import { LoadingView } from 'src/components/common/LoadingView'
import { PostGridCell } from 'src/components/common/PostGridCell'
import ImageComponent from 'src/components/ImageComponent'
import { ScreenScrollContainer } from 'src/components/layout'
import { useMenuScroll, useScreenMenu } from 'src/components/menu'
import { listScopeKeys, useCacheMutation } from 'src/hooks/mutations/cacheMutation'
import { followHashtag, unfollowHashtag } from 'src/lib/api'
import { toImageUri } from 'src/lib/media-source'
import { hashtagQueries } from 'src/lib/queries/hashtags'
import { Button, ScrollView, Text, useTheme, View, XStack, YStack } from 'tamagui'
import { prettyCount } from '../../../utils'

const RenderItem = memo(({ item }: any) => {
  if (!item?.media_attachments?.[0]?.url) return null
  return <PostGridCell post={item} />
})

export function ErrorBoundary({ error, retry }: ErrorBoundaryProps) {
  return <ErrorState message={error.message} onRetry={retry} />
}

export default function Page() {
  const { id } = useLocalSearchParams<{ id: string }>()
  const onScroll = useMenuScroll(true)
  const theme = useTheme()

  const RelatedTags = useCallback(
    ({ relatedTags }: any) =>
      relatedTags && relatedTags.length ? (
        <View px="$3" pb="$3">
          <ScrollView horizontal showsHorizontalScrollIndicator={false}>
            {relatedTags.map((tag: any) => (
              <Link key={tag.name} href={`/hashtag/${tag.name}`} asChild>
                <View
                  bg="transparent"
                  px="$3"
                  py="$1.5"
                  mr="$2"
                  borderRadius={10}
                  borderWidth={1}
                  borderColor={theme.borderColor.val}
                >
                  <Text color={theme.colorSecondary.val}>#{tag.name}</Text>
                </View>
              </Link>
            ))}
          </ScrollView>
        </View>
      ) : null,
    []
  )

  const _RenderRelatedItem = useCallback(
    ({ item }: any) =>
      item && item.name ? (
        <View p="$3" borderWidth={1}>
          <Link href={`/hashtag/${item.name}`} asChild>
            <Pressable>
              <View p="$3" borderWidth={1}>
                <Text fontSize="$5">{item.name}</Text>
              </View>
            </Pressable>
          </Link>
        </View>
      ) : null,
    []
  )

  const followMutation = useCacheMutation<unknown, 'follow' | 'unfollow'>({
    label: (action) => (action === 'follow' ? 'Following…' : 'Unfollowing…'),
    mutationFn: (action) =>
      action === 'follow' ? followHashtag(id) : unfollowHashtag(id),
    snapshotKeys: () =>
      listScopeKeys(
        hashtagQueries.byName(id).queryKey,
        hashtagQueries.followed().queryKey
      ),
    applyOptimistic: (qc, action) => {
      const isFollow = action === 'follow'
      qc.setQueryData<any>(hashtagQueries.byName(id).queryKey, (prev: any) =>
        prev ? { ...prev, following: isFollow } : prev
      )
    },
    onSuccess: (_data, _vars, qc) => {
      // The followed list is a separate server query; reconcile via refetch.
      qc.invalidateQueries({ queryKey: hashtagQueries.followed().queryKey })
    },
  })

  const handleOnFollow = () => {
    followMutation.mutate('follow')
  }

  const handleOnUnfollow = () => {
    followMutation.mutate('unfollow')
  }

  const { data: hashtag, isPending } = useQuery(hashtagQueries.byName(id))

  const {
    data: feed,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
    isFetching,
    error,
  } = useInfiniteQuery(hashtagQueries.feed(id))

  const { data: related } = useQuery({
    ...hashtagQueries.related(id),
    enabled: !!feed && !!hashtag,
  })

  const flattenedData = useMemo(() => feed?.pages.flat() || [], [feed?.pages])

  const keyExtractor = useCallback((item: any) => item?.id.toString(), [])

  const handleEndReached = useCallback(() => {
    if (hasNextPage && !isFetching) {
      fetchNextPage()
    }
  }, [hasNextPage, isFetching, fetchNextPage])

  const Header = useCallback(
    ({ hashtag, feed, onUnfollow, onFollow }: any) => {
      return (
        <View>
          <View p="$4" flexShrink={1}>
            <XStack alignItems="center" gap="$4">
              <View w={100} h={100}>
                {feed?.pages[0].length ? (
                  <ImageComponent
                    placeholder={{
                      blurhash: feed.pages[0][0]?.media_attachments[0]?.blurhash || '',
                    }}
                    source={{ uri: toImageUri(feed.pages[0][0].media_attachments[0]) }}
                    style={
                      {
                        width: 100,
                        height: 100,
                        borderRadius: 100,
                        borderWidth: 1,
                        borderColor: theme.borderColor.val,
                      } as any
                    }
                    contentFit={'cover'}
                  />
                ) : (
                  <View
                    w={100}
                    h={100}
                    borderRadius={100}
                    borderCurve="continuous"
                    bg={theme.backgroundTertiary.val}
                  ></View>
                )}
              </View>
              <YStack flex={1} justifyContent="center" alignItems="center" gap="$2">
                <Text fontSize="$6" allowFontScaling={false}>
                  <Text fontWeight="bold" color={theme.color.val}>
                    {prettyCount(hashtag?.count ?? 0)}
                  </Text>{' '}
                  <Text color={theme.color.val}>posts</Text>
                </Text>
                {hashtag?.count > 0 ? (
                  <>
                    {hashtag.following ? (
                      <Button
                        borderColor={theme.borderColor.val}
                        h={35}
                        bg="transparent"
                        size="$5"
                        alignSelf="stretch"
                        onPress={onUnfollow}
                      >
                        <Button.Text fontWeight="bold" color={theme.color.val}>
                          Unfollow
                        </Button.Text>
                      </Button>
                    ) : (
                      <Button
                        bg={theme.interactiveActive.val}
                        h={35}
                        size="$5"
                        alignSelf="stretch"
                        onPress={onFollow}
                      >
                        <Button.Text color="$onAccent" fontWeight="bold">
                          Follow
                        </Button.Text>
                      </Button>
                    )}
                    {hashtag.following ? (
                      <Text
                        fontSize="$4"
                        color={theme.colorTertiary.val}
                        flexWrap="wrap"
                        allowFontScaling={false}
                      >
                        You are following this hashtag
                      </Text>
                    ) : (
                      <Text
                        fontSize="$2"
                        color={theme.colorTertiary.val}
                        flexWrap="wrap"
                        allowFontScaling={false}
                      >
                        Follow to see posts like these in your home feed
                      </Text>
                    )}
                  </>
                ) : null}
              </YStack>
            </XStack>
          </View>
          <RelatedTags relatedTags={related} />
        </View>
      )
    },
    [hashtag, feed, related]
  )

  useScreenMenu({
    title: `#${id}`,
    intents: [
      {
        kind: 'commit',
        id: 'follow-hashtag',
        icon: hashtag?.following ? 'check-circle' : 'plus-circle',
        label: hashtag?.following ? 'Unfollow hashtag' : 'Follow hashtag',
        toggled: !!hashtag?.following,
        onPress: () => {
          if (hashtag?.following) handleOnUnfollow()
          else handleOnFollow()
        },
      },
    ],
  })

  if (isPending || (isFetching && !isFetchingNextPage)) return <LoadingView />
  if (error) return <ErrorState message={error?.message} />

  return (
    <ScreenScrollContainer variant="flashlist">
      {(scrollProps) => (
        <FlashList
          data={flattenedData}
          extraData={hashtag}
          keyExtractor={keyExtractor}
          renderItem={({ item }: any) => <RenderItem item={item} />}
          numColumns={3}
          showsVerticalScrollIndicator={false}
          onEndReached={handleEndReached}
          onEndReachedThreshold={0.4}
          ListEmptyComponent={
            <EmptyState icon="alert-circle" title="No posts with this tag" />
          }
          ListHeaderComponent={
            <Header
              hashtag={hashtag}
              feed={feed}
              onFollow={handleOnFollow}
              onUnfollow={handleOnUnfollow}
            />
          }
          ListFooterComponent={<SharedListFooter loading={isFetchingNextPage} />}
          onScroll={onScroll}
          contentInsetAdjustmentBehavior={scrollProps.contentInsetAdjustmentBehavior}
          contentInset={scrollProps.contentInset}
          scrollIndicatorInsets={scrollProps.scrollIndicatorInsets}
          contentContainerStyle={scrollProps.contentContainerStyle}
        />
      )}
    </ScreenScrollContainer>
  )
}
