/**
 * @format
 */

import { configureStore } from '@reduxjs/toolkit';
import authSlice, { login, refreshToken, logout, updateAccessToken } from '../src/modules/auth/store/authSlice';
import { authAPI } from '../src/modules/auth/services/authAPI';

// Mock the authAPI
jest.mock('../src/modules/auth/services/authAPI', () => ({
  authAPI: {
    login: jest.fn(),
    refreshToken: jest.fn(),
  },
}));

const mockAuthAPI = authAPI as jest.Mocked<typeof authAPI>;

describe('Auth Slice', () => {
  let store: ReturnType<typeof configureStore>;

  beforeEach(() => {
    store = configureStore({
      reducer: {
        auth: authSlice.reducer,
      },
    });
    jest.clearAllMocks();
  });

  describe('refreshToken', () => {
    it('should handle successful token refresh', async () => {
      const mockRefreshResponse = {
        data: {
          status: 'success',
          message: 'Token refreshed successfully',
          data: {
            accessToken: 'new-access-token',
          },
          timestamp: '2024-01-01T00:00:00Z',
        },
      };

      mockAuthAPI.refreshToken.mockResolvedValue(mockRefreshResponse);

      const result = await store.dispatch(refreshToken('valid-refresh-token'));

      expect(refreshToken.fulfilled.match(result)).toBe(true);
      expect(store.getState().auth.accessToken).toBe('new-access-token');
      expect(store.getState().auth.error).toBeNull();
    });

    it('should handle refresh token failure and logout user', async () => {
      const mockErrorResponse = {
        response: {
          data: {
            status: 'error',
            message: 'Invalid refresh token',
            errorCode: 'INVALID_REFRESH',
            timestamp: '2024-01-01T00:00:00Z',
          },
        },
      };

      mockAuthAPI.refreshToken.mockRejectedValue(mockErrorResponse);

      // Set initial state with user logged in
      store.dispatch(updateAccessToken('old-access-token'));
      store.dispatch({
        type: 'auth/login/fulfilled',
        payload: {
          accessToken: 'old-access-token',
          refreshToken: 'valid-refresh-token',
          user: {
            id: 1,
            uuid: 'test-uuid',
            email: 'test@example.com',
            displayName: 'Test User',
            role: 'user',
          },
        },
      });

      const result = await store.dispatch(refreshToken('invalid-refresh-token'));

      expect(refreshToken.rejected.match(result)).toBe(true);
      expect(store.getState().auth.isAuthenticated).toBe(false);
      expect(store.getState().auth.user).toBeNull();
      expect(store.getState().auth.accessToken).toBeNull();
      expect(store.getState().auth.refreshToken).toBeNull();
    });

    it('should handle network error during refresh', async () => {
      mockAuthAPI.refreshToken.mockRejectedValue(new Error('Network error'));

      const result = await store.dispatch(refreshToken('valid-refresh-token'));

      expect(refreshToken.rejected.match(result)).toBe(true);
      expect(store.getState().auth.error).toBe('Network error');
    });
  });

  describe('updateAccessToken', () => {
    it('should update access token', () => {
      const newToken = 'new-access-token';
      store.dispatch(updateAccessToken(newToken));
      
      expect(store.getState().auth.accessToken).toBe(newToken);
    });
  });

  describe('logout', () => {
    it('should clear all auth state', () => {
      // Set initial state
      store.dispatch(updateAccessToken('access-token'));
      store.dispatch({
        type: 'auth/login/fulfilled',
        payload: {
          accessToken: 'access-token',
          refreshToken: 'refresh-token',
          user: {
            id: 1,
            uuid: 'test-uuid',
            email: 'test@example.com',
            displayName: 'Test User',
            role: 'user',
          },
        },
      });

      // Dispatch logout
      store.dispatch(logout());

      const state = store.getState().auth;
      expect(state.user).toBeNull();
      expect(state.accessToken).toBeNull();
      expect(state.refreshToken).toBeNull();
      expect(state.isAuthenticated).toBe(false);
      expect(state.error).toBeNull();
    });
  });
});
