import {useCallback, useImperativeHandle, useRef, useState} from 'react'
import {View} from 'react-native'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro'

import {BSKY_SERVICE} from '#/lib/constants'
import * as persisted from '#/state/persisted'
import {useSession} from '#/state/session'
import {atoms as a, platform, useBreakpoints, useTheme, web} from '#/alf'
import {Admonition} from '#/components/Admonition'
import {Button, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import * as TextField from '#/components/forms/TextField'
import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
import {InlineLinkText} from '#/components/Link'
import {Text} from '#/components/Typography'
import {useAnalytics} from '#/analytics'

export function ServerInputDialog({
  control,
  onSelect,
}: {
  control: Dialog.DialogOuterProps['control']
  onSelect: (url: string) => void
}) {
  const ax = useAnalytics()
  const formRef = useRef<DialogInnerRef>(null)

  // persist these options between dialog open/close
  const [previousCustomAddress, setPreviousCustomAddress] = useState('')

  const onClose = useCallback(() => {
    const result = formRef.current?.getFormState()
    if (result) {
      onSelect(result)
      if (result !== BSKY_SERVICE) {
        setPreviousCustomAddress(result)
      }
    }
    ax.metric('signin:hostingProviderPressed', {
      hostingProviderDidChange: result !== BSKY_SERVICE,
    })
  }, [ax, onSelect])

  return (
    <Dialog.Outer
      control={control}
      onClose={onClose}
      nativeOptions={{preventExpansion: true}}>
      <Dialog.Handle />
      <DialogInner
        formRef={formRef}
        initialCustomAddress={previousCustomAddress}
      />
    </Dialog.Outer>
  )
}

type DialogInnerRef = {getFormState: () => string | null}

function DialogInner({
  formRef,
  initialCustomAddress,
}: {
  formRef: React.Ref<DialogInnerRef>
  initialCustomAddress: string
}) {
  const control = Dialog.useDialogContext()
  const {_} = useLingui()
  const t = useTheme()
  const {accounts} = useSession()
  const {gtMobile} = useBreakpoints()
  const [customAddress, setCustomAddress] = useState(initialCustomAddress)
  const [pdsAddressHistory, setPdsAddressHistory] = useState<string[]>(
    persisted.get('pdsAddressHistory') || [],
  )

  useImperativeHandle(
    formRef,
    () => ({
      getFormState: () => {
        let url = customAddress.trim().toLowerCase()
        if (!url) {
          return null
        }
        if (!url.startsWith('http://') && !url.startsWith('https://')) {
          if (url === 'localhost' || url.startsWith('localhost:')) {
            url = `http://${url}`
          } else {
            url = `https://${url}`
          }
        }

        if (!pdsAddressHistory.includes(url)) {
          const newHistory = [url, ...pdsAddressHistory.slice(0, 4)]
          setPdsAddressHistory(newHistory)
          persisted.write('pdsAddressHistory', newHistory)
        }

        return url
      },
    }),
    [customAddress, pdsAddressHistory],
  )

  const isFirstTimeUser = accounts.length === 0

  return (
    <Dialog.ScrollableInner
      accessibilityDescribedBy="dialog-description"
      accessibilityLabelledBy="dialog-title"
      style={web({maxWidth: 500})}>
      <View style={[a.relative, a.gap_md, a.w_full]}>
        <Text nativeID="dialog-title" style={[a.text_2xl, a.font_bold]}>
          <Trans>Choose your account provider</Trans>
        </Text>

        {isFirstTimeUser && (
          <Admonition type="tip">
            <Trans>
              Bluesky is an open network where you can choose your own provider.
              If you're new here, we recommend sticking with the default Bluesky
              Social option.
            </Trans>
          </Admonition>
        )}

        <View
          style={[
            a.border,
            t.atoms.border_contrast_low,
            a.rounded_sm,
            a.px_md,
            a.py_md,
          ]}>
          <TextField.LabelText nativeID="address-input-label">
            <Trans>Server address</Trans>
          </TextField.LabelText>
          <TextField.Root>
            <TextField.Icon icon={Globe} />
            <Dialog.Input
              testID="customServerTextInput"
              value={customAddress}
              onChangeText={setCustomAddress}
              label="my-server.com"
              accessibilityLabelledBy="address-input-label"
              autoCapitalize="none"
              keyboardType="url"
            />
          </TextField.Root>
          {pdsAddressHistory.length > 0 && (
            <View style={[a.flex_row, a.flex_wrap, a.mt_xs]}>
              {pdsAddressHistory.map(uri => (
                <Button
                  key={uri}
                  variant="ghost"
                  color="primary"
                  label={uri}
                  style={[a.px_sm, a.py_xs, a.rounded_sm, a.gap_sm]}
                  onPress={() => setCustomAddress(uri)}>
                  <ButtonText>{uri}</ButtonText>
                </Button>
              ))}
            </View>
          )}
        </View>

        <View style={[a.py_xs]}>
          <Text
            style={[t.atoms.text_contrast_medium, a.text_sm, a.leading_snug]}>
            {isFirstTimeUser ? (
              <Trans>
                If you're a developer, you can host your own server.
              </Trans>
            ) : (
              <Trans>
                Bluesky is an open network where you can choose your hosting
                provider. If you're a developer, you can host your own server.
              </Trans>
            )}{' '}
            <InlineLinkText
              label={_(msg`Learn more about self hosting your PDS.`)}
              to="https://atproto.com/guides/self-hosting">
              <Trans>Learn more.</Trans>
            </InlineLinkText>
          </Text>
        </View>

        <View style={gtMobile && [a.flex_row, a.justify_end]}>
          <Button
            testID="doneBtn"
            variant="solid"
            color="primary"
            size={platform({
              native: 'large',
              web: 'small',
            })}
            onPress={() => control.close()}
            label={_(msg`Done`)}>
            <ButtonText>
              <Trans>Done</Trans>
            </ButtonText>
          </Button>
        </View>
      </View>
    </Dialog.ScrollableInner>
  )
}
