import { Feather } from '@expo/vector-icons'
import { useQuery } from '@tanstack/react-query'
import { type ErrorBoundaryProps, Link, router } from 'expo-router'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { Pressable } from 'react-native'
import { ErrorState } from 'src/components/common/ErrorState'
import { ScreenScrollContainer } from 'src/components/layout'
import { useScreenMenu } from 'src/components/menu'
import {
  BodyText,
  Card,
  LinkRowGroup,
  type LinkRowProps,
  SortableList,
  SubheadText,
} from 'src/components/ui'
import { listsQueries } from 'src/lib/queries/lists'
import { useAuth } from 'src/state/AuthProvider'
import { applyListOrder, getListOrder, setListOrder } from 'src/state/storage'
import { Spinner, useTheme, View, XStack, YStack } from 'tamagui'

// Holistic Pass 4 Phase 5.1 — Mastodon Lists settings screen. The user can
// drag-to-reorder their server-side lists; ordering is stored locally
// per-account (`ui.lists.order.<accountId>`) and applied to the home tab
// list picker.
//
// Mastodon List Management proposal (v0.6) extends this screen forward:
// tap a row to manage list members + settings (Surface B); a `+` menu intent
// pushes the formSheet route that creates a new list (Surface D); the
// manage-on-web link is preserved as a fallback for power users / desktop.
//
// Pixelfed's `/api/v1/lists` is a stub returning `[]`, so the Settings
// landing entry to this screen is gated on `account.type === 'mastodon'`.
// Direct navigation here on a Pixelfed account renders a short explainer.

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

export default function ListsScreen() {
  const { user } = useAuth()
  const theme = useTheme()
  const isMastodon = user?.type === 'mastodon'
  const accountId = user?.accountId ?? ''

  const { data, isPending, error, refetch } = useQuery({
    ...listsQueries.lists(),
    enabled: isMastodon,
  })

  const serverLists = useMemo(() => data ?? [], [data])
  const serverIdsKey = serverLists.map((l) => l.id).join('|')

  // Mirror the ordered list locally so a drag commit re-renders this screen
  // immediately rather than waiting on a query refetch. Resync from server
  // when the catalogue changes (new list added, list deleted on the web).
  const [orderedIds, setOrderedIds] = useState<string[]>(() =>
    applyListOrder(serverLists, getListOrder(accountId)).map((l) => l.id)
  )

  useEffect(() => {
    if (!accountId) return
    const next = applyListOrder(serverLists, getListOrder(accountId)).map((l) => l.id)
    setOrderedIds((prev) => (prev.join('|') === next.join('|') ? prev : next))
  }, [accountId, serverIdsKey, serverLists])

  const byId = useMemo(() => new Map(serverLists.map((l) => [l.id, l])), [serverLists])
  const items = useMemo(
    () =>
      orderedIds.map((id) => byId.get(id)).filter((l): l is NonNullable<typeof l> => !!l),
    [orderedIds, byId]
  )

  const onReorder = useCallback(
    (newIds: string[]) => {
      setOrderedIds(newIds)
      if (accountId) setListOrder(accountId, newIds)
    },
    [accountId]
  )

  // Header menu — the `+` intent pushes the Surface D formSheet. Mastodon-only
  // (the rest of the page renders an explainer on Pixelfed), so we gate the
  // CTA on the same predicate. `back` is canonical for non-tab settings
  // screens.
  useScreenMenu({
    title: 'Lists',
    intents: isMastodon
      ? [
          { kind: 'back' },
          {
            kind: 'act',
            id: 'organize',
            label: 'Organize',
            icon: 'grid',
            weight: 'secondary',
            onPress: () => router.push('/settings/lists/organize' as any),
          },
          {
            kind: 'act',
            id: 'new-list',
            label: 'New list',
            icon: 'plus',
            weight: 'primary',
            onPress: () => router.push('/settings/lists/new' as any),
          },
        ]
      : [{ kind: 'back' }],
  })

  const instance = user?.instance
  const manageRow: LinkRowProps[] = instance
    ? [
        {
          kind: 'external',
          icon: 'external-link',
          title: `Manage lists on ${instance}`,
          description: 'Open the web UI for advanced settings.',
          url: `https://${instance}/lists`,
        },
      ]
    : []

  if (!isMastodon) {
    return (
      <ScreenScrollContainer variant="scroll" header="Lists">
        <YStack px="$5" pt="$4" pb="$2" gap="$2">
          <BodyText tone="secondary">
            Lists are a Mastodon-only feature. Switch to a Mastodon account to manage them
            here.
          </BodyText>
        </YStack>
      </ScreenScrollContainer>
    )
  }

  return (
    <ScreenScrollContainer variant="scroll" header="Lists">
      <YStack px="$5" pt="$4" pb="$2" gap="$2">
        <BodyText tone="secondary">
          Drag to reorder. Tap a list to manage members and settings.
        </BodyText>
      </YStack>

      <YStack px="$5" pt="$2" pb="$2">
        <Card
          tone="secondary"
          onPress={() => router.push('/settings/lists/organize' as any)}
          pressStyle={{ opacity: 0.7 }}
          accessibilityRole="button"
          accessibilityLabel="Organize lists — sort your follows into lists by dragging"
        >
          <XStack alignItems="center" gap="$3">
            <Feather name="grid" size={20} color={theme.color.val} />
            <YStack flex={1} gap={2}>
              <SubheadText emphasis="strong">Organize lists</SubheadText>
              <BodyText tone="secondary" fontSize="$caption">
                Drag your follows into lists, fast.
              </BodyText>
            </YStack>
            <Feather name="chevron-right" size={18} color={theme.colorTertiary.val} />
          </XStack>
        </Card>
      </YStack>

      {isPending ? (
        <YStack px="$5" pt="$8" alignItems="center">
          <Spinner color={theme.color.val} />
        </YStack>
      ) : error ? (
        <YStack px="$5" pt="$5">
          <ErrorState message={error.message} onRetry={refetch} />
        </YStack>
      ) : items.length === 0 ? (
        <YStack px="$5" pt="$5" gap="$3" alignItems="center">
          <BodyText tone="secondary">You don't have any lists yet.</BodyText>
          <Pressable
            onPress={() => router.push('/settings/lists/new' as any)}
            style={({ pressed }) => ({ opacity: pressed ? 0.7 : 1 })}
          >
            <XStack
              bg="$backgroundSecondary"
              px="$4"
              py="$3"
              borderRadius="$3"
              alignItems="center"
              gap="$2"
            >
              <Feather name="plus" size={16} color={theme.color.val} />
              <SubheadText emphasis="strong">Create your first list</SubheadText>
            </XStack>
          </Pressable>
        </YStack>
      ) : (
        <YStack px="$5" pt="$5">
          <SortableList
            items={items}
            rowHeight={56}
            onReorder={onReorder}
            renderItem={(item, { isActive }) => (
              <ListRow id={item.id} title={item.title} isActive={isActive} />
            )}
          />
        </YStack>
      )}

      <LinkRowGroup rows={manageRow} />
    </ScreenScrollContainer>
  )
}

// SortableList sizes each row to its `rowHeight` (56 px). Use an explicit
// inner height + margin instead of `flex: 1`: nesting Link→Pressable→View
// inside the absolutely-positioned `Animated.View` doesn't reliably
// propagate `flex: 1` through the Pressable, so the inner box collapsed to
// 0 in practice — borders rendered but content (icon + title + chevron)
// disappeared. With Link's `asChild`, the Tamagui View receives `onPress`
// directly and handles press feedback via `pressStyle`, so the legacy
// `<Pressable>` wrapper is unnecessary and was the part that broke layout.
function ListRow({
  id,
  title,
  isActive,
}: {
  id: string
  title: string
  isActive: boolean
}) {
  const theme = useTheme()
  return (
    <Link href={`/settings/lists/${id}` as any} asChild>
      <View
        bg="$backgroundSecondary"
        borderRadius="$3"
        borderWidth={1}
        borderColor={isActive ? theme.borderColorStrong.val : theme.borderColor.val}
        px="$4"
        my={4}
        height={48}
        shadowColor={isActive ? theme.color.val : 'transparent'}
        shadowOpacity={isActive ? 0.15 : 0}
        shadowRadius={isActive ? 8 : 0}
        shadowOffset={{ width: 0, height: 2 }}
        justifyContent="center"
        pressStyle={{ opacity: 0.7 }}
      >
        <XStack alignItems="center" gap="$3">
          <Feather
            name="menu"
            size={18}
            color={theme.colorTertiary.val as string}
            accessibilityLabel="Drag handle"
          />
          <SubheadText emphasis="strong" numberOfLines={1} flex={1}>
            {title}
          </SubheadText>
          <Feather
            name="chevron-right"
            size={16}
            color={theme.colorTertiary.val as string}
          />
        </XStack>
      </View>
    </Link>
  )
}
