import _ from 'lodash';
import { Dispatch } from 'redux';
import { showToast, ToastType } from 'src/common/util/show-toast';
import { State } from 'src/redux/types';
import { performApiCall } from 'src/services/api';
import { AuthActionTypes } from 'src/services/auth';
import {
  transformBatchResponse,
  transformRequestMultipleUsers,
  transformRequestUser,
  transformUser,
} from '../transformations';

export enum UserActionTypes {
  FETCH_USERS = 'users/fetch_users',
  FETCH_USER = 'users/fetch_user',
  UPDATE_USER = 'users/update_user',
  CREATE_USER = 'users/create_user',
  DELETE_USER = 'users/delete_user',
  SET_USER_MODAL_LOADING = 'users/user_modal_loading',
  SET_USERS_LOADING = 'users/users_loading',
  CREATE_BATCH_USERS = 'users/create_batch_users',
}

export const setUsersLoading = (isLoading: boolean) => (dispatch: Dispatch<any>) => {
  dispatch({
    type: UserActionTypes.SET_USERS_LOADING,
    payload: isLoading,
  });
};

export const setUserModalLoading = (isLoading: boolean) => (dispatch: Dispatch<any>) => {
  dispatch({
    type: UserActionTypes.SET_USER_MODAL_LOADING,
    payload: isLoading,
  });
};

export const fetchUsers = () => async (dispatch: Dispatch<any>) => {
  dispatch(setUsersLoading(true));

  try {
    const { data } = await performApiCall({
      path: '/users',
      method: 'GET',
    });

    dispatch({
      type: UserActionTypes.FETCH_USERS,
      payload: data.map(transformUser),
    });
  } catch (err) {
    console.error(err);
  }

  dispatch(setUsersLoading(false));
};

export const fetchUserById = (id: string) => async (dispatch: Dispatch<any>) => {
  dispatch(setUserModalLoading(true));

  try {
    const { data } = await performApiCall({
      path: `/users/${id}`,
      method: 'GET',
    });

    dispatch({
      type: UserActionTypes.FETCH_USER,
      payload: transformUser(data),
    });
  } catch (err) {
    console.error(err);
  }

  dispatch(setUserModalLoading(false));
};

export const fetchPersonalInfo = () => async (dispatch: Dispatch<any>) => {
  dispatch(setUserModalLoading(true));

  try {
    const { data } = await performApiCall({
      path: '/me',
      method: 'GET',
    });

    dispatch({
      type: UserActionTypes.FETCH_USER,
      payload: transformUser(data),
    });
  } catch (err) {
    console.error(err);
  }

  dispatch(setUserModalLoading(false));
};

export const updateUserById = (user: any) => async (dispatch: Dispatch<any>, getState: any) => {
  dispatch(setUserModalLoading(true));

  const state: State = getState();

  try {
    const { data } = await performApiCall({
      path: `/users/${user.id}`,
      method: 'PUT',
      body: transformRequestUser(user),
    });

    dispatch({
      type: UserActionTypes.UPDATE_USER,
      payload: transformUser(data),
    });

    if (state.auth.userInfo?.id === user.id) {
      dispatch({
        type: AuthActionTypes.UPDATE_AUTH_USER,
        payload: transformUser(data),
      });
    }

    showToast('User updated successfully.', ToastType.Success);

    dispatch(fetchUsers());
  } catch (err) {
    console.error(err);
  }

  dispatch(setUserModalLoading(false));
};

export const updatePersonalInfo = (user: any) => async (dispatch: Dispatch<any>) => {
  dispatch(setUserModalLoading(true));

  try {
    const { data } = await performApiCall({
      path: '/me',
      method: 'PUT',
      body: transformRequestUser(user),
    });

    dispatch({
      type: UserActionTypes.UPDATE_USER,
      payload: transformUser(data),
    });

    dispatch({
      type: AuthActionTypes.UPDATE_AUTH_USER,
      payload: transformUser(data),
    });

    showToast('Personal information updated successfully.', ToastType.Success);
  } catch (err) {
    console.error(err);
  }

  dispatch(setUserModalLoading(false));
};

export const createUser = (user: any) => async (dispatch: Dispatch<any>) => {
  dispatch(setUserModalLoading(true));

  try {
    const { data } = await performApiCall({
      path: '/users',
      method: 'POST',
      body: transformRequestUser(user),
    });

    dispatch({
      type: UserActionTypes.CREATE_USER,
      payload: transformUser(data),
    });

    showToast('User created successfully.', ToastType.Success);

    dispatch(fetchUsers());
  } catch (err: any) {
    dispatch(setUserModalLoading(false));
    showToast(`${err}`, ToastType.Error);
    throw err;
  }

  dispatch(setUserModalLoading(false));
};

export const deleteUser = (id: string) => async (dispatch: Dispatch<any>) => {
  dispatch(setUserModalLoading(true));

  try {
    await performApiCall({
      path: `/users/${id}`,
      method: 'DELETE',
    });

    dispatch({
      type: UserActionTypes.DELETE_USER,
      payload: {},
    });

    showToast('User deleted successfully.', ToastType.Success);

    dispatch(fetchUsers());
  } catch (err) {
    console.error(err);
  }

  dispatch(setUserModalLoading(false));
};

export const createBatchUsers = (users: any) => async (dispatch: Dispatch<any>) => {
  dispatch(setUserModalLoading(true));

  try {
    const { data } = await performApiCall({
      path: '/users-batch',
      method: 'POST',
      body: transformRequestMultipleUsers(users),
    });

    const responseData = transformBatchResponse(data);

    dispatch({
      type: UserActionTypes.CREATE_BATCH_USERS,
      payload: responseData,
    });

    // show information about created users
    if (!_.isEmpty(responseData.success)) {
      showToast(responseData.success.message, ToastType.Success, Infinity);
    }
    if (!_.isEmpty(responseData.existing)) {
      showToast(responseData.existing.message, ToastType.Error, Infinity);
    }
    if (!_.isEmpty(responseData.failed)) {
      showToast(responseData.failed.message, ToastType.Error, Infinity);
    }

    dispatch(fetchUsers());
  } catch (err: any) {
    dispatch(setUserModalLoading(false));
    showToast(`${err}`, ToastType.Error);
    throw err;
  }

  dispatch(setUserModalLoading(false));
};

export const clearCurrentUser = () => (dispatch: Dispatch<any>) => {
  dispatch({
    type: UserActionTypes.DELETE_USER,
    payload: {},
  });
};
