import {pickTagEmoji} from '@crumbs/core/emojis'
import type {ExtractCrumbDraft} from '@crumbs/core/schemas'
import {Redirect, Stack, useFocusEffect, useRouter} from 'expo-router'
import {SymbolView} from 'expo-symbols'
import {useCallback, useEffect, useRef, useState} from 'react'
import {ActivityIndicator, View} from 'react-native'

import {Button} from '@/components/ui/button'
import {Card} from '@/components/ui/card'
import {Divider} from '@/components/ui/divider'
import {Layout} from '@/components/ui/layout'
import {PressableRow} from '@/components/ui/pressable-row'
import {Thumbnail} from '@/components/ui/thumbnail'
import {Text} from '@/components/ui/typography'
import {useCrumbComposer} from '@/hooks/use-crumb-composer'
import {setPendingDraft} from '@/hooks/use-editable-draft'
import {useExtractDraft} from '@/hooks/use-extract-draft'
import {useSubmitAction} from '@/hooks/use-submit-action'
import {formatShortDate} from '@/lib/dates'
import {extractToDraft} from '@/lib/draft'
import {
  clearPendingShare,
  getPendingShare,
  type PendingShare,
} from '@/lib/pending-share'
import {suggestTrailFor} from '@/lib/suggest-trail'
import {atoms as a, useTheme} from '@/sprinkles'
import {useAddCrumb} from '@/stores/crumbs'
import {useRefreshTags} from '@/stores/tags'

export default function ScreengrabScreen() {
  const [share] = useState(getPendingShare)
  useEffect(() => clearPendingShare, [])
  if (!share) return <Redirect href="/" />
  return <ShareProcessor share={share} />
}

function ShareProcessor({share}: {share: PendingShare}) {
  const t = useTheme()
  const router = useRouter()
  const {outcome, run} = useExtractDraft(share)

  const statusRef = useRef(outcome.status)
  useEffect(() => {
    statusRef.current = outcome.status
  }, [outcome.status])

  // run on first focus and re-run when returning after a missing key
  useFocusEffect(
    useCallback(() => {
      if (
        statusRef.current === 'pending' ||
        statusRef.current === 'missing-key'
      )
        void run()
    }, [run]),
  )

  useEffect(() => {
    if (outcome.status === 'missing-key') router.push('/settings')
  }, [outcome, router])

  if (outcome.status === 'drafts' && outcome.drafts.length > 0)
    return <ExtractReview drafts={outcome.drafts} />

  return (
    <>
      <Stack.Screen options={{title: 'New crumbs'}} />
      <Layout.ModalContent>
        <View
          style={[
            a.flex_1,
            a.justify_center,
            a.align_center,
            a.gap_lg,
          ]}
        >
          {outcome.status === 'error' ? (
            <ExtractFallback message={outcome.message} retry={run} />
          ) : outcome.status === 'drafts' ? (
            <ExtractFallback message="We couldn't find anything to save in that share." />
          ) : (
            <>
              <ActivityIndicator />
              <Text style={t.atoms.text_contrast_medium}>
                Finding the details…
              </Text>
            </>
          )}
        </View>
      </Layout.ModalContent>
    </>
  )
}

function ExtractFallback({
  message,
  retry,
}: {
  message: string
  retry?: () => Promise<void>
}) {
  const t = useTheme()
  const {open} = useCrumbComposer()
  return (
    <>
      <Text style={[a.text_center, t.atoms.text_contrast_medium]}>
        {message}
      </Text>
      {retry && (
        <Button
          label="Try again"
          onPress={() => void retry()}
          color="primary"
          size="large"
          shape="rectangular"
        />
      )}
      <Button
        label="Add manually"
        onPress={open}
        color="secondary"
        size="large"
        shape="rectangular"
      />
    </>
  )
}

const draftEmoji = (draft: ExtractCrumbDraft): string =>
  pickTagEmoji(draft.tags[0] ?? draft.place?.category ?? '')

const draftSubtitle = (draft: ExtractCrumbDraft): string | null => {
  const when = draft.event?.startsAt
    ? formatShortDate(draft.event.startsAt)
    : null
  const where =
    draft.place?.address ?? draft.placeDraft?.address ?? null
  const parts = [when, draft.place?.category, where].filter(Boolean)
  return parts.length ? parts.join(' · ') : null
}

function ExtractReview({drafts}: {drafts: ExtractCrumbDraft[]}) {
  const t = useTheme()
  const router = useRouter()
  const addCrumb = useAddCrumb()
  const refreshTags = useRefreshTags()
  const [dismissed, setDismissed] = useState<readonly number[]>([])

  const kept = drafts.filter((_, i) => !dismissed.includes(i))
  const firstKept = drafts.findIndex((_, i) => !dismissed.includes(i))

  const dismiss = (index: number) =>
    setDismissed((cur) => [...cur, index])

  const edit = (draft: ExtractCrumbDraft) => {
    setPendingDraft(extractToDraft(draft))
    router.replace('/compose')
  }

  const {submitting: saving, submit} = useSubmitAction(
    async (extracts: ExtractCrumbDraft[]) => {
      const saved = await Promise.all(
        extracts.map((extracted) => {
          const draft = extractToDraft(extracted)
          return addCrumb({draft, tags: draft.tags})
        }),
      )
      void refreshTags()
      // a single save earns a trail suggestion + opens straight to the
      // crumb; bulk saves stay quiet and just close
      if (saved.length === 1) {
        void suggestTrailFor(saved[0]!.id)
        router.replace(`/crumb/${saved[0]!.id}`)
      } else {
        router.dismissAll()
      }
    },
    {alertOnError: true},
  )

  const save = () => {
    if (kept.length) void submit(kept)
  }

  const cta = saving
    ? 'Saving…'
    : kept.length > 1
      ? `Save ${kept.length} crumbs`
      : 'Save crumb'

  return (
    <>
      <Stack.Screen options={{title: 'New crumbs'}} />
      <Layout.ModalContent contentContainerStyle={a.gap_lg}>
        <View style={a.gap_xs}>
          <Layout.LargeTitle>What we found</Layout.LargeTitle>
          <Layout.Description>
            Tap a crumb to edit it before saving.
          </Layout.Description>
        </View>

        <Card>
          {drafts.map((draft, i) => {
            if (dismissed.includes(i)) return null
            const subtitle = draftSubtitle(draft)
            return (
              <View key={i}>
                {i !== firstKept && <Divider />}
                <View style={[a.flex_row, a.align_center, a.gap_sm]}>
                  <PressableRow
                    accessibilityLabel={`Edit ${draft.name}`}
                    onPress={() => edit(draft)}
                    style={[
                      a.flex_1,
                      a.flex_row,
                      a.align_center,
                      a.gap_md,
                      a.py_md,
                    ]}
                  >
                    {draft.imageUrl ? (
                      <Thumbnail
                        uri={draft.imageUrl}
                        width={44}
                        height={44}
                        accessibilityLabel={draft.name}
                      />
                    ) : (
                      <Text emoji style={a.text_2xl}>
                        {draftEmoji(draft)}
                      </Text>
                    )}
                    <View style={[a.flex_1, a.gap_xs]}>
                      <Text emoji>{draft.name}</Text>
                      {subtitle && (
                        <Text
                          numberOfLines={1}
                          style={[
                            a.text_sm,
                            t.atoms.text_contrast_medium,
                          ]}
                        >
                          {subtitle}
                        </Text>
                      )}
                    </View>
                  </PressableRow>
                  <Button
                    label={`Remove ${draft.name}`}
                    variant="ghost"
                    color="secondary"
                    size="small"
                    hitSlop={8}
                    onPress={() => dismiss(i)}
                  >
                    <SymbolView
                      name="xmark"
                      size={14}
                      weight="medium"
                      tintColor={t.palette.contrast_600}
                    />
                  </Button>
                </View>
              </View>
            )
          })}
          {kept.length === 0 && (
            <Text style={[a.py_lg, t.atoms.text_contrast_medium]}>
              Nothing left to save
            </Text>
          )}
        </Card>

        <Button
          label={cta}
          color="primary"
          size="large"
          shape="rectangular"
          onPress={save}
          disabled={!kept.length || saving}
        />
      </Layout.ModalContent>
    </>
  )
}
