import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import type { User } from '@/types'
import { authApi, type RegisterData, type LoginData } from '@/api/auth'

let syncPromise: Promise<void> | null = null

interface Pending2FA {
  sessionId: number
}

interface LoginResult {
  requires2FA: boolean
  sessionId?: number
}

export interface BanInfo {
  banned_at: string | null
  banned_until: string | null
  reason: string | null
}

interface AuthState {
  user: User | null
  token: string | null
  isAuthenticated: boolean
  isLoading: boolean
  error: string | null
  pendingInviteCode: string | null
  avatarVersion: number
  pending2FA: Pending2FA | null
  banInfo: BanInfo | null

  login: (data: LoginData) => Promise<LoginResult>
  verify2FA: (code: string) => Promise<void>
  cancel2FA: () => void
  register: (data: RegisterData) => Promise<void>
  logout: () => void
  clearError: () => void
  setPendingInviteCode: (code: string | null) => void
  consumePendingInviteCode: () => string | null
  updateUser: (updates: Partial<User>) => void
  bumpAvatarVersion: () => void
  setBanned: (banInfo: BanInfo) => void
  clearBanned: () => void
  syncUser: () => Promise<void>
}

export const useAuthStore = create<AuthState>()(
  persist(
    (set, get) => ({
      user: null,
      token: null,
      isAuthenticated: false,
      isLoading: false,
      error: null,
      pendingInviteCode: null,
      avatarVersion: 0,
      pending2FA: null,
      banInfo: null,

      login: async (data) => {
        set({ isLoading: true, error: null, pending2FA: null, banInfo: null })
        try {
          const response = await authApi.login(data)

          // Check if 2FA is required
          if (response.requires_2fa && response.two_factor_session_id) {
            set({
              isLoading: false,
              pending2FA: { sessionId: response.two_factor_session_id },
            })
            return { requires2FA: true, sessionId: response.two_factor_session_id }
          }

          // Regular login (no 2FA)
          if (response.access_token && response.user) {
            localStorage.setItem('token', response.access_token)
            set({
              user: response.user,
              token: response.access_token,
              isAuthenticated: true,
              isLoading: false,
            })
          }
          return { requires2FA: false }
        } catch (err: unknown) {
          const error = err as { response?: { status?: number; data?: { detail?: string | BanInfo } } }

          // Check if user is banned (403 with ban info)
          if (error.response?.status === 403) {
            const detail = error.response?.data?.detail
            if (typeof detail === 'object' && detail !== null && 'banned_at' in detail) {
              set({
                banInfo: detail as BanInfo,
                isLoading: false,
                error: null,
              })
              throw err
            }
          }

          // Regular error - translate common messages
          let errorMessage = 'Ошибка входа'
          const detail = error.response?.data?.detail
          if (typeof detail === 'string') {
            if (detail === 'Incorrect login or password') {
              errorMessage = 'Неверный логин или пароль'
            } else {
              errorMessage = detail
            }
          }

          set({
            error: errorMessage,
            isLoading: false,
          })
          throw err
        }
      },

      verify2FA: async (code) => {
        const pending = get().pending2FA
        if (!pending) {
          throw new Error('No pending 2FA session')
        }

        set({ isLoading: true, error: null })
        try {
          const response = await authApi.verify2FA(pending.sessionId, code)
          localStorage.setItem('token', response.access_token)
          set({
            user: response.user,
            token: response.access_token,
            isAuthenticated: true,
            isLoading: false,
            pending2FA: null,
          })
        } catch (err: unknown) {
          const error = err as { response?: { data?: { detail?: string } } }
          set({
            error: error.response?.data?.detail || '2FA verification failed',
            isLoading: false,
          })
          throw err
        }
      },

      cancel2FA: () => {
        set({ pending2FA: null, error: null })
      },

      register: async (data) => {
        set({ isLoading: true, error: null })
        try {
          const response = await authApi.register(data)
          localStorage.setItem('token', response.access_token)
          set({
            user: response.user,
            token: response.access_token,
            isAuthenticated: true,
            isLoading: false,
          })
        } catch (err: unknown) {
          const error = err as { response?: { data?: { detail?: string } } }
          set({
            error: error.response?.data?.detail || 'Registration failed',
            isLoading: false,
          })
          throw err
        }
      },

      logout: () => {
        localStorage.removeItem('token')
        sessionStorage.removeItem('telegram_banner_dismissed')
        set({
          user: null,
          token: null,
          isAuthenticated: false,
          banInfo: null,
        })
      },

      clearError: () => set({ error: null }),

      setPendingInviteCode: (code) => set({ pendingInviteCode: code }),

      consumePendingInviteCode: () => {
        const code = get().pendingInviteCode
        set({ pendingInviteCode: null })
        return code
      },

      updateUser: (updates) => {
        const currentUser = get().user
        if (currentUser) {
          set({ user: { ...currentUser, ...updates } })
        }
      },

      bumpAvatarVersion: () => {
        set({ avatarVersion: get().avatarVersion + 1 })
      },

      setBanned: (banInfo) => {
        set({ banInfo })
      },

      clearBanned: () => {
        set({ banInfo: null })
      },

      syncUser: async () => {
        if (!get().isAuthenticated || !get().token) return

        // Prevent duplicate sync calls
        if (syncPromise) return syncPromise

        syncPromise = (async () => {
          try {
            const userData = await authApi.me()
            set({ user: userData })
          } catch {
            // Token invalid - logout
            get().logout()
          } finally {
            syncPromise = null
          }
        })()

        return syncPromise
      },
    }),
    {
      name: 'auth-storage',
      partialize: (state) => ({
        user: state.user,
        token: state.token,
        isAuthenticated: state.isAuthenticated,
        pendingInviteCode: state.pendingInviteCode,
      }),
    }
  )
)
