import { createContext, useContext, PropsWithChildren, useState } from 'react'
import Taro from '@tarojs/taro'
import { authClient } from '../api'
import { InferResponseType, InferRequestType } from 'hono'
import { QueryClient, QueryClientProvider, useQuery, useMutation, useQueryClient } from '@tanstack/react-query'

// 用户类型定义
export type User = InferResponseType<typeof authClient.me.$get, 200>
type LoginRequest = InferRequestType<typeof authClient.login.$post>['json']
type RegisterRequest = InferRequestType<typeof authClient.register.$post>['json']

interface AuthContextType {
  user: User | null
  login: (data: LoginRequest) => Promise<User>
  logout: () => Promise<void>
  register: (data: RegisterRequest) => Promise<User>
  updateUser: (userData: Partial<User>) => void
  isLoading: boolean
  isLoggedIn: boolean
}

const AuthContext = createContext<AuthContextType | undefined>(undefined)

const queryClient = new QueryClient()

export const AuthProvider: React.FC<PropsWithChildren> = ({ children }) => {
  const queryClient = useQueryClient()

  const { data: user, isLoading } = useQuery<User | null, Error>({
    queryKey: ['currentUser'],
    queryFn: async () => {
      const token = Taro.getStorageSync('mini_token')
      if (!token) {
        return null
      }
      try {
        const response = await authClient.me.$get({})
        if (response.status !== 200) {
          throw new Error('获取用户信息失败')
        }
        const user = await response.json()
        Taro.setStorageSync('userInfo', JSON.stringify(user))
        return user
      } catch (error) {
        Taro.removeStorageSync('mini_token')
        Taro.removeStorageSync('userInfo')
        return null
      }
    },
    staleTime: Infinity, // 用户信息不常变动，设为无限期
    refetchOnWindowFocus: false, // 失去焦点不重新获取
    refetchOnReconnect: false, // 网络重连不重新获取
  })

  const loginMutation = useMutation<User, Error, LoginRequest>({
    mutationFn: async (data) => {
      const response = await authClient.login.$post({ json: data })
      if (response.status !== 200) {
        throw new Error('登录失败')
      }
      const { token, user } = await response.json()
      Taro.setStorageSync('mini_token', token)
      Taro.setStorageSync('userInfo', JSON.stringify(user))
      return user
    },
    onSuccess: (newUser) => {
      queryClient.setQueryData(['currentUser'], newUser)
    },
    onError: (error) => {
      Taro.showToast({
        title: error.message || '登录失败，请检查用户名和密码',
        icon: 'none',
        duration: 2000,
      })
    },
  })

  const registerMutation = useMutation<User, Error, RegisterRequest>({
    mutationFn: async (data) => {
      const response = await authClient.register.$post({ json: data })
      if (response.status !== 201) {
        throw new Error('注册失败')
      }
      const { token, user } = await response.json()
      Taro.setStorageSync('mini_token', token)
      Taro.setStorageSync('userInfo', JSON.stringify(user))
      return user
    },
    onSuccess: (newUser) => {
      queryClient.setQueryData(['currentUser'], newUser)
    },
    onError: (error) => {
      Taro.showToast({
        title: error.message || '注册失败，请重试',
        icon: 'none',
        duration: 2000,
      })
    },
  })

  const logoutMutation = useMutation<void, Error>({
    mutationFn: async () => {
      try {
        const response = await authClient.logout.$post({})
        if (response.status !== 200) {
          throw new Error('登出失败')
        }
      } catch (error) {
        console.error('Logout error:', error)
      } finally {
        Taro.removeStorageSync('mini_token')
        Taro.removeStorageSync('userInfo')
      }
    },
    onSuccess: () => {
      queryClient.setQueryData(['currentUser'], null)
      Taro.redirectTo({ url: '/pages/login/index' })
    },
    onError: (error) => {
      Taro.showToast({
        title: error.message || '登出失败',
        icon: 'none',
        duration: 2000,
      })
    },
  })

  const updateUserMutation = useMutation<User, Error, Partial<User>>({
    mutationFn: async (userData) => {
      const response = await authClient.me.$put({ json: userData })
      if (response.status !== 200) {
        throw new Error('更新用户信息失败')
      }
      const updatedUser = await response.json()
      Taro.setStorageSync('userInfo', JSON.stringify(updatedUser))
      return updatedUser
    },
    onSuccess: (updatedUser) => {
      queryClient.setQueryData(['currentUser'], updatedUser)
      Taro.showToast({
        title: '更新成功',
        icon: 'success',
        duration: 2000,
      })
    },
    onError: (error) => {
      Taro.showToast({
        title: error.message || '更新失败，请重试',
        icon: 'none',
        duration: 2000,
      })
    },
  })

  const updateUser = updateUserMutation.mutateAsync

  const value = {
    user: user || null,
    login: loginMutation.mutateAsync,
    logout: logoutMutation.mutateAsync,
    register: registerMutation.mutateAsync,
    updateUser,
    isLoading: isLoading || loginMutation.isPending || registerMutation.isPending || logoutMutation.isPending,
    isLoggedIn: !!user,
  }

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
}

export const useAuth = () => {
  const context = useContext(AuthContext)
  if (context === undefined) {
    throw new Error('useAuth must be used within an AuthProvider')
  }
  return context
}

export { queryClient }