import { FlashList } from '@shopify/flash-list'
import { useInfiniteQuery } from '@tanstack/react-query'
import { type ErrorBoundaryProps, Link, useRouter } from 'expo-router'
import { useCallback, useMemo } from 'react'
import { ActivityIndicator, Pressable, RefreshControl } from 'react-native'
import EmojiText from 'src/components/common/EmojiText'
import { ErrorState } from 'src/components/common/ErrorState'
import UserAvatar from 'src/components/common/UserAvatar'
import {
  ScreenScrollContainer,
  useAccentRefreshControlProps,
} from 'src/components/layout'
import { useMenuScroll, useScreenMenu } from 'src/components/menu'
import type { ChatConversationRow, ChatPreview } from 'src/lib/chat-shape'
import { chatQueries } from 'src/lib/queries/chats'
import { enforceLen, timeAgo } from 'src/utils'
import { Separator, Text, useTheme, View, XStack, YStack } from 'tamagui'

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

// Phase C §4.1 of the Mastodon follow-up plan: this screen used to redirect
// Mastodon-active sessions away because Mastodon DMs were deferred. Phase C
// reverses that — the inbox now consumes the protocol-agnostic
// `ChatConversationRow` produced by `chat-shape`, so the Pixelfed and
// Mastodon wire shapes both render through the same RenderItem below.

function previewLine(preview: ChatPreview): string {
  if (preview.kind === 'empty') return ''
  if (preview.kind === 'text') return preview.text
  const isSelf = preview.isSelf
  switch (preview.kind) {
    case 'photo':
      return isSelf ? 'You sent a photo' : 'Sent a photo'
    case 'photo:album':
      return isSelf ? 'You sent multiple photos' : 'Sent multiple photos'
    case 'video':
      return isSelf ? 'You sent a video' : 'Sent a video'
    case 'audio':
      return isSelf ? 'You sent audio' : 'Sent audio'
    case 'gifv':
      return isSelf ? 'You sent a GIF' : 'Sent a GIF'
    case 'story':
      return isSelf ? 'You replied to their story' : 'Replied to your story'
  }
}

export default function Page() {
  const theme = useTheme()
  const router = useRouter()
  const refreshProps = useAccentRefreshControlProps()

  useScreenMenu({
    intents: [
      {
        kind: 'menu',
        accessibilityLabel: 'Chats options',
        items: [
          {
            id: 'blocked',
            label: 'Blocked accounts',
            icon: 'slash',
            onPress: () => router.push('/settings/privacy/blocked-accounts'),
          },
          {
            id: 'requests',
            label: 'Message requests',
            icon: 'inbox',
            onPress: () => router.push('/settings/notifications/requests'),
          },
        ],
      },
      {
        kind: 'commit',
        id: 'new-message',
        icon: 'edit',
        label: 'New message',
        onPress: () => router.push('/chats/search'),
      },
    ],
  })

  const keyExtractor = useCallback((item: ChatConversationRow) => item.id, [])

  const {
    data,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
    isFetchingPreviousPage,
    isRefetching,
    refetch,
    isFetching,
    isError,
    error,
  } = useInfiniteQuery(chatQueries.conversations())

  const flattenedData = useMemo<ChatConversationRow[]>(
    () => data?.pages.flatMap((page) => page.data) ?? [],
    [data?.pages]
  )

  const onScroll = useMenuScroll(true)

  if (isFetching && !isFetchingNextPage && !isFetchingPreviousPage && !isRefetching) {
    return (
      <View flexGrow={1} mt="$5">
        <ActivityIndicator color={theme.color.val} />
      </View>
    )
  }

  if (isError) {
    return <Text>Error: {error?.message}</Text>
  }

  const RenderItem = ({ item }: { item: ChatConversationRow }) => {
    const other = item.participants[0]
    if (!other) return null
    const extra = item.participants.length > 1 ? ` +${item.participants.length - 1}` : ''
    const content = previewLine(item.preview)
    const isSelfFlag =
      item.preview.kind !== 'empty' &&
      item.preview.kind !== 'text' &&
      'isSelf' in item.preview
        ? item.preview.isSelf
        : item.preview.kind === 'text'
          ? item.preview.isSelf
          : false

    return (
      <View p="$3" bg={theme.background.val}>
        <Link href={`/chats/conversation/${item.threadKey}`} asChild>
          <Pressable>
            <XStack alignItems="center" gap="$3">
              <UserAvatar url={other.avatar} size="sm" />

              <YStack flexGrow={1} gap={4}>
                <XStack alignItems="center" gap="$2">
                  <EmojiText
                    variant="display"
                    text={enforceLen(
                      ((other.display_name as string) ?? '').trim() || other.acct,
                      40,
                      true
                    )}
                    emojis={other.emojis}
                  />
                  {extra ? (
                    <Text color={theme.colorTertiary.val} fontSize="$3">
                      {extra}
                    </Text>
                  ) : null}
                  {item.unread ? (
                    <View
                      width={8}
                      height={8}
                      borderRadius={4}
                      bg={theme.interactiveActive.val}
                    />
                  ) : null}
                </XStack>
                <XStack gap="$2" alignItems="center">
                  <Text
                    fontSize="$2"
                    allowFontScaling={false}
                    flexWrap="wrap"
                    color={theme.colorTertiary.val}
                    fontWeight={isSelfFlag ? 'normal' : 'bold'}
                  >
                    {content}
                  </Text>
                  {item.lastStatus ? (
                    <>
                      <Text
                        fontSize="$2"
                        allowFontScaling={false}
                        color={theme.colorTertiary.val}
                      >
                        ·
                      </Text>
                      <Text
                        fontSize="$2"
                        allowFontScaling={false}
                        color={theme.colorTertiary.val}
                      >
                        {timeAgo(item.lastStatus.createdAt)} ago
                      </Text>
                    </>
                  ) : null}
                </XStack>
              </YStack>
            </XStack>
          </Pressable>
        </Link>
      </View>
    )
  }

  return (
    <ScreenScrollContainer variant="flashlist">
      {(scrollProps) => (
        <FlashList
          data={flattenedData}
          keyExtractor={keyExtractor}
          renderItem={RenderItem}
          refreshControl={
            <RefreshControl
              refreshing={isRefetching}
              onRefresh={refetch}
              progressViewOffset={scrollProps.topInset}
              {...refreshProps}
            />
          }
          ItemSeparatorComponent={() => <Separator borderColor={theme.borderColor.val} />}
          onEndReached={() => {
            if (hasNextPage && !isFetching && !isFetchingNextPage) fetchNextPage()
          }}
          onEndReachedThreshold={0.5}
          ListFooterComponent={() =>
            isFetching || isFetchingNextPage || isFetchingPreviousPage || isRefetching ? (
              <View h={200} justifyContent="center" alignItems="center">
                <ActivityIndicator />
              </View>
            ) : (
              <View h={200}></View>
            )
          }
          onScroll={onScroll}
          contentInsetAdjustmentBehavior={scrollProps.contentInsetAdjustmentBehavior}
          contentInset={scrollProps.contentInset}
          scrollIndicatorInsets={scrollProps.scrollIndicatorInsets}
          contentContainerStyle={scrollProps.contentContainerStyle}
        />
      )}
    </ScreenScrollContainer>
  )
}
