import { useState } from 'react'
import { z } from 'zod'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { useNavigate } from '@tanstack/react-router'
import { Loader2, LogIn } from 'lucide-react'
import { toast } from 'sonner'
import { type AuthUser, useAuthStore } from '@/stores/auth-store'
import { api, getApiErrorMessage } from '@/lib/api'
import { cn } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { PasswordInput } from '@/components/password-input'

const formSchema = z.object({
  username: z.string().min(1, '请输入账号'),
  password: z.string().min(1, '请输入密码').min(6, '密码至少 6 位'),
})

type LoginResponse = {
  status: 'ok' | 'error'
  msg?: string
  token?: string
  user?: AuthUser
}

type ApiEnvelope<T> = {
  code?: number
  msg?: string
  data?: T
}

function unwrapLoginResponse(
  response: LoginResponse | ApiEnvelope<LoginResponse>
): LoginResponse {
  if ('data' in response && response.data) {
    return response.data
  }

  return response as LoginResponse
}

function getSafeRedirect(redirectTo?: string) {
  if (!redirectTo) {
    return '/'
  }

  const pathname = (() => {
    try {
      return new URL(redirectTo, window.location.origin).pathname
    } catch {
      return redirectTo
    }
  })()

  if (!pathname.startsWith('/') || pathname.startsWith('/sign-in')) {
    return '/'
  }

  return pathname
}

interface UserAuthFormProps extends React.HTMLAttributes<HTMLFormElement> {
  redirectTo?: string
}

export function UserAuthForm({
  className,
  redirectTo,
  ...props
}: UserAuthFormProps) {
  const [isLoading, setIsLoading] = useState(false)
  const navigate = useNavigate()
  const { auth } = useAuthStore()

  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      username: 'root',
      password: '123456',
    },
  })

  async function onSubmit(data: z.infer<typeof formSchema>) {
    setIsLoading(true)

    try {
      const response = await api.post<LoginResponse | ApiEnvelope<LoginResponse>>(
        '/api/user/login',
        {
          userName: data.username,
          password: data.password,
        }
      )
      const loginResult = unwrapLoginResponse(response.data)

      if (loginResult.status !== 'ok' || !loginResult.token || !loginResult.user) {
        throw new Error(loginResult.msg || '账号或密码错误')
      }

      const user = {
        ...loginResult.user,
        mustChangePassword: Boolean(loginResult.user.mustChangePassword),
      }

      auth.setAccessToken(loginResult.token)
      auth.setUser(user)
      toast.success(`欢迎回来，${user.name}`)

      await navigate({
        to: user.mustChangePassword
          ? '/settings/account'
          : getSafeRedirect(redirectTo),
        replace: true,
      })
    } catch (error) {
      toast.error(getApiErrorMessage(error, '登录失败，请检查账号和密码'))
    } finally {
      setIsLoading(false)
    }
  }

  return (
    <Form {...form}>
      <form
        onSubmit={(event) => {
          event.preventDefault()
          event.stopPropagation()
          void form.handleSubmit(onSubmit)(event)
        }}
        className={cn('grid gap-3', className)}
        {...props}
      >
        <FormField
          control={form.control}
          name='username'
          render={({ field }) => (
            <FormItem>
              <FormLabel>账号</FormLabel>
              <FormControl>
                <Input autoComplete='username' placeholder='请输入账号' {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <FormField
          control={form.control}
          name='password'
          render={({ field }) => (
            <FormItem className='relative'>
              <FormLabel>密码</FormLabel>
              <FormControl>
                <PasswordInput
                  autoComplete='current-password'
                  placeholder='请输入密码'
                  {...field}
                />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type='submit' className='mt-2' disabled={isLoading}>
          {isLoading ? <Loader2 className='animate-spin' /> : <LogIn />}
          登录
        </Button>
      </form>
    </Form>
  )
}
