import Feather from '@expo/vector-icons/Feather'
import { useQuery } from '@tanstack/react-query'
import { useRouter } from 'expo-router'
import { usePreventScreenCapture } from 'expo-screen-capture'
import * as WebBrowser from 'expo-web-browser'
import React, { useRef, useState } from 'react'
import {
  ActivityIndicator,
  Keyboard,
  Pressable,
  ScrollView as RNScrollView,
  TouchableWithoutFeedback,
} from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'
import type { OpenServer } from 'src/lib/api-types'
import { APP } from 'src/lib/branding'
import { ICON } from 'src/lib/icons'
import { authQueries } from 'src/lib/queries/auth'
import { prettyCount } from 'src/utils'
import {
  AnimatePresence,
  Button,
  Form,
  Input,
  ScrollView,
  Text,
  useTheme,
  useToastController,
  View,
  XStack,
  YStack,
} from 'tamagui'

const DOMAIN_REGEX = /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/

// Strip scheme prefix, trailing slash, surrounding whitespace, and lowercase
// before DOMAIN_REGEX runs — common pastes/autocompletes (`https://x.social`,
// `x.social/`, ` x.social `) would otherwise be rejected by the strict regex.
function normalizeDomainInput(raw: string): string {
  return raw
    .trim()
    .toLowerCase()
    .replace(/^https?:\/\//, '')
    .replace(/\/+$/, '')
}

export default function SignupScreen() {
  // Block screenshots / screen recording on the signup surface — the email
  // the user types here is reused as the verification target on the next
  // screen. Released automatically when the screen unmounts.
  usePreventScreenCapture('signup')
  const [server, setServer] = useState('')
  const [customDomain, setCustomDomain] = useState('')
  const [loading, setLoading] = useState(false)
  const [showInfo, setShowInfo] = useState(false)
  const [signupEmail, setSignupEmail] = useState('')
  const [formError, setFormError] = useState<string | null>(null)
  const scrollViewRef = useRef(null)
  const router = useRouter()
  const theme = useTheme()
  const toast = useToastController()

  const {
    data: serversData,
    isLoading: loadingServers,
    refetch,
  } = useQuery(authQueries.registerServers())

  const filteredServers = React.useMemo(() => {
    if (!serversData) return []

    return [...serversData]
      .filter((s) => Object.hasOwn(s, 'user_count'))
      .sort((a, b) => (b as OpenServer).user_count - (a as OpenServer).user_count)
      .slice(0, 10)
  }, [serversData])

  const normalizedCustomDomain = normalizeDomainInput(customDomain)
  const isCustomValid = DOMAIN_REGEX.test(normalizedCustomDomain)

  const handleServerSelect = (serverDomain: string) => {
    setServer(serverDomain)
    setTimeout(() => {
      ;(scrollViewRef.current as any)?.scrollToEnd({ animated: true })
    }, 100)
  }

  const openSignupFlow = async (targetServer: string) => {
    setLoading(true)
    try {
      const result = await WebBrowser.openAuthSessionAsync(
        `https://${targetServer}/i/app-email-verify`,
        `${APP.scheme}://verifyEmail`
      )

      if (result.type === 'success') {
        const urlParams = new URLSearchParams(new URL(result.url).search)
        const email = urlParams.get('email')
        if (email) {
          setSignupEmail(email)
        }

        handleDeepLink(targetServer, result.url)
      }
    } catch (_error) {
      toast.show('Signup error', {
        message: 'An error occurred during the signup process',
        preset: 'error',
        duration: 6000,
      })
    } finally {
      setLoading(false)
    }
  }

  const handleSignup = async () => {
    if (!server) {
      setFormError('Please select a server first')
      return
    }
    setFormError(null)
    await openSignupFlow(server)
  }

  const handleCustomSignup = async () => {
    if (!isCustomValid) {
      setFormError('Please enter a valid server domain')
      return
    }
    setFormError(null)
    await openSignupFlow(normalizedCustomDomain)
  }

  const handleDeepLink = (domain: string, url: string) => {
    const parsedUrl = new URL(url)
    const searchParams = new URLSearchParams(parsedUrl.search)
    const params = {
      domain: domain,
      email: searchParams.get('email') ?? '',
      expires_in: Number.parseInt(searchParams.get('expires_in') ?? '0', 10).toString(),
      status: searchParams.get('status') ?? '',
    }
    const q = new URLSearchParams(params)
    const finalPath = `/verifyEmail?${q.toString()}`
    router.push(finalPath as Parameters<typeof router.push>[0])
  }

  const handleResendVerification = async () => {
    if (!server) {
      setFormError('Please select a server first')
      return
    }
    setFormError(null)

    setLoading(true)
    try {
      await WebBrowser.openAuthSessionAsync(
        `https://${server}/i/app-email-resend?email=${encodeURIComponent(signupEmail)}`,
        `${APP.scheme}://verifyEmail`
      ).then((res) => {
        if (res.type === 'success') {
          toast.show('Verification email resent', { preset: 'success' })
        }
      })
    } catch (_error) {
      toast.show('Failed to resend verification email', { preset: 'error' })
    } finally {
      setLoading(false)
    }
  }

  const navigateToVerificationCode = () => {
    if (!server) {
      setFormError('Please select a server first')
      return
    }
    setFormError(null)

    router.push({
      pathname: '/verificationCode',
      params: { server },
    } as Parameters<typeof router.push>[0])
  }

  const navigateToLogin = () => {
    router.push('/handleLogin')
  }

  return (
    <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
      <SafeAreaView
        style={{
          backgroundColor: theme.background.val,
          flexGrow: 1,
        }}
        edges={['top']}
      >
        <RNScrollView
          ref={scrollViewRef}
          contentContainerStyle={{ flexGrow: 1 }}
          keyboardShouldPersistTaps="handled"
          onScroll={() => Keyboard.dismiss()}
        >
          <YStack px="$4" pt="$4" pb="$6" gap="$4" flexGrow={1} minHeight="100%">
            <XStack justifyContent="flex-end">
              <Pressable
                onPress={() => setShowInfo((prev) => !prev)}
                hitSlop={12}
                accessibilityRole="button"
                accessibilityLabel={showInfo ? 'Hide help' : 'Show help'}
              >
                <Feather
                  name={showInfo ? 'x-circle' : 'help-circle'}
                  size={ICON.md}
                  color={theme.color.val}
                />
              </Pressable>
            </XStack>

            <AnimatePresence>
              {showInfo && (
                <YStack
                  key="help"
                  transition="quick"
                  enterStyle={{ opacity: 0, y: -8 }}
                  exitStyle={{ opacity: 0, y: -8 }}
                  opacity={1}
                  y={0}
                  gap="$2"
                  p="$4"
                  borderRadius="$4"
                  bg="$backgroundSecondary"
                  borderColor="$borderColor"
                  borderWidth={1}
                >
                  <Text fontSize="$3" color="$color" mb="$2">
                    {APP.name} connects to a decentralized photo sharing network. To join,
                    you'll need to:
                  </Text>
                  <Text fontSize="$3" color="$colorSecondary">
                    • Choose a server
                  </Text>
                  <Text fontSize="$3" color="$colorSecondary">
                    • Provide your email address for a verification code
                  </Text>
                  <Text fontSize="$3" color="$colorSecondary">
                    • Return to this app to finish signing up
                  </Text>
                  <Text fontSize="$3" color="$colorSecondary" mt="$2">
                    Your account will work across the network, regardless of which server
                    you join.
                  </Text>
                </YStack>
              )}
            </AnimatePresence>

            <YStack gap="$3">
              <Text fontSize="$5" fontWeight="bold" color="$color">
                Choose a server to join
              </Text>

              <View
                borderWidth={1}
                borderColor="$borderColor"
                borderRadius="$4"
                p="$3"
                bg="$background"
              >
                {loadingServers ? (
                  <YStack gap="$3" py="$5" alignItems="center">
                    <ActivityIndicator color={theme.color.val} />
                    <Text color="$colorSecondary" fontSize="$3" textAlign="center">
                      Loading server list…
                    </Text>
                  </YStack>
                ) : !serversData ? (
                  <YStack gap="$3" py="$4" alignItems="center">
                    <Text color="$colorSecondary" textAlign="center">
                      Couldn't load the server list.{'\n'}Enter a server domain below or
                      try again.
                    </Text>
                    <Button size="$3" variant="outlined" onPress={() => refetch()}>
                      <Button.Text>Retry</Button.Text>
                    </Button>
                  </YStack>
                ) : filteredServers.length > 0 ? (
                  <YStack gap="$2" maxHeight={260}>
                    <ScrollView>
                      {filteredServers.map((item) => {
                        const selected = server === item.domain
                        return (
                          <XStack
                            key={item.domain}
                            onPress={() => handleServerSelect(item.domain)}
                            justifyContent="space-between"
                            alignItems="center"
                            borderRadius="$3"
                            p="$3"
                            mb="$2"
                            cursor="pointer"
                            bg={selected ? '$backgroundTertiary' : 'transparent'}
                            pressStyle={{ opacity: 0.7 }}
                          >
                            <Text
                              color={selected ? '$color' : '$colorTertiary'}
                              fontSize="$5"
                              fontWeight={selected ? 'bold' : 'normal'}
                              flex={1}
                            >
                              {item.domain}
                            </Text>
                            <Text fontSize="$3" color="$colorTertiary">
                              {prettyCount(item.user_count)} users
                            </Text>
                          </XStack>
                        )
                      })}
                    </ScrollView>
                  </YStack>
                ) : (
                  <Text color="$color" textAlign="center" py="$3">
                    No servers with open registration found
                  </Text>
                )}
              </View>
            </YStack>

            {formError ? (
              <Text color="$red10" fontSize="$3">
                {formError}
              </Text>
            ) : null}

            {server && (
              <Button
                size="$4"
                onPress={handleSignup}
                disabled={loading}
                icon={
                  !loading ? (
                    <Feather name="user-plus" size={ICON.sm} color={theme.color.val} />
                  ) : undefined
                }
              >
                {loading ? (
                  <ActivityIndicator color={theme.color.val} />
                ) : (
                  <Button.Text fontWeight="600">Sign up on {server}</Button.Text>
                )}
              </Button>
            )}

            <YStack gap="$3" mt="$2">
              <Text color="$colorSecondary" fontSize="$3">
                Or sign up on a different server
              </Text>
              <Form onSubmit={handleCustomSignup}>
                <YStack gap="$3">
                  <Input
                    size="$5"
                    placeholder={APP.serverPlaceholder}
                    value={customDomain}
                    onChangeText={setCustomDomain}
                    autoCapitalize="none"
                    autoCorrect={false}
                    autoComplete="off"
                    keyboardType="url"
                    focusStyle={{ borderColor: '$borderColorStrong' }}
                  />
                  {/* Tappable even when invalid: handleCustomSignup surfaces
                      a formError so users who paste a URL with a scheme see
                      *why* it's rejected instead of a silent dead button. */}
                  <Form.Trigger asChild disabled={loading}>
                    <Button size="$4" opacity={isCustomValid ? 1 : 0.6}>
                      <Button.Text fontWeight="600">
                        Sign up on {customDomain || 'your server'}
                      </Button.Text>
                    </Button>
                  </Form.Trigger>
                </YStack>
              </Form>
            </YStack>

            <YStack mt="$2" gap="$3">
              <XStack justifyContent="center" gap="$2">
                <Pressable onPress={handleResendVerification}>
                  <Text color="$color" fontWeight="600" fontSize="$4">
                    Resend email verification
                  </Text>
                </Pressable>
              </XStack>

              <XStack justifyContent="center" gap="$2">
                <Pressable onPress={navigateToVerificationCode}>
                  <Text color="$color" fontWeight="600" fontSize="$4">
                    I have a verification code
                  </Text>
                </Pressable>
              </XStack>
            </YStack>

            <View flexGrow={1} />

            <XStack justifyContent="center" gap="$2" mt="$4">
              <Text color="$colorSecondary">Already have an account?</Text>
              <Pressable onPress={navigateToLogin}>
                <Text color="$color" fontWeight="600">
                  Log in
                </Text>
              </Pressable>
            </XStack>

            <View h={20} />
          </YStack>
        </RNScrollView>
      </SafeAreaView>
    </TouchableWithoutFeedback>
  )
}
