import { describe, it, expect, beforeEach, vi } from 'vitest';
import { useUsersStore } from '../users-store';

// Mock the API functions
vi.mock('../../lib/api/users', () => ({
  getUsers: vi.fn(),
  getUser: vi.fn(),
  createUser: vi.fn(),
  updateUser: vi.fn(),
  deleteUser: vi.fn(),
  bulkDeleteUsers: vi.fn(),
  bulkUpdateUserRoles: vi.fn(),
}));

import {
  getUsers,
  getUser,
  createUser,
  updateUser,
  deleteUser,
  bulkDeleteUsers,
  bulkUpdateUserRoles,
} from '../../lib/api/users';

/**
 * EN: Users store unit tests
 * VI: Unit tests cho users store
 */
describe('UsersStore', () => {
  beforeEach(() => {
    // Reset store state before each test
    useUsersStore.setState({
      users: [],
      currentUser: null,
      pagination: null,
      isLoading: false,
      isLoadingUser: false,
      error: null,
    });

    // Reset all mocks
    vi.clearAllMocks();
  });

  describe('initial state', () => {
    it('initializes with default state', () => {
      const state = useUsersStore.getState();
      expect(state.users).toEqual([]);
      expect(state.currentUser).toBeNull();
      expect(state.pagination).toBeNull();
      expect(state.isLoading).toBe(false);
      expect(state.isLoadingUser).toBe(false);
      expect(state.error).toBeNull();
    });
  });

  describe('fetchUsers', () => {
    it('sets loading state and fetches users successfully', async () => {
      const mockResponse = {
        data: [
          {
            id: '1',
            email: 'user1@example.com',
            role: 'USER',
            isActive: true,
            createdAt: '2024-01-01T00:00:00Z',
            updatedAt: '2024-01-01T00:00:00Z',
          },
        ],
        pagination: {
          page: 1,
          limit: 10,
          total: 1,
          totalPages: 1,
        },
      };

      (getUsers as any).mockResolvedValue(mockResponse);

      const { fetchUsers } = useUsersStore.getState();
      await fetchUsers();

      const state = useUsersStore.getState();
      expect(state.isLoading).toBe(false);
      expect(state.users).toEqual(mockResponse.data);
      expect(state.pagination).toEqual(mockResponse.pagination);
      expect(state.error).toBeNull();
    });

    it('handles fetch users error', async () => {
      const mockError = new Error('Failed to fetch users');
      (getUsers as any).mockRejectedValue(mockError);

      const { fetchUsers } = useUsersStore.getState();
      await expect(fetchUsers()).rejects.toThrow('Failed to fetch users');

      const state = useUsersStore.getState();
      expect(state.isLoading).toBe(false);
      expect(state.users).toEqual([]);
      expect(state.error).toBe('Failed to fetch users');
    });
  });

  describe('fetchUser', () => {
    it('fetches single user successfully', async () => {
      const mockUser = {
        id: '1',
        email: 'user1@example.com',
        role: 'USER',
        isActive: true,
        createdAt: '2024-01-01T00:00:00Z',
        updatedAt: '2024-01-01T00:00:00Z',
      };

      (getUser as any).mockResolvedValue(mockUser);

      const { fetchUser } = useUsersStore.getState();
      await fetchUser('1');

      const state = useUsersStore.getState();
      expect(state.isLoadingUser).toBe(false);
      expect(state.currentUser).toEqual(mockUser);
      expect(state.error).toBeNull();
    });

    it('handles fetch user error', async () => {
      const mockError = new Error('User not found');
      (getUser as any).mockRejectedValue(mockError);

      const { fetchUser } = useUsersStore.getState();
      await expect(fetchUser('1')).rejects.toThrow('User not found');

      const state = useUsersStore.getState();
      expect(state.isLoadingUser).toBe(false);
      expect(state.currentUser).toBeNull();
      expect(state.error).toBe('User not found');
    });
  });

  describe('createUser', () => {
    it('creates user successfully and adds to list', async () => {
      const newUser = {
        id: '3',
        email: 'user3@example.com',
        role: 'USER',
        isActive: true,
        createdAt: '2024-01-03T00:00:00Z',
        updatedAt: '2024-01-03T00:00:00Z',
      };

      const existingUsers = [
        {
          id: '1',
          email: 'user1@example.com',
          role: 'USER',
          isActive: true,
          createdAt: '2024-01-01T00:00:00Z',
          updatedAt: '2024-01-01T00:00:00Z',
        },
        {
          id: '2',
          email: 'user2@example.com',
          role: 'USER',
          isActive: true,
          createdAt: '2024-01-02T00:00:00Z',
          updatedAt: '2024-01-02T00:00:00Z',
        },
      ];

      // Set initial state with existing users
      useUsersStore.setState({ users: existingUsers });

      (createUser as any).mockResolvedValue(newUser);

      const createData = {
        email: 'user3@example.com',
        password: 'password123',
        role: 'USER' as const,
      };

      const { createUser: createUserAction } = useUsersStore.getState();
      const result = await createUserAction(createData);

      expect(result).toEqual(newUser);

      const state = useUsersStore.getState();
      expect(state.isLoadingUser).toBe(false);
      expect(state.users).toHaveLength(3);
      expect(state.users[0]).toEqual(newUser); // New user added at beginning
    });
  });

  describe('updateUser', () => {
    it('updates user successfully', async () => {
      const existingUser = {
        id: '1',
        email: 'user1@example.com',
        role: 'USER',
        isActive: true,
        createdAt: '2024-01-01T00:00:00Z',
        updatedAt: '2024-01-01T00:00:00Z',
      };

      const updatedUser = {
        ...existingUser,
        email: 'updated@example.com',
        role: 'ADMIN',
      };

      useUsersStore.setState({
        users: [existingUser],
        currentUser: existingUser,
      });

      (updateUser as any).mockResolvedValue(updatedUser);

      const updateData = {
        email: 'updated@example.com',
        role: 'ADMIN' as const,
        isActive: true,
      };

      const { updateUser: updateUserAction } = useUsersStore.getState();
      const result = await updateUserAction('1', updateData);

      expect(result).toEqual(updatedUser);

      const state = useUsersStore.getState();
      expect(state.isLoadingUser).toBe(false);
      expect(state.users[0]).toEqual(updatedUser);
      expect(state.currentUser).toEqual(updatedUser);
    });
  });

  describe('deleteUser', () => {
    it('deletes user successfully', async () => {
      const userToDelete = {
        id: '2',
        email: 'user2@example.com',
        role: 'USER',
        isActive: true,
        createdAt: '2024-01-02T00:00:00Z',
        updatedAt: '2024-01-02T00:00:00Z',
      };

      const users = [
        {
          id: '1',
          email: 'user1@example.com',
          role: 'USER',
          isActive: true,
          createdAt: '2024-01-01T00:00:00Z',
          updatedAt: '2024-01-01T00:00:00Z',
        },
        userToDelete,
      ];

      useUsersStore.setState({ users, currentUser: userToDelete });

      (deleteUser as any).mockResolvedValue(undefined);

      const { deleteUser: deleteUserAction } = useUsersStore.getState();
      await deleteUserAction('2');

      const state = useUsersStore.getState();
      expect(state.isLoadingUser).toBe(false);
      expect(state.users).toHaveLength(1);
      expect(state.users[0].id).toBe('1');
      expect(state.currentUser).toBeNull();
    });
  });

  describe('error handling', () => {
    it('clears error state', () => {
      useUsersStore.setState({ error: 'Test error' });
      const { clearError } = useUsersStore.getState();

      clearError();

      const state = useUsersStore.getState();
      expect(state.error).toBeNull();
    });

    it('resets store to initial state', () => {
      useUsersStore.setState({
        users: [{ id: '1', email: 'test@example.com', role: 'USER', isActive: true, createdAt: '', updatedAt: '' }],
        currentUser: { id: '1', email: 'test@example.com', role: 'USER', isActive: true, createdAt: '', updatedAt: '' },
        pagination: { page: 1, limit: 10, total: 1, totalPages: 1 },
        isLoading: true,
        isLoadingUser: true,
        error: 'Test error',
      });

      const { reset } = useUsersStore.getState();
      reset();

      const state = useUsersStore.getState();
      expect(state.users).toEqual([]);
      expect(state.currentUser).toBeNull();
      expect(state.pagination).toBeNull();
      expect(state.isLoading).toBe(false);
      expect(state.isLoadingUser).toBe(false);
      expect(state.error).toBeNull();
    });
  });
});