/**
 * Auth Store Tests
 */

import { renderHook, act } from '@testing-library/react-hooks';
import { useAuthStore } from '../stores/auth.store';
import * as SecureStore from 'expo-secure-store';

// Mock the API module
jest.mock('../services/api', () => ({
  authApi: {
    login: jest.fn(),
    logout: jest.fn(),
    getProfile: jest.fn(),
  },
  storage: {
    setToken: jest.fn(() => Promise.resolve()),
    getToken: jest.fn(() => Promise.resolve(null)),
    setRefreshToken: jest.fn(() => Promise.resolve()),
    getRefreshToken: jest.fn(() => Promise.resolve(null)),
    setTenantId: jest.fn(() => Promise.resolve()),
    getTenantId: jest.fn(() => Promise.resolve(null)),
    clearAll: jest.fn(() => Promise.resolve()),
  },
}));

const { authApi, storage } = require('../services/api');

describe('useAuthStore', () => {
  beforeEach(() => {
    // Reset the store state
    useAuthStore.setState({
      user: null,
      token: null,
      refreshToken: null,
      isAuthenticated: false,
      isLoading: false,
    });

    // Clear all mocks
    jest.clearAllMocks();
  });

  describe('initial state', () => {
    it('should have correct initial state', () => {
      const { result } = renderHook(() => useAuthStore());

      expect(result.current.user).toBeNull();
      expect(result.current.token).toBeNull();
      expect(result.current.refreshToken).toBeNull();
      expect(result.current.isAuthenticated).toBe(false);
    });
  });

  describe('login', () => {
    it('should login successfully', async () => {
      const mockUser = {
        id: '1',
        email: 'test@example.com',
        fullName: 'Test User',
        tenantId: 'tenant-1',
        role: 'admin',
      };

      const mockResponse = {
        user: mockUser,
        token: 'test-token',
        refreshToken: 'test-refresh-token',
      };

      authApi.login.mockResolvedValue(mockResponse);

      const { result } = renderHook(() => useAuthStore());

      await act(async () => {
        await result.current.login({
          email: 'test@example.com',
          password: 'password123',
        });
      });

      expect(result.current.user).toEqual(mockUser);
      expect(result.current.token).toBe('test-token');
      expect(result.current.refreshToken).toBe('test-refresh-token');
      expect(result.current.isAuthenticated).toBe(true);
      expect(result.current.isLoading).toBe(false);

      expect(storage.setToken).toHaveBeenCalledWith('test-token');
      expect(storage.setRefreshToken).toHaveBeenCalledWith('test-refresh-token');
    });

    it('should handle login failure', async () => {
      authApi.login.mockRejectedValue(new Error('Invalid credentials'));

      const { result } = renderHook(() => useAuthStore());

      await expect(
        act(async () => {
          await result.current.login({
            email: 'test@example.com',
            password: 'wrongpassword',
          });
        })
      ).rejects.toThrow('Invalid credentials');

      expect(result.current.user).toBeNull();
      expect(result.current.isAuthenticated).toBe(false);
      expect(result.current.isLoading).toBe(false);
    });
  });

  describe('logout', () => {
    it('should logout successfully', async () => {
      // Set initial authenticated state
      useAuthStore.setState({
        user: { id: '1', email: 'test@example.com', fullName: 'Test', tenantId: 't1', role: 'admin' },
        token: 'test-token',
        refreshToken: 'test-refresh-token',
        isAuthenticated: true,
        isLoading: false,
      });

      authApi.logout.mockResolvedValue(undefined);

      const { result } = renderHook(() => useAuthStore());

      await act(async () => {
        await result.current.logout();
      });

      expect(result.current.user).toBeNull();
      expect(result.current.token).toBeNull();
      expect(result.current.refreshToken).toBeNull();
      expect(result.current.isAuthenticated).toBe(false);

      expect(storage.clearAll).toHaveBeenCalled();
    });

    it('should logout even if API fails', async () => {
      useAuthStore.setState({
        user: { id: '1', email: 'test@example.com', fullName: 'Test', tenantId: 't1', role: 'admin' },
        token: 'test-token',
        refreshToken: 'test-refresh-token',
        isAuthenticated: true,
        isLoading: false,
      });

      authApi.logout.mockRejectedValue(new Error('Network error'));

      const { result } = renderHook(() => useAuthStore());

      await act(async () => {
        await result.current.logout();
      });

      // Should still logout locally
      expect(result.current.user).toBeNull();
      expect(result.current.isAuthenticated).toBe(false);
      expect(storage.clearAll).toHaveBeenCalled();
    });
  });

  describe('loadStoredAuth', () => {
    it('should load stored auth successfully', async () => {
      const mockUser = {
        id: '1',
        email: 'test@example.com',
        fullName: 'Test User',
        tenantId: 'tenant-1',
        role: 'admin',
      };

      storage.getToken.mockResolvedValue('stored-token');
      storage.getRefreshToken.mockResolvedValue('stored-refresh-token');
      authApi.getProfile.mockResolvedValue(mockUser);

      const { result } = renderHook(() => useAuthStore());

      await act(async () => {
        await result.current.loadStoredAuth();
      });

      expect(result.current.user).toEqual(mockUser);
      expect(result.current.token).toBe('stored-token');
      expect(result.current.isAuthenticated).toBe(true);
      expect(result.current.isLoading).toBe(false);
    });

    it('should handle no stored token', async () => {
      storage.getToken.mockResolvedValue(null);

      const { result } = renderHook(() => useAuthStore());

      await act(async () => {
        await result.current.loadStoredAuth();
      });

      expect(result.current.user).toBeNull();
      expect(result.current.isAuthenticated).toBe(false);
      expect(result.current.isLoading).toBe(false);
    });

    it('should handle invalid stored token', async () => {
      storage.getToken.mockResolvedValue('invalid-token');
      authApi.getProfile.mockRejectedValue(new Error('Invalid token'));

      const { result } = renderHook(() => useAuthStore());

      await act(async () => {
        await result.current.loadStoredAuth();
      });

      expect(result.current.user).toBeNull();
      expect(result.current.isAuthenticated).toBe(false);
      expect(storage.clearAll).toHaveBeenCalled();
    });
  });

  describe('setUser', () => {
    it('should set user directly', () => {
      const { result } = renderHook(() => useAuthStore());

      const newUser = {
        id: '2',
        email: 'new@example.com',
        fullName: 'New User',
        tenantId: 'tenant-2',
        role: 'user',
      };

      act(() => {
        result.current.setUser(newUser);
      });

      expect(result.current.user).toEqual(newUser);
      expect(result.current.isAuthenticated).toBe(true);
    });

    it('should clear user when set to null', () => {
      useAuthStore.setState({
        user: { id: '1', email: 'test@example.com', fullName: 'Test', tenantId: 't1', role: 'admin' },
        isAuthenticated: true,
      });

      const { result } = renderHook(() => useAuthStore());

      act(() => {
        result.current.setUser(null);
      });

      expect(result.current.user).toBeNull();
      expect(result.current.isAuthenticated).toBe(false);
    });
  });

  describe('setLoading', () => {
    it('should set loading state', () => {
      const { result } = renderHook(() => useAuthStore());

      act(() => {
        result.current.setLoading(true);
      });

      expect(result.current.isLoading).toBe(true);

      act(() => {
        result.current.setLoading(false);
      });

      expect(result.current.isLoading).toBe(false);
    });
  });
});
