import {memo, useMemo, useState} from 'react'
import {View} from 'react-native'
import {
  type AppBskyActorDefs,
  moderateProfile,
  type ModerationDecision,
  type ModerationOpts,
  type RichText as RichTextAPI,
} from '@atproto/api'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro'

import {useHaptics} from '#/lib/haptics'
import {isFollowedByMetricHidden} from '#/lib/metrics-display'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
import {formatJoinDate, niceDate} from '#/lib/strings/time'
import {
  sanitizeWebsiteForDisplay,
  sanitizeWebsiteForLink,
} from '#/lib/strings/website'
import {logger} from '#/logger'
import {type Shadow, useProfileShadow} from '#/state/cache/profile-shadow'
import {useShowGermDmButton} from '#/state/preferences'
import {useConfirmFollowUnfollow} from '#/state/preferences/confirm-follow-unfollow'
import {useHideScaryFollowButtons} from '#/state/preferences/hide-scary-follow-buttons'
import {useFollowedByMetricsDisplay} from '#/state/preferences/metrics-display-preference'
import {
  useProfileBlockMutationQueue,
  useProfileFollowMutationQueue,
} from '#/state/queries/profile'
import {type SessionAccount, useRequireAuth, useSession} from '#/state/session'
import {ProfileMenu} from '#/view/com/profile/ProfileMenu'
import {
  atoms as a,
  native,
  platform,
  tokens,
  useBreakpoints,
  useTheme,
  web,
} from '#/alf'
import {SubscribeProfileButton} from '#/components/activity-notifications/SubscribeProfileButton'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {DebugFieldDisplay} from '#/components/DebugFieldDisplay'
import {useDialogControl} from '#/components/Dialog'
import {FollowConfirmationDialog} from '#/components/dialogs/FollowConfirmationDialog'
import {MessageProfileButton} from '#/components/dms/MessageProfileButton'
import {EphemeralAccountSwitcher} from '#/components/EphemeralAccountSwitcher'
import {
  useEphemeralFollowAction,
  useEphemeralFollowIntent,
} from '#/components/hooks/useEphemeralFollowAction'
import {CalendarDays_Stroke2_Corner0_Rounded as CalendarDays} from '#/components/icons/CalendarDays'
import {
  Check_Stroke2_Corner0_Rounded as Check,
  DoubleCheck_Stroke2_Corner0_Rounded as DoubleCheck,
} from '#/components/icons/Check'
import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
import {ArrowShareRight_Stroke2_Corner2_Rounded as ArrowShareRight} from '#/components/icons/ArrowShareRight'
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {
  KnownFollowers,
  shouldShowKnownFollowers,
} from '#/components/KnownFollowers'
import {Link} from '#/components/Link'
import {ProfileBadges} from '#/components/ProfileBadges'
import * as Prompt from '#/components/Prompt'
import {RichText} from '#/components/RichText'
import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography'
import {useAnalytics} from '#/analytics'
import {IS_IOS, IS_NATIVE} from '#/env'
import {InviteFriendsDialog} from '#/features/inviteFriends'
import {useActorStatus} from '#/features/liveNow'
import {GermButton} from '../components/GermButton'
import {EditProfileDialog} from './EditProfileDialog'
import {ProfileHeaderHandle} from './Handle'
import {ProfileHeaderMetrics} from './Metrics'
import {ProfileHeaderShell} from './Shell'
import {ProfileHeaderSuggestedFollows} from './SuggestedFollows'

interface Props {
  profile: AppBskyActorDefs.ProfileViewDetailed
  descriptionRT: RichTextAPI | null
  moderationOpts: ModerationOpts
  hideBackButton?: boolean
  isPlaceholderProfile?: boolean
}

let ProfileHeaderStandard = ({
  profile: profileUnshadowed,
  descriptionRT,
  moderationOpts,
  hideBackButton = false,
  isPlaceholderProfile,
}: Props): React.ReactNode => {
  const t = useTheme()
  const {gtMobile} = useBreakpoints()
  const profile =
    useProfileShadow<AppBskyActorDefs.ProfileViewDetailed>(profileUnshadowed)
  const {currentAccount} = useSession()
  const {_, i18n} = useLingui()
  const showGermDmButton = useShowGermDmButton()
  const moderation = useMemo(
    () => moderateProfile(profile, moderationOpts),
    [profile, moderationOpts],
  )
  const [, queueUnblock] = useProfileBlockMutationQueue(profile)
  const unblockPromptControl = Prompt.usePromptControl()
  const [showSuggestedFollows, setShowSuggestedFollows] = useState(false)
  const [hasSeenAllSuggestedFollows, setHasSeenAllSuggestedFollows] =
    useState(false)
  const isBlockedUser =
    profile.viewer?.blocking ||
    profile.viewer?.blockedBy ||
    profile.viewer?.blockingByList

  const website = profile.website
  const websiteFormatted = sanitizeWebsiteForDisplay(website ?? '')

  const dateJoined = useMemo(() => {
    if (!profile.createdAt) return ''
    return formatJoinDate(profile.createdAt)
  }, [profile.createdAt])

  const dateJoinedExact = useMemo(() => {
    if (!profile.createdAt) return ''

    const createdAt = new Date(profile.createdAt)
    if (Number.isNaN(createdAt.getTime())) return ''

    return niceDate(i18n, createdAt)
  }, [i18n, profile.createdAt])

  const unblockAccount = async () => {
    try {
      await queueUnblock()
      Toast.show(_(msg({message: 'Account unblocked', context: 'toast'})))
    } catch (err) {
      const e = err as Error
      if (e?.name !== 'AbortError') {
        logger.error('Failed to unblock account', {message: e})
        Toast.show(_(msg`There was an issue! ${e.toString()}`), {type: 'error'})
      }
    }
  }

  const onRequestHide = () => {
    setHasSeenAllSuggestedFollows(true)
    setShowSuggestedFollows(false)
  }

  const isMe = currentAccount?.did === profile.did

  const {isActive: live} = useActorStatus(profile)

  // disable metrics
  const followedByMetricsDisplay = useFollowedByMetricsDisplay()

  return (
    <>
      <ProfileHeaderShell
        profile={profile}
        moderation={moderation}
        hideBackButton={hideBackButton}
        isPlaceholderProfile={isPlaceholderProfile}>
        <View
          style={[
            a.px_lg,
            a.pt_md,
            a.pb_sm,
            native(a.overflow_hidden),
            web({overflowX: 'clip', zIndex: 10}),
          ]}
          pointerEvents={IS_IOS ? 'auto' : 'box-none'}>
          <View
            style={[
              {paddingLeft: 90},
              a.flex_row,
              a.align_center,
              a.justify_end,
              a.gap_xs,
              a.pb_sm,
              a.flex_wrap,
            ]}
            pointerEvents={IS_IOS ? 'auto' : 'box-none'}>
            <HeaderStandardButtons
              profile={profile}
              moderation={moderation}
              moderationOpts={moderationOpts}
              onFollow={() => setShowSuggestedFollows(true)}
              onUnfollow={() => setShowSuggestedFollows(false)}
            />
          </View>
          <View
            style={[a.flex_col, a.gap_xs, a.pb_md, live ? a.pt_sm : a.pt_2xs]}>
            <View style={[a.flex_row, a.align_center, a.gap_xs, a.flex_1]}>
              <Text
                emoji
                testID="profileHeaderDisplayName"
                style={[
                  t.atoms.text,
                  gtMobile ? a.text_4xl : a.text_3xl,
                  a.self_start,
                  a.font_bold,
                  a.leading_tight,
                ]}>
                {sanitizeDisplayName(
                  profile.displayName || sanitizeHandle(profile.handle),
                  moderation.ui('displayName'),
                )}
                <View
                  style={[
                    a.pl_xs,
                    a.flex_row,
                    a.gap_2xs,
                    a.align_center,
                    {marginTop: platform({ios: 2})},
                  ]}>
                  <ProfileBadges profile={profile} size="lg" interactive />
                </View>
              </Text>
            </View>
            <ProfileHeaderHandle profile={profile} />
          </View>
          {!isPlaceholderProfile && !isBlockedUser && (
            <View style={a.gap_md}>
              <ProfileHeaderMetrics profile={profile} />
              {descriptionRT && !moderation.ui('profileView').blur ? (
                <View pointerEvents="auto">
                  <RichText
                    testID="profileHeaderDescription"
                    style={[a.text_md]}
                    numberOfLines={15}
                    selectable
                    value={descriptionRT}
                    enableTags
                    authorHandle={profile.handle}
                  />
                </View>
              ) : undefined}

              {showGermDmButton && profile.associated?.germ && (
                <GermButton germ={profile.associated.germ} profile={profile} />
              )}

              {!isMe &&
                !isFollowedByMetricHidden(followedByMetricsDisplay) &&
                !isBlockedUser &&
                shouldShowKnownFollowers(profile.viewer?.knownFollowers) && (
                  <View style={[a.flex_row, a.align_center, a.gap_sm]}>
                    <KnownFollowers
                      profile={profile}
                      moderationOpts={moderationOpts}
                      followedByDisplay={followedByMetricsDisplay}
                    />
                  </View>
                )}
            </View>
          )}

          <View style={[a.flex_row, a.flex_wrap, {gap: 10}, a.pt_md]}>
            {websiteFormatted && (
              <Link
                to={sanitizeWebsiteForLink(website ?? '')}
                label={_(msg({message: `Visit ${websiteFormatted}`}))}
                style={[a.flex_row, a.align_center, a.gap_xs]}>
                <Globe
                  width={tokens.space.lg}
                  style={{color: t.palette.primary_500}}
                />
                <Text style={[{color: t.palette.primary_500}]}>
                  {websiteFormatted}
                </Text>
              </Link>
            )}
            <View style={[a.flex_row, a.align_center, a.gap_xs]}>
              <CalendarDays
                width={tokens.space.lg}
                style={{color: t.atoms.text_contrast_medium.color}}
              />
              <Text
                style={[t.atoms.text_contrast_medium]}
                title={dateJoinedExact}>
                <Trans>Joined {dateJoined}</Trans>
              </Text>
            </View>
          </View>

          <DebugFieldDisplay subject={profile} />
        </View>

        <Prompt.Basic
          control={unblockPromptControl}
          title={_(msg`Unblock Account?`)}
          description={_(
            msg`The account will be able to interact with you after unblocking.`,
          )}
          onConfirm={() => {
            void unblockAccount()
          }}
          confirmButtonCta={
            profile.viewer?.blocking ? _(msg`Unblock`) : _(msg`Block`)
          }
          confirmButtonColor="negative"
        />
      </ProfileHeaderShell>

      <ProfileHeaderSuggestedFollows
        isExpanded={!hasSeenAllSuggestedFollows && showSuggestedFollows}
        actorDid={profile.did}
        onRequestHide={onRequestHide}
      />
    </>
  )
}

ProfileHeaderStandard = memo(ProfileHeaderStandard)
export {ProfileHeaderStandard}

export function HeaderStandardButtons({
  profile,
  moderation,
  moderationOpts,
  onFollow,
  onUnfollow,
  minimal,
}: {
  profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>
  moderation: ModerationDecision
  moderationOpts: ModerationOpts
  onFollow?: () => void
  onUnfollow?: () => void
  minimal?: boolean
}) {
  const {_} = useLingui()
  const ax = useAnalytics()
  const {accounts, hasSession, currentAccount} = useSession()
  const playHaptic = useHaptics()
  const requireAuth = useRequireAuth()
  const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(
    profile,
    'ProfileHeader',
  )
  const [, queueUnblock] = useProfileBlockMutationQueue(profile)
  const editProfileControl = useDialogControl()
  const inviteFriendsControl = useDialogControl()
  const unblockPromptControl = Prompt.usePromptControl()
  const hideScaryFollowButtons = useHideScaryFollowButtons()
  const confirmFollowUnfollow = useConfirmFollowUnfollow()
  const followPromptControl = Prompt.usePromptControl()
  const [confirmationAction, setConfirmationAction] = useState<
    'follow' | 'unfollow'
  >('follow')
  const [pendingEphemeralAccount, setPendingEphemeralAccount] =
    useState<SessionAccount | null>(null)

  const onSelectEphemeralAccount = useEphemeralFollowAction({
    profile,
    logContext: 'ProfileHeader',
    onFollow,
    onUnfollow,
  })
  const getEphemeralFollowAction = useEphemeralFollowIntent({profile})
  const hasAlternateAccounts = accounts.some(
    account => account.did !== currentAccount?.did,
  )

  const isMe = currentAccount?.did === profile.did

  const executeFollow = async () => {
    try {
      await queueFollow()
      onFollow?.()
      Toast.show(
        _(
          msg`Following ${sanitizeDisplayName(
            profile.displayName || profile.handle,
            moderation.ui('displayName'),
          )}`,
        ),
      )
    } catch (err) {
      const e = err as Error
      if (e?.name !== 'AbortError') {
        logger.error('Failed to follow', {message: String(e)})
        Toast.show(_(msg`There was an issue! ${e.toString()}`), {
          type: 'error',
        })
      }
    }
  }

  const executeUnfollow = async () => {
    try {
      await queueUnfollow()
      onUnfollow?.()
      Toast.show(
        _(
          msg`No longer following ${sanitizeDisplayName(
            profile.displayName || profile.handle,
            moderation.ui('displayName'),
          )}`,
        ),
        {type: 'default'},
      )
    } catch (err) {
      const e = err as Error
      if (e?.name !== 'AbortError') {
        logger.error('Failed to unfollow', {message: String(e)})
        Toast.show(_(msg`There was an issue! ${e.toString()}`), {
          type: 'error',
        })
      }
    }
  }

  const onPressFollow = () => {
    playHaptic()
    requireAuth(() => {
      if (confirmFollowUnfollow) {
        setConfirmationAction('follow')
        followPromptControl.open()
      } else {
        void executeFollow()
      }
    })
  }

  const onPressUnfollow = () => {
    playHaptic()
    requireAuth(() => {
      if (confirmFollowUnfollow) {
        setConfirmationAction('unfollow')
        followPromptControl.open()
      } else {
        void executeUnfollow()
      }
    })
  }

  const onConfirmFollowAction = () => {
    if (pendingEphemeralAccount) {
      void onSelectEphemeralAccount(pendingEphemeralAccount)
      setPendingEphemeralAccount(null)
    } else if (confirmationAction === 'follow') {
      void executeFollow()
    } else {
      void executeUnfollow()
    }
  }

  const unblockAccount = async () => {
    try {
      await queueUnblock()
      Toast.show(_(msg({message: 'Account unblocked', context: 'toast'})))
    } catch (err) {
      const e = err as Error
      if (e?.name !== 'AbortError') {
        logger.error('Failed to unblock account', {message: e})
        Toast.show(_(msg`There was an issue! ${e.toString()}`), {type: 'error'})
      }
    }
  }

  const subscriptionsAllowed = useMemo(() => {
    switch (profile.associated?.activitySubscription?.allowSubscriptions) {
      case 'followers':
      case undefined:
        return !!profile.viewer?.following
      case 'mutuals':
        return !!profile.viewer?.following && !!profile.viewer.followedBy
      case 'none':
      default:
        return false
    }
  }, [profile])

  return (
    <>
      {isMe ? (
        <>
          <Button
            testID="profileHeaderEditProfileButton"
            size="small"
            color="secondary"
            onPress={() => {
              playHaptic('Light')
              editProfileControl.open()
            }}
            label={_(msg`Edit profile`)}>
            <ButtonText>
              <Trans>Edit Profile</Trans>
            </ButtonText>
          </Button>
          {/* Invite friends is a native-only share sheet (the dialog is a
              no-op on web), so gate the entry point to avoid a dead button. */}
          {IS_NATIVE && (
            <Button
              testID="profileHeaderShareButton"
              size="small"
              color="secondary"
              shape="round"
              onPress={() => {
                playHaptic('Light')
                ax.metric('invite:dialog:open', {logContext: 'ProfileHeader'})
                inviteFriendsControl.open()
              }}
              label={_(msg`Invite friends`)}>
              <ButtonIcon icon={ArrowShareRight} />
            </Button>
          )}
          <EditProfileDialog profile={profile} control={editProfileControl} />
          {IS_NATIVE && <InviteFriendsDialog control={inviteFriendsControl} />}
        </>
      ) : profile.viewer?.blocking ? (
        profile.viewer?.blockingByList ? null : (
          <Button
            testID="unblockBtn"
            size="small"
            color="secondary"
            label={_(msg`Unblock`)}
            disabled={!hasSession}
            onPress={() => unblockPromptControl.open()}>
            <ButtonText>
              <Trans context="action">Unblock</Trans>
            </ButtonText>
          </Button>
        )
      ) : !profile.viewer?.blockedBy ? (
        <>
          {hasSession && (!minimal || profile.viewer?.following) && (
            <>
              {subscriptionsAllowed && (
                <SubscribeProfileButton
                  profile={profile}
                  moderationOpts={moderationOpts}
                  disableHint={minimal}
                />
              )}

              <MessageProfileButton profile={profile} />
            </>
          )}

          {(!minimal || !profile.viewer?.following) &&
            !(minimal && hideScaryFollowButtons) &&
            (currentAccount && hasAlternateAccounts ? (
              <EphemeralAccountSwitcher
                selectedDid={currentAccount.did}
                title={_(msg`Follow as`)}
                triggerBehavior="longPress"
                onSelectAccount={account => {
                  if (confirmFollowUnfollow) {
                    setPendingEphemeralAccount(account)
                    void (async () => {
                      const action = await getEphemeralFollowAction(account)
                      setConfirmationAction(action)
                      followPromptControl.open()
                    })()
                  } else {
                    void onSelectEphemeralAccount(account)
                  }
                }}
                renderTrigger={({triggerProps}) => (
                  <Button
                    testID={
                      profile.viewer?.following ? 'unfollowBtn' : 'followBtn'
                    }
                    size="small"
                    color={profile.viewer?.following ? 'secondary' : 'primary'}
                    label={
                      profile.viewer?.following
                        ? _(msg`Unfollow ${profile.handle}`)
                        : _(msg`Follow ${profile.handle}`)
                    }
                    onLongPress={triggerProps.onLongPress}
                    onPress={
                      profile.viewer?.following
                        ? onPressUnfollow
                        : onPressFollow
                    }>
                    {profile.viewer?.following && profile.viewer?.followedBy ? (
                      <ButtonIcon icon={DoubleCheck} />
                    ) : !profile.viewer?.following ? (
                      <ButtonIcon icon={Plus} />
                    ) : (
                      <ButtonIcon icon={Check} />
                    )}
                    <ButtonText>
                      {profile.viewer?.following ? (
                        profile.viewer?.followedBy ? (
                          <Trans>Mutuals</Trans>
                        ) : (
                          <Trans>Following</Trans>
                        )
                      ) : profile.viewer?.followedBy ? (
                        <Trans>Follow back</Trans>
                      ) : (
                        <Trans>Follow</Trans>
                      )}
                    </ButtonText>
                  </Button>
                )}
              />
            ) : (
              <Button
                testID={profile.viewer?.following ? 'unfollowBtn' : 'followBtn'}
                size="small"
                color={profile.viewer?.following ? 'secondary' : 'primary'}
                label={
                  profile.viewer?.following
                    ? _(msg`Unfollow ${profile.handle}`)
                    : _(msg`Follow ${profile.handle}`)
                }
                onPress={
                  profile.viewer?.following ? onPressUnfollow : onPressFollow
                }>
                {profile.viewer?.following && profile.viewer?.followedBy ? (
                  <ButtonIcon icon={DoubleCheck} />
                ) : !profile.viewer?.following ? (
                  <ButtonIcon icon={Plus} />
                ) : (
                  <ButtonIcon icon={Check} />
                )}
                <ButtonText>
                  {profile.viewer?.following ? (
                    profile.viewer?.followedBy ? (
                      <Trans>Mutuals</Trans>
                    ) : (
                      <Trans>Following</Trans>
                    )
                  ) : profile.viewer?.followedBy ? (
                    <Trans>Follow back</Trans>
                  ) : (
                    <Trans>Follow</Trans>
                  )}
                </ButtonText>
              </Button>
            ))}
        </>
      ) : null}
      <ProfileMenu profile={profile} />

      <Prompt.Basic
        control={unblockPromptControl}
        title={_(msg`Unblock Account?`)}
        description={_(
          msg`The account will be able to interact with you after unblocking.`,
        )}
        onConfirm={() => {
          void unblockAccount()
        }}
        confirmButtonCta={_(msg`Unblock`)}
        confirmButtonColor="negative"
      />
      {confirmFollowUnfollow && (
        <FollowConfirmationDialog
          control={followPromptControl}
          displayName={sanitizeDisplayName(
            profile.displayName || profile.handle,
            moderation.ui('displayName'),
          )}
          handle={profile.handle}
          actionType={confirmationAction}
          onConfirm={onConfirmFollowAction}
        />
      )}
    </>
  )
}
