import { Feather } from '@expo/vector-icons'
import { useRouter } from 'expo-router'
import { type GestureResponderEvent, Pressable } from 'react-native'
import EmojiText from 'src/components/common/EmojiText'
import { Favicon } from 'src/components/common/Favicon'
import { PressableOpacity } from 'src/components/common/PressableOpacity'
import UserAvatar from 'src/components/common/UserAvatar'
import ImageComponent from 'src/components/ImageComponent'
import type { PreviewCard, Status } from 'src/lib/api-types'
import { openBrowserAsync } from 'src/utils'
import { Text, useTheme, View, XStack, YStack } from 'tamagui'

// The server's `preview_card` slot is still stubbed on stock Pixelfed
// (ApiV1Controller.php:3533 returns `{}` and StatusTransformer sets
// `'card' => null`), so on most instances `card` is `null` and this
// component renders nothing. When the server patch that populates
// `status.card` lands — part of Batch C's Halflight "link previews"
// module — feed cells will start surfacing OpenGraph metadata automatically.
//
// The api-types file types `Status['card']` as `Array<PreviewCard>` but
// Mastodon's canonical shape is a single object. We accept both and pick
// the first entry defensively so neither shape breaks rendering.
type CardInput = Status['card'] | PreviewCard | null | undefined

export default function LinkPreviewCard({ card }: { card: CardInput }) {
  const c = normalizeCard(card)
  const theme = useTheme()
  const router = useRouter()
  if (!c || !c.url || !c.title) return null

  const host = c.provider_name?.trim() || hostFromUrl(c.url)
  const usesHero =
    !!c.image &&
    (c.type === 'rich' ||
      c.type === 'photo' ||
      c.type === 'video' ||
      (c.width ?? 0) >= 500)

  // Fediverse author attribution (Mastodon 4.3+ PreviewCard.authors). Falls
  // back to the resolved fediverse account → the raw author name/url → the
  // deprecated top-level author_name/author_url → nothing. Pixelfed omits
  // `authors` and leaves the deprecated fields empty, so `hasAuthor` is false
  // and no row renders — data-driven, no protocol gate.
  const primaryAuthor = c.authors?.[0] ?? null
  const authorName =
    primaryAuthor?.account?.display_name || primaryAuthor?.name || c.author_name || ''
  const authorUrl = primaryAuthor?.url || c.author_url || ''
  const authorEmojis = primaryAuthor?.account?.emojis
  const authorAvatar = primaryAuthor?.account?.avatar
  const authorAccountId = primaryAuthor?.account?.id
  const hasAuthor = !!authorName && (!!authorAccountId || !!authorUrl)

  // The whole card is a Pressable opening the article; the author region taps
  // independently. It's a real nested PressableOpacity (its own native view),
  // so RN's responder system lets the inner pressable win — `stopPropagation`
  // is belt-and-suspenders against the outer card also firing.
  const onAuthorPress = (e: GestureResponderEvent) => {
    e?.stopPropagation?.()
    if (authorAccountId) {
      router.push(`/profile/${authorAccountId}`)
    } else if (authorUrl) {
      openBrowserAsync(authorUrl)
    }
  }

  return (
    <Pressable
      onPress={() => openBrowserAsync(c.url)}
      style={({ pressed }) => ({ opacity: pressed ? 0.85 : 1 })}
    >
      <View
        borderWidth={1}
        borderColor={theme.borderColor.val}
        borderRadius={10}
        overflow="hidden"
        backgroundColor={theme.backgroundSecondary.val}
      >
        {usesHero && c.image ? (
          <View style={{ width: '100%', aspectRatio: 16 / 9 }}>
            <ImageComponent
              source={{ uri: c.image, width: 800, height: 420 }}
              style={{ width: '100%', height: '100%' }}
              resizeMode={'cover' as any}
              accessibilityLabel={c.title}
            />
            {c.type === 'video' ? (
              <View
                position="absolute"
                top={0}
                left={0}
                right={0}
                bottom={0}
                alignItems="center"
                justifyContent="center"
                pointerEvents="none"
              >
                <View
                  style={{
                    shadowColor: '#000',
                    shadowOffset: { width: 0, height: 2 },
                    shadowOpacity: 0.45,
                    shadowRadius: 6,
                    elevation: 6,
                  }}
                >
                  <Feather name="play-circle" size={56} color="#fff" />
                </View>
              </View>
            ) : null}
          </View>
        ) : null}
        <XStack gap="$3" p="$3" alignItems="center">
          {!usesHero && c.image ? (
            <ImageComponent
              source={{ uri: c.image, width: 120, height: 120 }}
              style={{ width: 60, height: 60, borderRadius: 6 }}
              resizeMode={'cover' as any}
              accessibilityLabel={c.title}
            />
          ) : null}
          <YStack flex={1} gap="$1">
            {host ? (
              <XStack gap="$2" alignItems="center">
                <Favicon variant="chip" host={host} size="xxs" />
                <Text
                  fontSize="$1"
                  color={theme.colorTertiary.val}
                  numberOfLines={1}
                  textTransform="uppercase"
                  letterSpacing={0.4}
                  fontWeight="600"
                  flexShrink={1}
                >
                  {host}
                </Text>
              </XStack>
            ) : null}
            <Text
              fontSize="$4"
              fontWeight="600"
              color={theme.color.val}
              numberOfLines={2}
            >
              {c.title}
            </Text>
            {c.description ? (
              <Text fontSize="$3" color={theme.colorSecondary.val} numberOfLines={2}>
                {c.description}
              </Text>
            ) : null}
            {hasAuthor ? (
              <PressableOpacity onPress={onAuthorPress} hitSlop={4}>
                <XStack alignItems="center" gap="$1.5" mt="$1">
                  {authorAvatar ? <UserAvatar url={authorAvatar} size="xs" /> : null}
                  <Text fontSize="$2" color={theme.colorSecondary.val}>
                    by{' '}
                  </Text>
                  <EmojiText
                    variant="caption"
                    text={authorName}
                    emojis={authorEmojis}
                    color={theme.color.val}
                    fontWeight="600"
                    flexShrink={1}
                    numberOfLines={1}
                  />
                </XStack>
              </PressableOpacity>
            ) : null}
          </YStack>
        </XStack>
      </View>
    </Pressable>
  )
}

function normalizeCard(input: CardInput): PreviewCard | null {
  if (!input) return null
  if (Array.isArray(input)) return input[0] ?? null
  return input
}

function hostFromUrl(url: string): string {
  try {
    return new URL(url).hostname.replace(/^www\./, '')
  } catch {
    return ''
  }
}
