import { zodResolver } from '@hookform/resolvers/zod'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import { ExternalLink } from 'lucide-react'
import Link from 'next/link'
import { useEffect } from 'react'
import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import {
  Alert,
  AlertDescription,
  AlertTitle,
  Button,
  Card,
  CardContent,
  CardFooter,
  Form,
  FormControl,
  FormField,
  Switch,
  WarningIcon,
} from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import {
  PageSection,
  PageSectionContent,
  PageSectionMeta,
  PageSectionSummary,
  PageSectionTitle,
} from 'ui-patterns/PageSection'
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
import * as z from 'zod'

import { NO_REQUIRED_CHARACTERS } from './Auth.constants'
import AlertError from '@/components/ui/AlertError'
import { InlineLink } from '@/components/ui/InlineLink'
import NoPermission from '@/components/ui/NoPermission'
import { useAuthConfigQuery } from '@/data/auth/auth-config-query'
import { useAuthConfigUpdateMutation } from '@/data/auth/auth-config-update-mutation'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
import { DOCS_URL } from '@/lib/constants'

const schema = z.object({
  DISABLE_SIGNUP: z.boolean(),
  EXTERNAL_ANONYMOUS_USERS_ENABLED: z.boolean(),
  SECURITY_MANUAL_LINKING_ENABLED: z.boolean(),
  MAILER_AUTOCONFIRM: z.boolean(),
  SITE_URL: z.string().min(1, 'Must have a Site URL'),
})

export const BasicAuthSettingsForm = () => {
  const { ref: projectRef } = useParams()
  const showManualLinking = useIsFeatureEnabled('authentication:show_manual_linking')

  const {
    data: authConfig,
    error: authConfigError,
    isError,
    isSuccess,
    isPending: isLoading,
  } = useAuthConfigQuery({ projectRef })
  const { mutate: updateAuthConfig, isPending: isUpdatingConfig } = useAuthConfigUpdateMutation()

  const { can: canReadConfig, isSuccess: isPermissionsLoaded } = useAsyncCheckPermissions(
    PermissionAction.READ,
    'custom_config_gotrue'
  )
  const { can: canUpdateConfig } = useAsyncCheckPermissions(
    PermissionAction.UPDATE,
    'custom_config_gotrue'
  )

  const form = useForm({
    resolver: zodResolver(schema as any),
    defaultValues: {
      DISABLE_SIGNUP: true,
      EXTERNAL_ANONYMOUS_USERS_ENABLED: false,
      SECURITY_MANUAL_LINKING_ENABLED: false,
      MAILER_AUTOCONFIRM: true,
      SITE_URL: '',
    },
  })
  const { isDirty } = form.formState

  useEffect(() => {
    if (authConfig) {
      form.reset({
        DISABLE_SIGNUP: !authConfig.DISABLE_SIGNUP,
        EXTERNAL_ANONYMOUS_USERS_ENABLED: authConfig.EXTERNAL_ANONYMOUS_USERS_ENABLED,
        SECURITY_MANUAL_LINKING_ENABLED: authConfig.SECURITY_MANUAL_LINKING_ENABLED,
        // The backend uses false to represent that email confirmation is required
        MAILER_AUTOCONFIRM: !authConfig.MAILER_AUTOCONFIRM,
        SITE_URL: authConfig.SITE_URL,
      })
    }
  }, [authConfig])

  const onSubmit = (values: any) => {
    const payload = { ...values }
    payload.DISABLE_SIGNUP = !values.DISABLE_SIGNUP
    // The backend uses empty string to represent no required characters in the password
    if (payload.PASSWORD_REQUIRED_CHARACTERS === NO_REQUIRED_CHARACTERS) {
      payload.PASSWORD_REQUIRED_CHARACTERS = ''
    }

    // The backend uses false to represent that email confirmation is required
    payload.MAILER_AUTOCONFIRM = !values.MAILER_AUTOCONFIRM

    updateAuthConfig(
      { projectRef: projectRef!, config: payload },
      {
        onError: (error) => {
          toast.error(`Failed to update settings: ${error?.message}`)
        },
        onSuccess: () => {
          toast.success('Successfully updated settings')
        },
      }
    )
  }

  return (
    <PageSection>
      <PageSectionMeta>
        <PageSectionSummary>
          <PageSectionTitle>User Signups</PageSectionTitle>
        </PageSectionSummary>
      </PageSectionMeta>
      <PageSectionContent>
        {isError && (
          <AlertError
            error={authConfigError}
            subject="Failed to retrieve auth configuration for hooks"
          />
        )}

        {isPermissionsLoaded && !canReadConfig && (
          <div className="mt-8">
            <NoPermission resourceText="view auth configuration settings" />
          </div>
        )}

        {isLoading && (
          <Card>
            <CardContent className="py-6">
              <ShimmeringLoader />
            </CardContent>
            <CardContent className="py-6">
              <ShimmeringLoader />
            </CardContent>
            <CardContent className="py-6">
              <ShimmeringLoader />
            </CardContent>
            <CardContent className="py-7">
              <ShimmeringLoader />
            </CardContent>
            <CardContent className="py-7"></CardContent>
          </Card>
        )}

        {isSuccess && (
          <Form {...form}>
            <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
              <Card>
                <CardContent>
                  <FormField
                    control={form.control}
                    name="DISABLE_SIGNUP"
                    render={({ field }) => (
                      <FormItemLayout
                        layout="flex-row-reverse"
                        label="Allow new users to sign up"
                        description="If this is disabled, new users will not be able to sign up to your application"
                      >
                        <FormControl>
                          <Switch
                            checked={field.value}
                            onCheckedChange={field.onChange}
                            disabled={!canUpdateConfig}
                          />
                        </FormControl>
                      </FormItemLayout>
                    )}
                  />
                </CardContent>
                {showManualLinking && (
                  <CardContent>
                    <FormField
                      control={form.control}
                      name="SECURITY_MANUAL_LINKING_ENABLED"
                      render={({ field }) => (
                        <FormItemLayout
                          layout="flex-row-reverse"
                          label="Allow manual linking"
                          description={
                            <>
                              Enable{' '}
                              <InlineLink
                                className="text-foreground-light hover:text-foreground"
                                href={`${DOCS_URL}/guides/auth/auth-identity-linking#manual-linking-beta`}
                              >
                                manual linking APIs
                              </InlineLink>{' '}
                              for your project
                            </>
                          }
                        >
                          <FormControl>
                            <Switch
                              checked={field.value}
                              onCheckedChange={field.onChange}
                              disabled={!canUpdateConfig}
                            />
                          </FormControl>
                        </FormItemLayout>
                      )}
                    />
                  </CardContent>
                )}
                <CardContent>
                  <FormField
                    control={form.control}
                    name="EXTERNAL_ANONYMOUS_USERS_ENABLED"
                    render={({ field }) => (
                      <FormItemLayout
                        layout="flex-row-reverse"
                        label="Allow anonymous sign-ins"
                        description={
                          <>
                            Enable{' '}
                            <InlineLink
                              className="text-foreground-light hover:text-foreground"
                              href={`${DOCS_URL}/guides/auth/auth-anonymous`}
                            >
                              anonymous sign-ins
                            </InlineLink>{' '}
                            for your project
                          </>
                        }
                      >
                        <FormControl>
                          <Switch
                            checked={field.value}
                            onCheckedChange={field.onChange}
                            disabled={!canUpdateConfig}
                          />
                        </FormControl>
                      </FormItemLayout>
                    )}
                  />

                  {form.watch('EXTERNAL_ANONYMOUS_USERS_ENABLED') && (
                    <Alert
                      className="flex w-full items-center justify-between mt-4"
                      variant="warning"
                    >
                      <WarningIcon />
                      <div>
                        <AlertTitle>
                          Anonymous users will use the{' '}
                          <code className="text-code-inline">authenticated</code> role when signing
                          in
                        </AlertTitle>
                        <AlertDescription className="flex flex-col gap-y-3">
                          <p>
                            As a result, anonymous users will be subjected to RLS policies that
                            apply to the <code className="text-code-inline">public</code> and{' '}
                            <code className="text-code-inline">authenticated</code> roles. We
                            strongly advise{' '}
                            <Link
                              href={`/project/${projectRef}/auth/policies`}
                              className="text-foreground underline"
                            >
                              reviewing your RLS policies
                            </Link>{' '}
                            to ensure that access to your data is restricted where required.
                          </p>
                          <Button asChild type="default" className="w-min" icon={<ExternalLink />}>
                            <Link href={`${DOCS_URL}/guides/auth/auth-anonymous#access-control`}>
                              View access control docs
                            </Link>
                          </Button>
                        </AlertDescription>
                      </div>
                    </Alert>
                  )}

                  {!authConfig?.SECURITY_CAPTCHA_ENABLED &&
                    form.watch('EXTERNAL_ANONYMOUS_USERS_ENABLED') && (
                      <Alert className="mt-4">
                        <WarningIcon />
                        <AlertTitle>
                          We highly recommend{' '}
                          <InlineLink href={`/project/${projectRef}/auth/protection`}>
                            enabling captcha
                          </InlineLink>{' '}
                          for anonymous sign-ins
                        </AlertTitle>
                        <AlertDescription>
                          This will prevent potential abuse on sign-ins which may bloat your
                          database and incur costs for monthly active users (MAU)
                        </AlertDescription>
                      </Alert>
                    )}
                </CardContent>
                <CardContent>
                  <FormField
                    control={form.control}
                    name="MAILER_AUTOCONFIRM"
                    render={({ field }) => (
                      <FormItemLayout
                        layout="flex-row-reverse"
                        label="Confirm email"
                        description="Users will need to confirm their email address before signing in for the first time"
                      >
                        <FormControl>
                          <Switch
                            checked={field.value}
                            onCheckedChange={field.onChange}
                            disabled={!canUpdateConfig}
                          />
                        </FormControl>
                      </FormItemLayout>
                    )}
                  />
                </CardContent>
                <CardFooter className="justify-end space-x-2">
                  {isDirty && (
                    <Button type="default" onClick={() => form.reset()}>
                      Cancel
                    </Button>
                  )}
                  <Button
                    type="primary"
                    htmlType="submit"
                    disabled={!canUpdateConfig || isUpdatingConfig || !isDirty}
                    loading={isUpdatingConfig}
                  >
                    Save changes
                  </Button>
                </CardFooter>
              </Card>
            </form>
          </Form>
        )}
      </PageSectionContent>
    </PageSection>
  )
}
