import React from 'react'
import {View} from 'react-native'
import {Image} from 'expo-image'
import {
  AppBskyGraphDefs,
  AppBskyGraphStarterpack,
  AtUri,
  ModerationOpts,
  RichText as RichTextAPI,
} from '@atproto/api'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useNavigation} from '@react-navigation/native'
import {NativeStackScreenProps} from '@react-navigation/native-stack'
import {useQueryClient} from '@tanstack/react-query'

import {cleanError} from '#/lib/strings/errors'
import {logger} from '#/logger'
import {useDeleteStarterPackMutation} from '#/state/queries/starter-packs'
import {
  ProgressGuideAction,
  useProgressGuideControls,
} from '#/state/shell/progress-guide'
import {batchedUpdates} from 'lib/batchedUpdates'
import {HITSLOP_20} from 'lib/constants'
import {isBlockedOrBlocking, isMuted} from 'lib/moderation/blocked-and-muted'
import {makeProfileLink, makeStarterPackLink} from 'lib/routes/links'
import {CommonNavigatorParams, NavigationProp} from 'lib/routes/types'
import {logEvent} from 'lib/statsig/statsig'
import {getStarterPackOgCard} from 'lib/strings/starter-pack'
import {isWeb} from 'platform/detection'
import {updateProfileShadow} from 'state/cache/profile-shadow'
import {useModerationOpts} from 'state/preferences/moderation-opts'
import {useResolvedStarterPackShortLink} from 'state/queries/resolve-short-link'
import {useResolveDidQuery} from 'state/queries/resolve-uri'
import {useShortenLink} from 'state/queries/shorten-link'
import {useStarterPackQuery} from 'state/queries/starter-packs'
import {useAgent, useSession} from 'state/session'
import {useLoggedOutViewControls} from 'state/shell/logged-out'
import {useSetActiveStarterPack} from 'state/shell/starter-pack'
import * as Toast from '#/view/com/util/Toast'
import {PagerWithHeader} from 'view/com/pager/PagerWithHeader'
import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader'
import {CenteredView} from 'view/com/util/Views'
import {bulkWriteFollows} from '#/screens/Onboarding/util'
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {useDialogControl} from '#/components/Dialog'
import {ArrowOutOfBox_Stroke2_Corner0_Rounded as ArrowOutOfBox} from '#/components/icons/ArrowOutOfBox'
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
import {DotGrid_Stroke2_Corner0_Rounded as Ellipsis} from '#/components/icons/DotGrid'
import {Pencil_Stroke2_Corner0_Rounded as Pencil} from '#/components/icons/Pencil'
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
import {ListMaybePlaceholder} from '#/components/Lists'
import {Loader} from '#/components/Loader'
import * as Menu from '#/components/Menu'
import * as Prompt from '#/components/Prompt'
import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'
import {RichText} from '#/components/RichText'
import {FeedsList} from '#/components/StarterPack/Main/FeedsList'
import {PostsList} from '#/components/StarterPack/Main/PostsList'
import {ProfilesList} from '#/components/StarterPack/Main/ProfilesList'
import {QrCodeDialog} from '#/components/StarterPack/QrCodeDialog'
import {ShareDialog} from '#/components/StarterPack/ShareDialog'
import {Text} from '#/components/Typography'

type StarterPackScreeProps = NativeStackScreenProps<
  CommonNavigatorParams,
  'StarterPack'
>
type StarterPackScreenShortProps = NativeStackScreenProps<
  CommonNavigatorParams,
  'StarterPackShort'
>

export function StarterPackScreen({route}: StarterPackScreeProps) {
  return <StarterPackScreenInner routeParams={route.params} />
}

export function StarterPackScreenShort({route}: StarterPackScreenShortProps) {
  const {_} = useLingui()
  const {
    data: resolvedStarterPack,
    isLoading,
    isError,
  } = useResolvedStarterPackShortLink({
    code: route.params.code,
  })

  if (isLoading || isError || !resolvedStarterPack) {
    return (
      <ListMaybePlaceholder
        isLoading={isLoading}
        isError={isError}
        errorMessage={_(msg`That starter pack could not be found.`)}
        emptyMessage={_(msg`That starter pack could not be found.`)}
      />
    )
  }
  return <StarterPackScreenInner routeParams={resolvedStarterPack} />
}

export function StarterPackScreenInner({
  routeParams,
}: {
  routeParams: StarterPackScreeProps['route']['params']
}) {
  const {name, rkey} = routeParams
  const {_} = useLingui()
  const {currentAccount} = useSession()

  const moderationOpts = useModerationOpts()
  const {
    data: did,
    isLoading: isLoadingDid,
    isError: isErrorDid,
  } = useResolveDidQuery(name)
  const {
    data: starterPack,
    isLoading: isLoadingStarterPack,
    isError: isErrorStarterPack,
  } = useStarterPackQuery({did, rkey})

  const isValid =
    starterPack &&
    (starterPack.list || starterPack?.creator?.did === currentAccount?.did) &&
    AppBskyGraphDefs.validateStarterPackView(starterPack) &&
    AppBskyGraphStarterpack.validateRecord(starterPack.record)

  if (!did || !starterPack || !isValid || !moderationOpts) {
    return (
      <ListMaybePlaceholder
        isLoading={isLoadingDid || isLoadingStarterPack || !moderationOpts}
        isError={isErrorDid || isErrorStarterPack || !isValid}
        errorMessage={_(msg`That starter pack could not be found.`)}
        emptyMessage={_(msg`That starter pack could not be found.`)}
      />
    )
  }

  if (!starterPack.list && starterPack.creator.did === currentAccount?.did) {
    return <InvalidStarterPack rkey={rkey} />
  }

  return (
    <StarterPackScreenLoaded
      starterPack={starterPack}
      routeParams={routeParams}
      moderationOpts={moderationOpts}
    />
  )
}

function StarterPackScreenLoaded({
  starterPack,
  routeParams,
  moderationOpts,
}: {
  starterPack: AppBskyGraphDefs.StarterPackView
  routeParams: StarterPackScreeProps['route']['params']
  moderationOpts: ModerationOpts
}) {
  const showPeopleTab = Boolean(starterPack.list)
  const showFeedsTab = Boolean(starterPack.feeds?.length)
  const showPostsTab = Boolean(starterPack.list)
  const {_} = useLingui()

  const tabs = [
    ...(showPeopleTab ? [_(msg`People`)] : []),
    ...(showFeedsTab ? [_(msg`Feeds`)] : []),
    ...(showPostsTab ? [_(msg`Posts`)] : []),
  ]

  const qrCodeDialogControl = useDialogControl()
  const shareDialogControl = useDialogControl()

  const shortenLink = useShortenLink()
  const [link, setLink] = React.useState<string>()
  const [imageLoaded, setImageLoaded] = React.useState(false)

  React.useEffect(() => {
    logEvent('starterPack:opened', {
      starterPack: starterPack.uri,
    })
  }, [starterPack.uri])

  const onOpenShareDialog = React.useCallback(() => {
    const rkey = new AtUri(starterPack.uri).rkey
    shortenLink(makeStarterPackLink(starterPack.creator.did, rkey)).then(
      res => {
        setLink(res.url)
      },
    )
    Image.prefetch(getStarterPackOgCard(starterPack))
      .then(() => {
        setImageLoaded(true)
      })
      .catch(() => {
        setImageLoaded(true)
      })
    shareDialogControl.open()
  }, [shareDialogControl, shortenLink, starterPack])

  React.useEffect(() => {
    if (routeParams.new) {
      onOpenShareDialog()
    }
  }, [onOpenShareDialog, routeParams.new, shareDialogControl])

  return (
    <CenteredView style={[a.h_full_vh]}>
      <View style={isWeb ? {minHeight: '100%'} : {height: '100%'}}>
        <PagerWithHeader
          items={tabs}
          isHeaderReady={true}
          renderHeader={() => (
            <Header
              starterPack={starterPack}
              routeParams={routeParams}
              onOpenShareDialog={onOpenShareDialog}
            />
          )}>
          {showPeopleTab
            ? ({headerHeight, scrollElRef}) => (
                <ProfilesList
                  // Validated above
                  listUri={starterPack!.list!.uri}
                  headerHeight={headerHeight}
                  // @ts-expect-error
                  scrollElRef={scrollElRef}
                  moderationOpts={moderationOpts}
                />
              )
            : null}
          {showFeedsTab
            ? ({headerHeight, scrollElRef}) => (
                <FeedsList
                  // @ts-expect-error ?
                  feeds={starterPack?.feeds}
                  headerHeight={headerHeight}
                  // @ts-expect-error
                  scrollElRef={scrollElRef}
                />
              )
            : null}
          {showPostsTab
            ? ({headerHeight, scrollElRef}) => (
                <PostsList
                  // Validated above
                  listUri={starterPack!.list!.uri}
                  headerHeight={headerHeight}
                  // @ts-expect-error
                  scrollElRef={scrollElRef}
                  moderationOpts={moderationOpts}
                />
              )
            : null}
        </PagerWithHeader>
      </View>

      <QrCodeDialog
        control={qrCodeDialogControl}
        starterPack={starterPack}
        link={link}
      />
      <ShareDialog
        control={shareDialogControl}
        qrDialogControl={qrCodeDialogControl}
        starterPack={starterPack}
        link={link}
        imageLoaded={imageLoaded}
      />
    </CenteredView>
  )
}

function Header({
  starterPack,
  routeParams,
  onOpenShareDialog,
}: {
  starterPack: AppBskyGraphDefs.StarterPackView
  routeParams: StarterPackScreeProps['route']['params']
  onOpenShareDialog: () => void
}) {
  const {_} = useLingui()
  const t = useTheme()
  const {currentAccount, hasSession} = useSession()
  const agent = useAgent()
  const queryClient = useQueryClient()
  const setActiveStarterPack = useSetActiveStarterPack()
  const {requestSwitchToAccount} = useLoggedOutViewControls()
  const {captureAction} = useProgressGuideControls()

  const [isProcessing, setIsProcessing] = React.useState(false)

  const {record, creator} = starterPack
  const isOwn = creator?.did === currentAccount?.did
  const joinedAllTimeCount = starterPack.joinedAllTimeCount ?? 0

  const navigation = useNavigation<NavigationProp>()

  React.useEffect(() => {
    const onFocus = () => {
      if (hasSession) return
      setActiveStarterPack({
        uri: starterPack.uri,
      })
    }
    const onBeforeRemove = () => {
      if (hasSession) return
      setActiveStarterPack(undefined)
    }

    navigation.addListener('focus', onFocus)
    navigation.addListener('beforeRemove', onBeforeRemove)

    return () => {
      navigation.removeListener('focus', onFocus)
      navigation.removeListener('beforeRemove', onBeforeRemove)
    }
  }, [hasSession, navigation, setActiveStarterPack, starterPack.uri])

  const onFollowAll = async () => {
    if (!starterPack.list) return

    setIsProcessing(true)

    try {
      const list = await agent.app.bsky.graph.getList({
        list: starterPack.list.uri,
      })
      const dids = list.data.items
        .filter(
          li =>
            li.subject.did !== currentAccount?.did &&
            !isBlockedOrBlocking(li.subject) &&
            !isMuted(li.subject) &&
            !li.subject.viewer?.following,
        )
        .map(li => li.subject.did)

      const followUris = await bulkWriteFollows(agent, dids)

      batchedUpdates(() => {
        for (let did of dids) {
          updateProfileShadow(queryClient, did, {
            followingUri: followUris.get(did),
          })
        }
      })

      logEvent('starterPack:followAll', {
        logContext: 'StarterPackProfilesList',
        starterPack: starterPack.uri,
        count: dids.length,
      })
      captureAction(ProgressGuideAction.Follow, dids.length)
      Toast.show(_(msg`All accounts have been followed!`))
    } catch (e) {
      Toast.show(_(msg`An error occurred while trying to follow all`))
    } finally {
      setIsProcessing(false)
    }
  }

  if (!AppBskyGraphStarterpack.isRecord(record)) {
    return null
  }

  const richText = record.description
    ? new RichTextAPI({
        text: record.description,
        facets: record.descriptionFacets,
      })
    : undefined

  return (
    <>
      <ProfileSubpageHeader
        isLoading={false}
        href={makeProfileLink(creator)}
        title={record.name}
        isOwner={isOwn}
        avatar={undefined}
        creator={creator}
        avatarType="starter-pack">
        {hasSession ? (
          <View style={[a.flex_row, a.gap_sm, a.align_center]}>
            {isOwn ? (
              <Button
                label={_(msg`Share this starter pack`)}
                hitSlop={HITSLOP_20}
                variant="solid"
                color="primary"
                size="small"
                onPress={onOpenShareDialog}>
                <ButtonText>
                  <Trans>Share</Trans>
                </ButtonText>
              </Button>
            ) : (
              <Button
                label={_(msg`Follow all`)}
                variant="solid"
                color="primary"
                size="small"
                disabled={isProcessing}
                onPress={onFollowAll}>
                <ButtonText>
                  <Trans>Follow all</Trans>
                  {isProcessing && <Loader size="xs" />}
                </ButtonText>
              </Button>
            )}
            <OverflowMenu
              routeParams={routeParams}
              starterPack={starterPack}
              onOpenShareDialog={onOpenShareDialog}
            />
          </View>
        ) : null}
      </ProfileSubpageHeader>
      {!hasSession || richText || joinedAllTimeCount >= 25 ? (
        <View style={[a.px_lg, a.pt_md, a.pb_sm, a.gap_md]}>
          {richText ? (
            <RichText value={richText} style={[a.text_md, a.leading_snug]} />
          ) : null}
          {!hasSession ? (
            <Button
              label={_(msg`Join Bluesky`)}
              onPress={() => {
                setActiveStarterPack({
                  uri: starterPack.uri,
                })
                requestSwitchToAccount({requestedAccount: 'new'})
              }}
              variant="solid"
              color="primary"
              size="medium">
              <ButtonText style={[a.text_lg]}>
                <Trans>Join Bluesky</Trans>
              </ButtonText>
            </Button>
          ) : null}
          {joinedAllTimeCount >= 25 ? (
            <View style={[a.flex_row, a.align_center, a.gap_sm]}>
              <FontAwesomeIcon
                icon="arrow-trend-up"
                size={12}
                color={t.atoms.text_contrast_medium.color}
              />
              <Text
                style={[a.font_bold, a.text_sm, t.atoms.text_contrast_medium]}>
                <Trans>
                  {starterPack.joinedAllTimeCount || 0} people have used this
                  starter pack!
                </Trans>
              </Text>
            </View>
          ) : null}
        </View>
      ) : null}
    </>
  )
}

function OverflowMenu({
  starterPack,
  routeParams,
  onOpenShareDialog,
}: {
  starterPack: AppBskyGraphDefs.StarterPackView
  routeParams: StarterPackScreeProps['route']['params']
  onOpenShareDialog: () => void
}) {
  const t = useTheme()
  const {_} = useLingui()
  const {gtMobile} = useBreakpoints()
  const {currentAccount} = useSession()
  const reportDialogControl = useReportDialogControl()
  const deleteDialogControl = useDialogControl()
  const navigation = useNavigation<NavigationProp>()

  const {
    mutate: deleteStarterPack,
    isPending: isDeletePending,
    error: deleteError,
  } = useDeleteStarterPackMutation({
    onSuccess: () => {
      logEvent('starterPack:delete', {})
      deleteDialogControl.close(() => {
        if (navigation.canGoBack()) {
          navigation.popToTop()
        } else {
          navigation.navigate('Home')
        }
      })
    },
    onError: e => {
      logger.error('Failed to delete starter pack', {safeMessage: e})
    },
  })

  const isOwn = starterPack.creator.did === currentAccount?.did

  const onDeleteStarterPack = async () => {
    if (!starterPack.list) {
      logger.error(`Unable to delete starterpack because list is missing`)
      return
    }

    deleteStarterPack({
      rkey: routeParams.rkey,
      listUri: starterPack.list.uri,
    })
    logEvent('starterPack:delete', {})
  }

  return (
    <>
      <Menu.Root>
        <Menu.Trigger label={_(msg`Repost or quote post`)}>
          {({props}) => (
            <Button
              {...props}
              testID="headerDropdownBtn"
              label={_(msg`Open starter pack menu`)}
              hitSlop={HITSLOP_20}
              variant="solid"
              color="secondary"
              size="small"
              shape="round">
              <ButtonIcon icon={Ellipsis} />
            </Button>
          )}
        </Menu.Trigger>
        <Menu.Outer style={{minWidth: 170}}>
          {isOwn ? (
            <>
              <Menu.Item
                label={_(msg`Edit starter pack`)}
                testID="editStarterPackLinkBtn"
                onPress={() => {
                  navigation.navigate('StarterPackEdit', {
                    rkey: routeParams.rkey,
                  })
                }}>
                <Menu.ItemText>
                  <Trans>Edit</Trans>
                </Menu.ItemText>
                <Menu.ItemIcon icon={Pencil} position="right" />
              </Menu.Item>
              <Menu.Item
                label={_(msg`Delete starter pack`)}
                testID="deleteStarterPackBtn"
                onPress={() => {
                  deleteDialogControl.open()
                }}>
                <Menu.ItemText>
                  <Trans>Delete</Trans>
                </Menu.ItemText>
                <Menu.ItemIcon icon={Trash} position="right" />
              </Menu.Item>
            </>
          ) : (
            <>
              <Menu.Group>
                <Menu.Item
                  label={_(msg`Share`)}
                  testID="shareStarterPackLinkBtn"
                  onPress={onOpenShareDialog}>
                  <Menu.ItemText>
                    <Trans>Share link</Trans>
                  </Menu.ItemText>
                  <Menu.ItemIcon icon={ArrowOutOfBox} position="right" />
                </Menu.Item>
              </Menu.Group>

              <Menu.Item
                label={_(msg`Report starter pack`)}
                onPress={reportDialogControl.open}>
                <Menu.ItemText>
                  <Trans>Report starter pack</Trans>
                </Menu.ItemText>
                <Menu.ItemIcon icon={CircleInfo} position="right" />
              </Menu.Item>
            </>
          )}
        </Menu.Outer>
      </Menu.Root>

      {starterPack.list && (
        <ReportDialog
          control={reportDialogControl}
          params={{
            type: 'starterpack',
            uri: starterPack.uri,
            cid: starterPack.cid,
          }}
        />
      )}

      <Prompt.Outer control={deleteDialogControl}>
        <Prompt.TitleText>
          <Trans>Delete starter pack?</Trans>
        </Prompt.TitleText>
        <Prompt.DescriptionText>
          <Trans>Are you sure you want delete this starter pack?</Trans>
        </Prompt.DescriptionText>
        {deleteError && (
          <View
            style={[
              a.flex_row,
              a.gap_sm,
              a.rounded_sm,
              a.p_md,
              a.mb_lg,
              a.border,
              t.atoms.border_contrast_medium,
              t.atoms.bg_contrast_25,
            ]}>
            <View style={[a.flex_1, a.gap_2xs]}>
              <Text style={[a.font_bold]}>
                <Trans>Unable to delete</Trans>
              </Text>
              <Text style={[a.leading_snug]}>{cleanError(deleteError)}</Text>
            </View>
            <CircleInfo size="sm" fill={t.palette.negative_400} />
          </View>
        )}
        <Prompt.Actions>
          <Button
            variant="solid"
            color="negative"
            size={gtMobile ? 'small' : 'medium'}
            label={_(msg`Yes, delete this starter pack`)}
            onPress={onDeleteStarterPack}>
            <ButtonText>
              <Trans>Delete</Trans>
            </ButtonText>
            {isDeletePending && <ButtonIcon icon={Loader} />}
          </Button>
          <Prompt.Cancel />
        </Prompt.Actions>
      </Prompt.Outer>
    </>
  )
}

function InvalidStarterPack({rkey}: {rkey: string}) {
  const {_} = useLingui()
  const t = useTheme()
  const navigation = useNavigation<NavigationProp>()
  const {gtMobile} = useBreakpoints()
  const [isProcessing, setIsProcessing] = React.useState(false)

  const goBack = () => {
    if (navigation.canGoBack()) {
      navigation.goBack()
    } else {
      navigation.replace('Home')
    }
  }

  const {mutate: deleteStarterPack} = useDeleteStarterPackMutation({
    onSuccess: () => {
      setIsProcessing(false)
      goBack()
    },
    onError: e => {
      setIsProcessing(false)
      logger.error('Failed to delete invalid starter pack', {safeMessage: e})
      Toast.show(_(msg`Failed to delete starter pack`))
    },
  })

  return (
    <CenteredView
      style={[
        a.flex_1,
        a.align_center,
        a.gap_5xl,
        !gtMobile && a.justify_between,
        t.atoms.border_contrast_low,
        {paddingTop: 175, paddingBottom: 110},
      ]}
      sideBorders={true}>
      <View style={[a.w_full, a.align_center, a.gap_lg]}>
        <Text style={[a.font_bold, a.text_3xl]}>
          <Trans>Starter pack is invalid</Trans>
        </Text>
        <Text
          style={[
            a.text_md,
            a.text_center,
            t.atoms.text_contrast_high,
            {lineHeight: 1.4},
            gtMobile ? {width: 450} : [a.w_full, a.px_lg],
          ]}>
          <Trans>
            The starter pack that you are trying to view is invalid. You may
            delete this starter pack instead.
          </Trans>
        </Text>
      </View>
      <View style={[a.gap_md, gtMobile ? {width: 350} : [a.w_full, a.px_lg]]}>
        <Button
          variant="solid"
          color="primary"
          label={_(msg`Delete starter pack`)}
          size="large"
          style={[a.rounded_sm, a.overflow_hidden, {paddingVertical: 10}]}
          disabled={isProcessing}
          onPress={() => {
            setIsProcessing(true)
            deleteStarterPack({rkey})
          }}>
          <ButtonText>
            <Trans>Delete</Trans>
          </ButtonText>
          {isProcessing && <Loader size="xs" color="white" />}
        </Button>
        <Button
          variant="solid"
          color="secondary"
          label={_(msg`Return to previous page`)}
          size="large"
          style={[a.rounded_sm, a.overflow_hidden, {paddingVertical: 10}]}
          disabled={isProcessing}
          onPress={goBack}>
          <ButtonText>
            <Trans>Go Back</Trans>
          </ButtonText>
        </Button>
      </View>
    </CenteredView>
  )
}
