import { FlashList } from '@shopify/flash-list'
import { useQuery } from '@tanstack/react-query'
import type { ErrorBoundaryProps } from 'expo-router'
import { Link } from 'expo-router'
import { useMemo, useState } from 'react'
import { ActivityIndicator, Pressable } 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 { Switch } from 'src/components/form/Switch'
import { ScreenScrollContainer } from 'src/components/layout'
import { useMenuScroll, useScreenMenu, useSearchQuery } from 'src/components/menu'
import { listScopeKeys, useCacheMutation } from 'src/hooks/mutations/cacheMutation'
import { useConfirmDialog } from 'src/hooks/useConfirmDialog'
import { accountFollowRequestAccept, accountFollowRequestReject } from 'src/lib/api'
import { accountQueries } from 'src/lib/queries/accounts'
import { enforceLen } from 'src/utils'
import { Button, Text, useTheme, View, XStack, YStack } from 'tamagui'

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

export default function FollowersScreen() {
  const theme = useTheme()
  const [showAlert, setAlert] = useState(true)
  const [query, setQuery] = useSearchQuery()
  const onScroll = useMenuScroll(true)
  const { confirm, dialog: confirmDialog } = useConfirmDialog()
  useScreenMenu({
    title: 'Follow Requests',
    intents: [
      {
        kind: 'search',
        placeholder: 'Filter requests',
        value: query,
        onChangeText: setQuery,
      },
    ],
  })

  const RenderItem = ({ item }: { item: any }) => {
    return (
      <View p="$3" bg={theme.background.val}>
        <XStack gap="$3" justifyContent="space-between" alignItems="center">
          <XStack width="60%" gap="$3" alignItems="center">
            <Link href={`/profile/${item.id}`} asChild>
              <Pressable>
                <UserAvatar url={item.avatar} size="md" />
              </Pressable>
            </Link>
            <YStack flexShrink={1}>
              <EmojiText
                text={item.display_name}
                emojis={item.emojis}
                fontSize="$3"
                color="$gray10"
              />
              <Text fontSize="$5" fontWeight="bold" flexWrap="wrap">
                @{enforceLen(item.acct, 20, true, 'middle')}
              </Text>
            </YStack>
          </XStack>
          <XStack width="40%" gap="$3" alignItems="center">
            <Button
              size="$3"
              theme="red"
              onPress={() => _handleMutation('reject', item.id)}
            >
              Reject
            </Button>
            <Button
              size="$3"
              theme="blue"
              onPress={() => _handleMutation('accept', item.id)}
            >
              Approve
            </Button>
          </XStack>
        </XStack>
      </View>
    )
  }

  const RenderEmpty = () => (
    <View
      bg={theme.background.val}
      py="$5"
      flexGrow={1}
      justifyContent="center"
      alignItems="center"
    >
      <Text fontSize="$6">You don't have any follow requests!</Text>
    </View>
  )

  const { data: feed, error, isFetching } = useQuery(accountQueries.followRequests())

  const filteredFeed = useMemo(() => {
    const q = query.trim().toLowerCase()
    if (!q || !Array.isArray(feed)) return feed
    return feed.filter((item: any) => {
      const acct = item?.acct?.toLowerCase() ?? ''
      const name = item?.display_name?.toLowerCase() ?? ''
      return acct.includes(q) || name.includes(q)
    })
  }, [feed, query])

  const mutation = useCacheMutation<unknown, { type: 'accept' | 'reject'; id: string }>({
    label: ({ type }) => (type === 'accept' ? 'Accepting…' : 'Rejecting…'),
    mutationFn: ({ type, id }) =>
      type === 'accept' ? accountFollowRequestAccept(id) : accountFollowRequestReject(id),
    snapshotKeys: () => listScopeKeys(accountQueries.followRequests().queryKey),
    applyOptimistic: (qc, { id }) => {
      qc.setQueryData<any[]>(accountQueries.followRequests().queryKey, (prev) =>
        Array.isArray(prev) ? prev.filter((item) => item.id !== id) : prev
      )
    },
    onSuccess: (_data, _vars, qc) => {
      // Defensive refetch — the row is already gone optimistically, but the
      // server may have surfaced other state changes (e.g. new relationship).
      qc.invalidateQueries({ queryKey: accountQueries.followRequests().queryKey })
    },
  })

  const _handleMutation = async (type: any, id: any) => {
    if (showAlert) {
      const isAccept = type === 'accept'
      const ok = await confirm({
        title: `Confirm ${isAccept ? 'Accept' : 'Rejection'}`,
        message: `Are you sure you want to ${isAccept ? 'accept' : 'reject'} this follow application?`,
        confirmLabel: isAccept ? 'Accept' : 'Reject',
        destructive: !isAccept,
      })
      if (!ok) return
      mutation.mutate({ type: type, id: id })
      return
    }
    mutation.mutate({ type: type, id: id })
  }

  const ItemSeparator = () => <View h={1} bg="$gray5"></View>

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

  if (error) {
    return (
      <View flexGrow={1}>
        <Text>Error</Text>
      </View>
    )
  }

  // The "Show alert" toggle rides as ListHeaderComponent so the FlashList
  // remains the only child the container hands its scroll geometry to.
  // Pre-Batch-F it was a sibling above the list inside SafeAreaView; the
  // change scrolls it with content but keeps it on screen at rest.
  const ListHeader = (
    <XStack
      justifyContent="space-between"
      alignItems="center"
      p="$3"
      bg={theme.background.val}
    >
      <Text>Show alert</Text>
      <Switch
        size="$2"
        defaultChecked={showAlert}
        onCheckedChange={(checked) => setAlert(checked)}
      >
        <Switch.Thumb transition="quicker" />
      </Switch>
    </XStack>
  )

  return (
    <>
      <ScreenScrollContainer variant="flashlist">
        {(scrollProps) => (
          <FlashList
            data={filteredFeed}
            renderItem={RenderItem}
            keyExtractor={(item, _index) => item.id.toString()}
            ItemSeparatorComponent={ItemSeparator}
            ListHeaderComponent={ListHeader}
            showsVerticalScrollIndicator={false}
            ListEmptyComponent={RenderEmpty}
            ListFooterComponent={() => (isFetching ? <ActivityIndicator /> : null)}
            onScroll={onScroll}
            contentInsetAdjustmentBehavior={scrollProps.contentInsetAdjustmentBehavior}
            contentInset={scrollProps.contentInset}
            scrollIndicatorInsets={scrollProps.scrollIndicatorInsets}
            contentContainerStyle={scrollProps.contentContainerStyle}
          />
        )}
      </ScreenScrollContainer>
      {confirmDialog}
    </>
  )
}
