import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { useAuthStore } from '../auth'
import { apiClient } from '../api'
import type { UserRole } from '../../types/api'

// Mock the API client
vi.mock('../api', () => ({
  apiClient: {
    login: vi.fn(),
    logout: vi.fn(),
    refresh: vi.fn(),
  }
}))

const mockApiClient = vi.mocked(apiClient)

describe('Auth Store', () => {
  beforeEach(() => {
    // Reset store state
    useAuthStore.setState({
      user: null,
      isLoading: false,
      isAuthenticated: false,
    })
    
    // Reset mocks
    vi.clearAllMocks()
  })

  afterEach(() => {
    vi.clearAllMocks()
  })

  describe('initial state', () => {
    it('has correct initial state', () => {
      const state = useAuthStore.getState()
      
      expect(state.user).toBeNull()
      expect(state.isLoading).toBe(false)
      expect(state.isAuthenticated).toBe(false)
    })
  })

  describe('login', () => {
    it('successfully logs in user', async () => {
      const mockLoginResponse = {
        access_token: 'mock-token',
        token_type: 'bearer',
        user_id: 'user-123',
        role: 'client'
      }

      mockApiClient.login.mockResolvedValueOnce(mockLoginResponse)

      const { login } = useAuthStore.getState()
      await login('test@example.com', 'password')

      const state = useAuthStore.getState()
      expect(state.isAuthenticated).toBe(true)
      expect(state.isLoading).toBe(false)
      expect(state.user).toEqual({
        id: 'user-123',
        email: 'test@example.com',
        full_name: '',
        role: 'client' as UserRole,
        auth_provider: 'local',
        is_active: true,
        created_at: '',
      })

      expect(mockApiClient.login).toHaveBeenCalledWith({
        email: 'test@example.com',
        password: 'password'
      })
    })

    it('sets loading state during login', async () => {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      let resolveLogin: (value: any) => void
      const loginPromise = new Promise((resolve) => {
        resolveLogin = resolve
      })
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      mockApiClient.login.mockReturnValueOnce(loginPromise as any)

      const { login } = useAuthStore.getState()
      const loginCall = login('test@example.com', 'password')

      // Check loading state is true during request
      expect(useAuthStore.getState().isLoading).toBe(true)

      // Resolve the promise
      resolveLogin!({
        access_token: 'token',
        user_id: 'user-123',
        role: 'client'
      })
      
      await loginCall
      
      // Check loading state is false after completion
      expect(useAuthStore.getState().isLoading).toBe(false)
    })

    it('handles login error correctly', async () => {
      const loginError = new Error('Invalid credentials')
      mockApiClient.login.mockRejectedValueOnce(loginError)

      const { login } = useAuthStore.getState()
      
      await expect(login('test@example.com', 'wrong-password')).rejects.toThrow('Invalid credentials')
      
      const state = useAuthStore.getState()
      expect(state.isAuthenticated).toBe(false)
      expect(state.isLoading).toBe(false)
      expect(state.user).toBeNull()
    })
  })

  describe('logout', () => {
    it('successfully logs out user', async () => {
      // Set initial authenticated state
      useAuthStore.setState({
        user: {
          id: 'user-123',
          email: 'test@example.com',
          full_name: 'Test User',
          role: 'client' as UserRole,
          is_active: true,
          created_at: '2024-01-01T00:00:00Z',
        },
        isAuthenticated: true
      })

      mockApiClient.logout.mockResolvedValueOnce(undefined)

      const { logout } = useAuthStore.getState()
      await logout()

      const state = useAuthStore.getState()
      expect(state.user).toBeNull()
      expect(state.isAuthenticated).toBe(false)
      expect(mockApiClient.logout).toHaveBeenCalled()
    })

    it('clears auth state even if logout request fails', async () => {
      // Set initial authenticated state
      useAuthStore.setState({
        user: {
          id: 'user-123',
          email: 'test@example.com',
          full_name: 'Test User',
          role: 'client' as UserRole,
          is_active: true,
          created_at: '2024-01-01T00:00:00Z',
        },
        isAuthenticated: true
      })

      mockApiClient.logout.mockRejectedValueOnce(new Error('Network error'))

      const { logout } = useAuthStore.getState()
      await logout()

      const state = useAuthStore.getState()
      expect(state.user).toBeNull()
      expect(state.isAuthenticated).toBe(false)
    })
  })

  describe('refreshAuth', () => {
    it('successfully refreshes authentication', async () => {
      mockApiClient.refresh.mockResolvedValueOnce({
        access_token: 'new-token'
      })

      const { refreshAuth } = useAuthStore.getState()
      await refreshAuth()

      const state = useAuthStore.getState()
      expect(state.isLoading).toBe(false)
      expect(mockApiClient.refresh).toHaveBeenCalled()
    })

    it('clears auth state on refresh failure', async () => {
      // Set initial authenticated state
      useAuthStore.setState({
        user: {
          id: 'user-123',
          email: 'test@example.com',
          full_name: 'Test User',
          role: 'client' as UserRole,
          is_active: true,
          created_at: '2024-01-01T00:00:00Z',
        },
        isAuthenticated: true
      })

      mockApiClient.refresh.mockRejectedValueOnce(new Error('Refresh failed'))

      const { refreshAuth } = useAuthStore.getState()
      
      await expect(refreshAuth()).rejects.toThrow('Refresh failed')
      
      const state = useAuthStore.getState()
      expect(state.user).toBeNull()
      expect(state.isAuthenticated).toBe(false)
      expect(state.isLoading).toBe(false)
    })

    it('sets loading state during refresh', async () => {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      let resolveRefresh: (value: any) => void
      const refreshPromise = new Promise((resolve) => {
        resolveRefresh = resolve
      })
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      mockApiClient.refresh.mockReturnValueOnce(refreshPromise as any)

      const { refreshAuth } = useAuthStore.getState()
      const refreshCall = refreshAuth()

      // Check loading state is true during request
      expect(useAuthStore.getState().isLoading).toBe(true)

      // Resolve the promise
      resolveRefresh!({ access_token: 'new-token' })
      
      await refreshCall
      
      // Check loading state is false after completion
      expect(useAuthStore.getState().isLoading).toBe(false)
    })
  })

  describe('setUser', () => {
    it('sets user and authentication state', () => {
      const mockUser = {
        id: 'user-123',
        email: 'test@example.com',
        full_name: 'Test User',
        role: 'client' as UserRole,
        is_active: true,
        created_at: '2024-01-01T00:00:00Z',
      }

      const { setUser } = useAuthStore.getState()
      setUser(mockUser)

      const state = useAuthStore.getState()
      expect(state.user).toEqual(mockUser)
      expect(state.isAuthenticated).toBe(true)
    })

    it('clears authentication when user is null', () => {
      // Set initial authenticated state
      useAuthStore.setState({
        user: {
          id: 'user-123',
          email: 'test@example.com',
          full_name: 'Test User',
          role: 'client' as UserRole,
          is_active: true,
          created_at: '2024-01-01T00:00:00Z',
        },
        isAuthenticated: true
      })

      const { setUser } = useAuthStore.getState()
      setUser(null)

      const state = useAuthStore.getState()
      expect(state.user).toBeNull()
      expect(state.isAuthenticated).toBe(false)
    })
  })
})