import {useCallback, useState} from 'react'
import {Pressable, StyleSheet, View} from 'react-native'
import {Image} from 'expo-image'
import {type ModerationUI} from '@atproto/api'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro'

import {IMAGE_SIZE_CONFIG_2K_1MB} from '#/lib/constants'
import {
  useCameraPermission,
  usePhotoLibraryPermission,
} from '#/lib/hooks/usePermissions'
import {compressIfNeeded} from '#/lib/media/manip'
import {openCamera, openCropper, openPicker} from '#/lib/media/picker'
import {type PickerImage} from '#/lib/media/picker.shared'
import {isCancelledError} from '#/lib/strings/errors'
import {logger} from '#/logger'
import {
  type ComposerImage,
  compressImage,
  createComposerImage,
} from '#/state/gallery'
import {useFullsizeFormat} from '#/state/preferences/fullsize-format'
import {
  applyImageTransforms,
  useImageCdnHost,
} from '#/state/preferences/image-cdn-host'
import {useThumbnailFormat} from '#/state/preferences/thumbnail-format'
import {EditImageDialog} from '#/view/com/composer/photos/EditImageDialog'
import {EventStopper} from '#/view/com/util/EventStopper'
import {atoms as a, tokens, useTheme} from '#/alf'
import {useDialogControl} from '#/components/Dialog'
import {useSheetWrapper} from '#/components/Dialog/sheet-wrapper'
import {
  Camera_Filled_Stroke2_Corner0_Rounded as CameraFilledIcon,
  Camera_Stroke2_Corner0_Rounded as CameraIcon,
} from '#/components/icons/Camera'
import {StreamingLive_Stroke2_Corner0_Rounded as LibraryIcon} from '#/components/icons/StreamingLive'
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash'
import * as Menu from '#/components/Menu'
import {IS_ANDROID, IS_NATIVE} from '#/env'

export function UserBanner({
  type,
  banner,
  moderation,
  onSelectNewBanner,
}: {
  type?: 'labeler' | 'default'
  banner?: string | null
  moderation?: ModerationUI
  onSelectNewBanner?: (img: PickerImage | null) => void
}) {
  const t = useTheme()
  const {_} = useLingui()
  const {requestCameraAccessIfNeeded} = useCameraPermission()
  const {requestPhotoAccessIfNeeded} = usePhotoLibraryPermission()
  const sheetWrapper = useSheetWrapper()
  const [rawImage, setRawImage] = useState<ComposerImage | undefined>()
  const editImageDialogControl = useDialogControl()
  const fullsizeFormat = useFullsizeFormat()
  const thumbnailFormat = useThumbnailFormat()
  const imageCdnHost = useImageCdnHost()

  const onOpenCamera = useCallback(async () => {
    if (!(await requestCameraAccessIfNeeded())) {
      return
    }
    onSelectNewBanner?.(
      await compressIfNeeded(
        await openCamera({
          aspect: [3, 1],
        }),
        IMAGE_SIZE_CONFIG_2K_1MB,
      ),
    )
  }, [onSelectNewBanner, requestCameraAccessIfNeeded])

  const onOpenLibrary = useCallback(async () => {
    if (!(await requestPhotoAccessIfNeeded())) {
      return
    }
    const items = await sheetWrapper(openPicker())
    if (!items[0]) {
      return
    }

    try {
      if (IS_NATIVE) {
        onSelectNewBanner?.(
          await compressIfNeeded(
            await openCropper({
              imageUri: items[0].path,
              aspectRatio: 3 / 1,
            }),
            IMAGE_SIZE_CONFIG_2K_1MB,
          ),
        )
      } else {
        setRawImage(await createComposerImage(items[0]))
        editImageDialogControl.open()
      }
    } catch (e) {
      // Don't log errors for cancelling selection to sentry on ios or android
      if (!isCancelledError(e)) {
        logger.error('Failed to crop banner', {error: e})
      }
    }
  }, [
    onSelectNewBanner,
    requestPhotoAccessIfNeeded,
    sheetWrapper,
    editImageDialogControl,
  ])

  const onRemoveBanner = useCallback(() => {
    onSelectNewBanner?.(null)
  }, [onSelectNewBanner])

  const onChangeEditImage = useCallback(
    async (image: ComposerImage) => {
      const compressed = await compressImage(
        image,
        IMAGE_SIZE_CONFIG_2K_1MB,
        {
          outputMime: 'image/jpeg',
          forceEncode: true,
        },
      )
      onSelectNewBanner?.(compressed)
    },
    [onSelectNewBanner],
  )

  // setUserBanner is only passed as prop on the EditProfile component
  return onSelectNewBanner ? (
    <>
      <EventStopper onKeyDown={true}>
        <Menu.Root>
          <Menu.Trigger label={_(msg`Edit avatar`)}>
            {({props}) => (
              <Pressable {...props} testID="changeBannerBtn">
                {banner ? (
                  <Image
                    testID="userBannerImage"
                    style={styles.bannerImage}
                    source={{
                      uri: applyImageTransforms(banner, {
                        imageCdnHost,
                        format: thumbnailFormat,
                      }),
                    }}
                    accessible={true}
                    accessibilityIgnoresInvertColors
                    useAppleWebpCodec
                  />
                ) : (
                  <View
                    testID="userBannerFallback"
                    style={[styles.bannerImage, t.atoms.bg_contrast_25]}
                  />
                )}
                <View
                  style={[
                    styles.editButtonContainer,
                    t.atoms.bg_contrast_25,
                    a.border,
                    t.atoms.border_contrast_low,
                  ]}>
                  <CameraFilledIcon
                    height={14}
                    width={14}
                    style={t.atoms.text}
                  />
                </View>
              </Pressable>
            )}
          </Menu.Trigger>
          <Menu.Outer showCancel>
            <Menu.Group>
              {IS_NATIVE && (
                <Menu.Item
                  testID="changeBannerCameraBtn"
                  label={_(msg`Upload from Camera`)}
                  onPress={onOpenCamera}>
                  <Menu.ItemText>
                    <Trans>Upload from Camera</Trans>
                  </Menu.ItemText>
                  <Menu.ItemIcon icon={CameraIcon} />
                </Menu.Item>
              )}

              <Menu.Item
                testID="changeBannerLibraryBtn"
                label={_(msg`Upload from Library`)}
                onPress={onOpenLibrary}>
                <Menu.ItemText>
                  {IS_NATIVE ? (
                    <Trans>Upload from Library</Trans>
                  ) : (
                    <Trans>Upload from Files</Trans>
                  )}
                </Menu.ItemText>
                <Menu.ItemIcon icon={LibraryIcon} />
              </Menu.Item>
            </Menu.Group>
            {!!banner && (
              <>
                <Menu.Divider />
                <Menu.Group>
                  <Menu.Item
                    testID="changeBannerRemoveBtn"
                    label={_(msg`Remove Banner`)}
                    onPress={onRemoveBanner}>
                    <Menu.ItemText>
                      <Trans>Remove Banner</Trans>
                    </Menu.ItemText>
                    <Menu.ItemIcon icon={TrashIcon} />
                  </Menu.Item>
                </Menu.Group>
              </>
            )}
          </Menu.Outer>
        </Menu.Root>
      </EventStopper>

      <EditImageDialog
        control={editImageDialogControl}
        image={rawImage}
        onChange={onChangeEditImage}
        aspectRatio={3}
      />
    </>
  ) : banner &&
    !((moderation?.blur && IS_ANDROID) /* android crashes with blur */) ? (
    <Image
      style={[styles.bannerImage, t.atoms.bg_contrast_25]}
      contentFit="cover"
      source={{
        uri: applyImageTransforms(banner, {
          imageCdnHost,
          format: fullsizeFormat,
        }),
      }}
      blurRadius={moderation?.blur ? 100 : 0}
      accessible={true}
      accessibilityIgnoresInvertColors
      useAppleWebpCodec
    />
  ) : (
    <View
      style={[
        styles.bannerImage,
        type === 'labeler' ? styles.labelerBanner : t.atoms.bg_contrast_25,
      ]}
    />
  )
}

const styles = StyleSheet.create({
  editButtonContainer: {
    position: 'absolute',
    width: 24,
    height: 24,
    bottom: 8,
    right: 24,
    borderRadius: 12,
    alignItems: 'center',
    justifyContent: 'center',
  },
  bannerImage: {
    width: '100%',
    height: 150,
  },
  labelerBanner: {
    backgroundColor: tokens.color.temp_purple,
  },
})
