import { zodResolver } from '@hookform/resolvers/zod'
import { useState } from 'react'
import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import {
  Button,
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogSection,
  DialogTitle,
  Form,
  FormControl,
  FormField,
  Input,
} from 'ui'
import { Input as PasswordInput } from 'ui-patterns/DataInputs/Input'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import { z } from 'zod'

import { AdditionalMonthlySpend } from './AdditionalMonthlySpend'
import { NewProjectPrice } from './RestoreToNewProject.utils'
import { PasswordStrengthBar } from '@/components/ui/PasswordStrengthBar'
import { useProjectCloneMutation } from '@/data/projects/clone-mutation'
import { useCloneBackupsQuery } from '@/data/projects/clone-query'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { passwordStrength, PasswordStrengthScore } from '@/lib/password-strength'
import { generateStrongPassword } from '@/lib/project'

interface CreateNewProjectDialogProps {
  open: boolean
  selectedBackupId: number | null
  recoveryTimeTarget: number | null
  onOpenChange: (value: boolean) => void
  onCloneSuccess: () => void
  additionalMonthlySpend: NewProjectPrice
  hasAccess?: boolean
}

export const CreateNewProjectDialog = ({
  open,
  selectedBackupId,
  recoveryTimeTarget,
  onOpenChange,
  onCloneSuccess,
  additionalMonthlySpend,
  hasAccess,
}: CreateNewProjectDialogProps) => {
  const { data: project } = useSelectedProjectQuery()
  const [passwordStrengthScore, setPasswordStrengthScore] = useState(0)
  const [passwordStrengthMessage, setPasswordStrengthMessage] = useState('')

  const FormSchema = z.object({
    name: z.string().min(1),
    password: z.string().min(1),
  })

  const form = useForm<z.infer<typeof FormSchema>>({
    resolver: zodResolver(FormSchema as any),
    defaultValues: {
      name: '',
      password: '',
    },
  })

  const { data: cloneBackups } = useCloneBackupsQuery(
    { projectRef: project?.ref },
    { enabled: hasAccess }
  )
  const hasPITREnabled = cloneBackups?.pitr_enabled

  const { mutate: triggerClone, isPending: cloneMutationLoading } = useProjectCloneMutation({
    onError: (error) => {
      toast.error(`Failed to restore to new project: ${error.message}`)
    },
    onSuccess: () => {
      toast.success('Restoration process started')
      onCloneSuccess()
    },
  })

  async function checkPasswordStrength(value: string) {
    const { message, strength } = await passwordStrength(value)
    setPasswordStrengthScore(strength)
    setPasswordStrengthMessage(message)
  }

  const generatePassword = () => {
    const password = generateStrongPassword()
    form.setValue('password', password)
    checkPasswordStrength(password)
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent>
        <DialogHeader className="border-b">
          <DialogTitle>Create new project</DialogTitle>
          <DialogDescription>
            This process will create a new project and restore your database to it.
          </DialogDescription>
        </DialogHeader>
        <Form {...form}>
          <form
            id={'create-new-project-form'}
            onSubmit={form.handleSubmit((data) => {
              if (!project?.ref) {
                toast.error('Project ref is required')
                return
              }

              if (hasPITREnabled && recoveryTimeTarget) {
                triggerClone({
                  projectRef: project?.ref,
                  newProjectName: data.name,
                  newDbPass: data.password,
                  recoveryTimeTarget: recoveryTimeTarget,
                  cloneBackupId: undefined,
                })
              } else if (selectedBackupId) {
                triggerClone({
                  projectRef: project?.ref,
                  cloneBackupId: selectedBackupId,
                  newProjectName: data.name,
                  newDbPass: data.password,
                  recoveryTimeTarget: undefined,
                })
              } else {
                toast.error('No backup or point in time selected')
                return
              }
            })}
          >
            <DialogSection className="pb-6 space-y-4 text-sm">
              <FormField
                control={form.control}
                name="name"
                render={({ field }) => (
                  <FormItemLayout label="New Project Name">
                    <FormControl>
                      <Input placeholder="Enter a name" type="text" {...field} />
                    </FormControl>
                  </FormItemLayout>
                )}
              />
              <FormField
                control={form.control}
                name="password"
                render={({ field }) => (
                  <FormItemLayout
                    label="Database password"
                    description={
                      <PasswordStrengthBar
                        passwordStrengthScore={passwordStrengthScore as PasswordStrengthScore}
                        password={field.value}
                        passwordStrengthMessage={passwordStrengthMessage}
                        generateStrongPassword={generatePassword}
                      />
                    }
                  >
                    <FormControl>
                      <PasswordInput
                        id="db-password"
                        type="password"
                        placeholder="Type in a strong password"
                        value={field.value}
                        copy={field.value?.length > 0}
                        reveal
                        onChange={(e) => {
                          const value = e.target.value
                          field.onChange(value)
                          if (value == '') {
                            setPasswordStrengthScore(-1)
                            setPasswordStrengthMessage('')
                          } else checkPasswordStrength(value)
                        }}
                      />
                    </FormControl>
                  </FormItemLayout>
                )}
              />
            </DialogSection>
            <AdditionalMonthlySpend additionalMonthlySpend={additionalMonthlySpend} />
            <DialogFooter>
              <Button htmlType="reset" type="outline" onClick={() => onOpenChange(false)}>
                Cancel
              </Button>
              <Button htmlType="submit" loading={cloneMutationLoading}>
                Restore to new project
              </Button>
            </DialogFooter>
          </form>
        </Form>
      </DialogContent>
    </Dialog>
  )
}
