import {type JSX, useCallback, useMemo, useState} from 'react'
import {
  ActivityIndicator,
  FlatList as RNFlatList,
  RefreshControl,
  type StyleProp,
  View,
  type ViewStyle,
} from 'react-native'
import {type AppBskyGraphDefs as GraphDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'

import {usePalette} from '#/lib/hooks/usePalette'
import {cleanError} from '#/lib/strings/errors'
import {s} from '#/lib/styles'
import {logger} from '#/logger'
import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {type MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists'
import {atoms as a, useTheme} from '#/alf'
import {BulletList_Stroke1_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList'
import * as ListCard from '#/components/ListCard'
import {Text} from '#/components/Typography'
import {ErrorMessage} from '../util/error/ErrorMessage'
import {List} from '../util/List'

const LOADING = {_reactKey: '__loading__'}
const EMPTY = {_reactKey: '__empty__'}
const ERROR_ITEM = {_reactKey: '__error__'}

export function MyLists({
  filter,
  inline,
  style,
  renderItem,
  testID,
}: {
  filter: MyListsFilter
  inline?: boolean
  style?: StyleProp<ViewStyle>
  renderItem?: (list: GraphDefs.ListView, index: number) => JSX.Element
  testID?: string
}) {
  const pal = usePalette('default')
  const t = useTheme()
  const {_} = useLingui()
  const moderationOpts = useModerationOpts()
  const [isPTRing, setIsPTRing] = useState(false)
  const {data, isFetching, isFetched, isError, error, refetch} =
    useMyListsQuery(filter)
  const isEmpty = !isFetching && !data?.length
  const enableSquareButtons = useEnableSquareButtons()

  const items = useMemo(() => {
    let items: any[] = []
    if (isError && isEmpty) {
      items = items.concat([ERROR_ITEM])
    }
    if ((!isFetched && isFetching) || !moderationOpts) {
      items = items.concat([LOADING])
    } else if (isEmpty) {
      items = items.concat([EMPTY])
    } else {
      items = items.concat(data)
    }
    return items
  }, [isError, isEmpty, isFetched, isFetching, moderationOpts, data])

  let emptyText
  switch (filter) {
    case 'curate':
      emptyText = _(
        msg`Lists allow you to see content from your favorite people.`,
      )
      break
    case 'mod':
      emptyText = _(
        msg`Public, sharable lists of users to mute or block in bulk.`,
      )
      break
    default:
      emptyText = _(msg`You have no lists.`)
      break
  }

  // events
  // =

  const onRefresh = useCallback(async () => {
    setIsPTRing(true)
    try {
      await refetch()
    } catch (err) {
      logger.error('Failed to refresh lists', {message: err})
    }
    setIsPTRing(false)
  }, [refetch, setIsPTRing])

  // rendering
  // =

  const renderItemInner = useCallback(
    ({item, index}: {item: any; index: number}) => {
      if (item === EMPTY) {
        return (
          <View style={[a.flex_1, a.align_center, a.gap_sm, a.px_xl, a.pt_3xl]}>
            <View
              style={[
                a.align_center,
                a.justify_center,
                enableSquareButtons ? a.rounded_sm : a.rounded_full,
                {
                  width: 64,
                  height: 64,
                },
              ]}>
              <ListIcon size="2xl" fill={t.atoms.text_contrast_medium.color} />
            </View>
            <Text
              style={[
                a.text_center,
                a.flex_1,
                a.text_sm,
                a.leading_snug,
                t.atoms.text_contrast_medium,
                {
                  maxWidth: 200,
                },
              ]}>
              {emptyText}
            </Text>
          </View>
        )
      } else if (item === ERROR_ITEM) {
        return (
          <ErrorMessage
            message={cleanError(error)}
            onPressTryAgain={onRefresh}
          />
        )
      } else if (item === LOADING) {
        return (
          <View style={{padding: 20}}>
            <ActivityIndicator color={t.palette.primary_500} />
          </View>
        )
      }
      return renderItem ? (
        renderItem(item, index)
      ) : (
        <View
          style={[
            index !== 0 && a.border_t,
            t.atoms.border_contrast_low,
            a.px_lg,
            a.py_lg,
          ]}>
          <ListCard.Default view={item} />
        </View>
      )
    },
    [t, renderItem, error, onRefresh, emptyText, enableSquareButtons],
  )

  if (inline) {
    return (
      <View testID={testID} style={style}>
        {items.length > 0 && (
          <RNFlatList
            testID={testID ? `${testID}-flatlist` : undefined}
            data={items}
            keyExtractor={item => (item.uri ? item.uri : item._reactKey)}
            renderItem={renderItemInner}
            refreshControl={
              <RefreshControl
                refreshing={isPTRing}
                onRefresh={onRefresh}
                tintColor={pal.colors.text}
                titleColor={pal.colors.text}
              />
            }
            contentContainerStyle={[s.contentContainer]}
            removeClippedSubviews={true}
          />
        )}
      </View>
    )
  } else {
    return (
      <View testID={testID} style={style}>
        {items.length > 0 && (
          <List
            testID={testID ? `${testID}-flatlist` : undefined}
            data={items}
            keyExtractor={item => (item.uri ? item.uri : item._reactKey)}
            renderItem={renderItemInner}
            refreshing={isPTRing}
            onRefresh={onRefresh}
            contentContainerStyle={[s.contentContainer]}
            removeClippedSubviews={true}
            desktopFixedHeight
            sideBorders={false}
          />
        )}
      </View>
    )
  }
}
