import { Feather } from '@expo/vector-icons'
import { useQuery } from '@tanstack/react-query'
import type { ErrorBoundaryProps } from 'expo-router'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { ErrorState } from 'src/components/common/ErrorState'
import { ScreenScrollContainer } from 'src/components/layout'
import {
  BodyText,
  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. A manage-on-web link at the bottom hands off to the user's
// instance for create/edit/delete — Halflight does not mirror that surface
// natively (per plan §5: "local ordering only — no server writes, no
// create / edit / delete from the app").
//
// 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]
  )

  const instance = user?.instance
  const manageRow: LinkRowProps[] = instance
    ? [
        {
          kind: 'external',
          icon: 'external-link',
          title: `Manage lists on ${instance}`,
          description: 'Create, rename, and delete lists in the web UI.',
          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. The order applies to the home tab's list picker.
        </BodyText>
      </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="$2">
          <BodyText tone="secondary">You don't have any lists yet.</BodyText>
        </YStack>
      ) : (
        <YStack px="$5" pt="$5">
          <SortableList
            items={items}
            rowHeight={56}
            onReorder={onReorder}
            renderItem={(item, { isActive }) => (
              <ListRow title={item.title} isActive={isActive} />
            )}
          />
        </YStack>
      )}

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

function ListRow({ title, isActive }: { title: string; isActive: boolean }) {
  const theme = useTheme()
  return (
    <View
      bg="$backgroundSecondary"
      borderRadius="$3"
      borderWidth={1}
      borderColor={isActive ? theme.borderColorStrong.val : theme.borderColor.val}
      px="$4"
      my="$1"
      shadowColor={isActive ? theme.color.val : 'transparent'}
      shadowOpacity={isActive ? 0.15 : 0}
      shadowRadius={isActive ? 8 : 0}
      shadowOffset={{ width: 0, height: 2 }}
      flex={1}
      justifyContent="center"
    >
      <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>
      </XStack>
    </View>
  )
}
