import {useCallback, useEffect, useRef, useState} from 'react'
import {Pressable, View} from 'react-native'
import {type AppBskyActorDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Plural, Trans} from '@lingui/react/macro'

import {
  HITSLOP_10,
  MAX_DESCRIPTION,
  MAX_DISPLAY_NAME,
  urls,
} from '#/lib/constants'
import {cleanError} from '#/lib/strings/errors'
import {isOverMaxGraphemeCount} from '#/lib/strings/helpers'
import {isValidWebsiteFormat} from '#/lib/strings/website'
import {logger} from '#/logger'
import {type ImageMeta} from '#/state/gallery'
import {useEnableSquareAvatars} from '#/state/preferences/enable-square-avatars'
import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons'
import {useProfileUpdateMutation} from '#/state/queries/profile'
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
import {EditableUserAvatar} from '#/view/com/util/UserAvatar'
import {UserBanner} from '#/view/com/util/UserBanner'
import {atoms as a, useTheme} from '#/alf'
import * as tokens from '#/alf/tokens'
import {Admonition} from '#/components/Admonition'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import * as TextField from '#/components/forms/TextField'
import {CircleX_Stroke2_Corner0_Rounded as CircleX} from '#/components/icons/CircleX'
import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
import {InlineLinkText} from '#/components/Link'
import {Loader} from '#/components/Loader'
import * as Prompt from '#/components/Prompt'
import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography'
import {useSimpleVerificationState} from '#/components/verification'

const PRONOUNS_MAX_GRAPHEMES = 20
const WEBSITE_MAX_GRAPHEMES = 2048

export function EditProfileDialog({
  profile,
  control,
  onUpdate,
}: {
  profile: AppBskyActorDefs.ProfileViewDetailed
  control: Dialog.DialogControlProps
  onUpdate?: () => void
}) {
  const {_} = useLingui()
  const cancelControl = Dialog.useDialogControl()
  const [dirty, setDirty] = useState(false)

  const onPressCancel = useCallback(() => {
    if (dirty) {
      cancelControl.open()
    } else {
      control.close()
    }
  }, [dirty, control, cancelControl])

  return (
    <Dialog.Outer
      control={control}
      nativeOptions={{
        preventDismiss: dirty,
        fullHeight: true,
      }}
      webOptions={{
        onBackgroundPress: () => {
          if (dirty) {
            cancelControl.open()
          } else {
            control.close()
          }
        },
      }}
      testID="editProfileModal">
      <DialogInner
        profile={profile}
        onUpdate={onUpdate}
        setDirty={setDirty}
        onPressCancel={onPressCancel}
      />

      <Prompt.Basic
        control={cancelControl}
        title={_(msg`Discard changes?`)}
        description={_(msg`Are you sure you want to discard your changes?`)}
        onConfirm={() => control.close()}
        confirmButtonCta={_(msg`Discard`)}
        confirmButtonColor="negative"
      />
    </Dialog.Outer>
  )
}

function DialogInner({
  profile,
  onUpdate,
  setDirty,
  onPressCancel,
}: {
  profile: AppBskyActorDefs.ProfileViewDetailed
  onUpdate?: () => void
  setDirty: (dirty: boolean) => void
  onPressCancel: () => void
}) {
  const {_} = useLingui()
  const t = useTheme()
  const control = Dialog.useDialogContext()
  const enableSquareButtons = useEnableSquareButtons()
  const verification = useSimpleVerificationState({
    profile,
  })
  const {
    mutateAsync: updateProfileMutation,
    error: updateProfileError,
    isError: isUpdateProfileError,
    isPending: isUpdatingProfile,
  } = useProfileUpdateMutation()
  const [imageError, setImageError] = useState('')
  const initialDisplayName = profile.displayName || ''
  const [displayName, setDisplayName] = useState(initialDisplayName)
  const initialDescription = profile.description || ''
  const [description, setDescription] = useState(initialDescription)
  const initialPronouns = profile.pronouns || ''
  const [pronouns, setPronouns] = useState(initialPronouns)
  const initialWebsite = profile.website || ''
  const [website, setWebsite] = useState(initialWebsite)
  const websiteInputRef = useRef<any>(null)
  const [userBanner, setUserBanner] = useState<string | undefined | null>(
    profile.banner,
  )
  const [userAvatar, setUserAvatar] = useState<string | undefined | null>(
    profile.avatar,
  )
  const [newUserBanner, setNewUserBanner] = useState<
    ImageMeta | undefined | null
  >()
  const [newUserAvatar, setNewUserAvatar] = useState<
    ImageMeta | undefined | null
  >()

  const dirty =
    displayName !== initialDisplayName ||
    description !== initialDescription ||
    userAvatar !== profile.avatar ||
    userBanner !== profile.banner ||
    pronouns !== initialPronouns ||
    website !== initialWebsite

  const enableSquareAvatars = useEnableSquareAvatars()

  useEffect(() => {
    setDirty(dirty)
  }, [dirty, setDirty])

  const onSelectNewAvatar = useCallback(
    (img: ImageMeta | null) => {
      setImageError('')
      if (img === null) {
        setNewUserAvatar(null)
        setUserAvatar(null)
        return
      }
      try {
        setNewUserAvatar(img)
        setUserAvatar(img.path)
      } catch (e: any) {
        setImageError(cleanError(e))
      }
    },
    [setNewUserAvatar, setUserAvatar, setImageError],
  )

  const onSelectNewBanner = useCallback(
    (img: ImageMeta | null) => {
      setImageError('')
      if (!img) {
        setNewUserBanner(null)
        setUserBanner(null)
        return
      }
      try {
        setNewUserBanner(img)
        setUserBanner(img.path)
      } catch (e: any) {
        setImageError(cleanError(e))
      }
    },
    [setNewUserBanner, setUserBanner, setImageError],
  )

  const onClearWebsite = useCallback(() => {
    setWebsite('')
    if (websiteInputRef.current) {
      websiteInputRef.current.clear()
    }
  }, [setWebsite])

  const onPressSave = useCallback(async () => {
    setImageError('')
    try {
      await updateProfileMutation({
        profile,
        updates: {
          displayName: displayName.trimEnd(),
          description: description.trimEnd(),
          pronouns: pronouns.trimEnd().toLowerCase(),
          website: website.trimEnd(),
        },
        newUserAvatar,
        newUserBanner,
      })
      control.close(() => onUpdate?.())
      Toast.show(_(msg({message: 'Profile updated', context: 'toast'})))
    } catch (e: any) {
      logger.error('Failed to update user profile', {message: String(e)})
    }
  }, [
    updateProfileMutation,
    profile,
    onUpdate,
    control,
    displayName,
    description,
    pronouns,
    website,
    newUserAvatar,
    newUserBanner,
    setImageError,
    _,
  ])

  const displayNameTooLong = isOverMaxGraphemeCount({
    text: displayName,
    maxCount: MAX_DISPLAY_NAME,
  })
  const pronounsTooLong = isOverMaxGraphemeCount({
    text: pronouns,
    maxCount: PRONOUNS_MAX_GRAPHEMES,
  })
  const websiteTooLong = isOverMaxGraphemeCount({
    text: website,
    maxCount: WEBSITE_MAX_GRAPHEMES,
  })
  const websiteInvalidFormat = !isValidWebsiteFormat(website)
  const descriptionTooLong = isOverMaxGraphemeCount({
    text: description,
    maxCount: MAX_DESCRIPTION,
  })

  const cancelButton = useCallback(
    () => (
      <Button
        label={_(msg`Cancel`)}
        onPress={onPressCancel}
        size="small"
        color="primary"
        variant="ghost"
        style={[enableSquareButtons ? a.rounded_sm : a.rounded_full]}
        testID="editProfileCancelBtn">
        <ButtonText style={[a.text_md]}>
          <Trans>Cancel</Trans>
        </ButtonText>
      </Button>
    ),
    [onPressCancel, _, enableSquareButtons],
  )

  const saveButton = useCallback(
    () => (
      <Button
        label={_(msg`Save`)}
        onPress={onPressSave}
        disabled={
          !dirty ||
          isUpdatingProfile ||
          displayNameTooLong ||
          descriptionTooLong
        }
        size="small"
        color="primary"
        variant="ghost"
        style={[enableSquareButtons ? a.rounded_sm : a.rounded_full]}
        testID="editProfileSaveBtn">
        <ButtonText style={[a.text_md, !dirty && t.atoms.text_contrast_low]}>
          <Trans>Save</Trans>
        </ButtonText>
        {isUpdatingProfile && <ButtonIcon icon={Loader} />}
      </Button>
    ),
    [
      _,
      t,
      dirty,
      onPressSave,
      isUpdatingProfile,
      displayNameTooLong,
      descriptionTooLong,
      enableSquareButtons,
    ],
  )

  return (
    <Dialog.ScrollableInner
      label={_(msg`Edit profile`)}
      style={[a.overflow_hidden]}
      contentContainerStyle={[a.px_0, a.pt_0]}
      header={
        <Dialog.Header renderLeft={cancelButton} renderRight={saveButton}>
          <Dialog.HeaderText>
            <Trans>Edit profile</Trans>
          </Dialog.HeaderText>
        </Dialog.Header>
      }>
      <View style={[a.relative]}>
        <UserBanner banner={userBanner} onSelectNewBanner={onSelectNewBanner} />
        <View
          style={[
            a.absolute,
            {
              top: 80,
              left: 20,
              width: 84,
              height: 84,
              borderWidth: 2,
              borderRadius: enableSquareAvatars ? 11 : 42,
              borderColor: t.atoms.bg.backgroundColor,
            },
          ]}>
          <EditableUserAvatar
            size={80}
            avatar={userAvatar}
            onSelectNewAvatar={onSelectNewAvatar}
          />
        </View>
      </View>
      {isUpdateProfileError && (
        <View style={[a.mt_xl]}>
          <ErrorMessage message={cleanError(updateProfileError)} />
        </View>
      )}
      {imageError !== '' && (
        <View style={[a.mt_xl]}>
          <ErrorMessage message={imageError} />
        </View>
      )}
      <View style={[a.mt_4xl, a.px_xl, a.gap_xl]}>
        <View>
          <TextField.LabelText>
            <Trans>Display name</Trans>
          </TextField.LabelText>
          <TextField.Root isInvalid={displayNameTooLong}>
            <Dialog.Input
              defaultValue={displayName}
              onChangeText={setDisplayName}
              label={_(msg`Display name`)}
              placeholder={_(msg`e.g. Alice Lastname`)}
              testID="editProfileDisplayNameInput"
            />
          </TextField.Root>
          {displayNameTooLong && (
            <Text
              style={[
                a.text_sm,
                a.mt_xs,
                a.font_semi_bold,
                {color: t.palette.negative_400},
              ]}>
              <Plural
                value={MAX_DISPLAY_NAME}
                other="Display name is too long. The maximum number of characters is #."
              />
            </Text>
          )}
        </View>

        {verification.isVerified &&
          verification.role === 'default' &&
          displayName !== initialDisplayName && (
            <Admonition type="error">
              <Trans>
                You are verified. You will lose your verification status if you
                change your display name.{' '}
                <InlineLinkText
                  label={_(
                    msg({
                      message: `Learn more`,
                      context: `english-only-resource`,
                    }),
                  )}
                  to={urls.website.blog.initialVerificationAnnouncement}>
                  <Trans context="english-only-resource">Learn more.</Trans>
                </InlineLinkText>
              </Trans>
            </Admonition>
          )}

        <View>
          <TextField.LabelText>
            <Trans>Description</Trans>
          </TextField.LabelText>
          <TextField.Root isInvalid={descriptionTooLong}>
            <Dialog.Input
              defaultValue={description}
              onChangeText={setDescription}
              multiline
              label={_(msg`Description`)}
              placeholder={_(msg`Tell us a bit about yourself`)}
              testID="editProfileDescriptionInput"
            />
          </TextField.Root>
          {descriptionTooLong && (
            <Text
              style={[
                a.text_sm,
                a.mt_xs,
                a.font_semi_bold,
                {color: t.palette.negative_400},
              ]}>
              <Plural
                value={MAX_DESCRIPTION}
                other="Description is too long. The maximum number of characters is #."
              />
            </Text>
          )}
        </View>

        <View>
          <TextField.LabelText>
            <Trans>Pronouns</Trans>
          </TextField.LabelText>
          <TextField.Root isInvalid={pronounsTooLong}>
            <Dialog.Input
              defaultValue={pronouns}
              onChangeText={setPronouns}
              label={_(msg`Pronouns`)}
              placeholder={_(msg`e.g. she/her`)}
              testID="editProfilePronounsInput"
            />
          </TextField.Root>
          {pronounsTooLong && (
            <Text
              style={[
                a.text_sm,
                a.mt_xs,
                a.font_bold,
                {color: t.palette.negative_400},
              ]}>
              <Plural
                value={PRONOUNS_MAX_GRAPHEMES}
                other="The maximum number of characters is #."
              />
            </Text>
          )}
        </View>

        <View>
          <TextField.LabelText>
            <Trans>Website</Trans>
          </TextField.LabelText>
          <View style={[a.w_full, a.relative]}>
            <TextField.Root isInvalid={websiteTooLong || websiteInvalidFormat}>
              {website && <TextField.Icon icon={Globe} />}
              <Dialog.Input
                inputRef={websiteInputRef}
                defaultValue={website}
                onChangeText={setWebsite}
                label={_(msg`EditWebsite`)}
                placeholder={_(msg`URL`)}
                testID="editProfileWebsiteInput"
                autoCapitalize="none"
                keyboardType="url"
                style={[
                  website
                    ? {
                        paddingRight: tokens.space._5xl,
                      }
                    : {},
                ]}
              />
            </TextField.Root>

            {website && (
              <View
                style={[
                  a.absolute,
                  a.z_10,
                  a.my_auto,
                  a.inset_0,
                  a.justify_center,
                  a.pr_sm,
                  {left: 'auto'},
                ]}>
                <Pressable
                  testID="clearWebsiteBtn"
                  onPress={onClearWebsite}
                  accessibilityLabel={_(msg`Clear website`)}
                  accessibilityHint={_(msg`Removes the website URL`)}
                  hitSlop={HITSLOP_10}
                  style={[
                    a.flex_row,
                    a.align_center,
                    a.justify_center,
                    {
                      width: tokens.space._2xl,
                      height: tokens.space._2xl,
                    },
                    a.rounded_full,
                  ]}>
                  <CircleX
                    width={tokens.space.lg}
                    style={{color: t.palette.contrast_600}}
                  />
                </Pressable>
              </View>
            )}
          </View>
          {websiteTooLong && (
            <Text
              style={[
                a.text_sm,
                a.mt_xs,
                a.font_bold,
                {color: t.palette.negative_400},
              ]}>
              <Plural
                value={WEBSITE_MAX_GRAPHEMES}
                other="Website is too long. The maximum number of characters is #."
              />
            </Text>
          )}
          {websiteInvalidFormat && (
            <Text
              style={[
                a.text_sm,
                a.mt_xs,
                a.font_bold,
                {color: t.palette.negative_400},
              ]}>
              <Trans>
                Website must be a valid URI (e.g., https://bsky.app)
              </Trans>
            </Text>
          )}
        </View>
      </View>
    </Dialog.ScrollableInner>
  )
}
