import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { USER_ROLES } from "components/auth/constants";
import { UsersState } from "./state";
import {
  addUserAsync,
  listUsersAsync,
  updateUserAsync,
  getAllocatableLicensesAsync,
  deallocateLicenseAsync,
} from "./operations";
import { RoleType, UserView } from "./types";

const initialState: UsersState = {
  domain: { users: [], allocatableLicenses: [] },
  apps: {
    updateUser: {
      id: 0,
      name: "",
      email: "",
      role: USER_ROLES.NONE,
      authorId: undefined,
      encryption: undefined,
      encryptionPassword: undefined,
      prompt: undefined,
      autoRenew: true,
      notification: true,
    },
    selectedUser: {
      id: 0,
      name: "",
      email: "",
      role: USER_ROLES.NONE,
      authorId: undefined,
      encryption: undefined,
      encryptionPassword: undefined,
      prompt: undefined,
      autoRenew: true,
      notification: true,
    },
    addUser: {
      name: "",
      role: USER_ROLES.NONE,
      email: "",
      autoRenew: true,
      notification: true,
      authorId: undefined,
      encryption: false,
      prompt: false,
      encryptionPassword: undefined,
    },
    licenseAllocateUser: {
      id: 0,
      name: "",
      email: "",
      authorId: "",
      licenseStatus: "",
      expiration: "",
      remaining: "",
    },
    selectedlicenseId: 0,
    hasPasswordMask: false,
    isLoading: false,
  },
};

export const userSlice = createSlice({
  name: "user",
  initialState,
  reducers: {
    changeName: (state, action: PayloadAction<{ name: string }>) => {
      const { name } = action.payload;
      state.apps.addUser.name = name;
    },
    changeEmail: (state, action: PayloadAction<{ email: string }>) => {
      const { email } = action.payload;
      state.apps.addUser.email = email;
    },
    changeRole: (state, action: PayloadAction<{ role: RoleType }>) => {
      const { role } = action.payload;
      state.apps.addUser.role = role;
    },
    changeAuthorId: (
      state,
      action: PayloadAction<{ authorId: string | undefined }>
    ) => {
      const { authorId } = action.payload;
      state.apps.addUser.authorId = authorId?.toUpperCase();
    },
    changeAutoRenew: (state, action: PayloadAction<{ autoRenew: boolean }>) => {
      const { autoRenew } = action.payload;
      state.apps.addUser.autoRenew = autoRenew;
    },
    changeEncryption: (
      state,
      action: PayloadAction<{ encryption: boolean }>
    ) => {
      const { encryption } = action.payload;
      state.apps.addUser.encryption = encryption;
      if (!encryption) {
        state.apps.addUser.encryptionPassword = undefined;
      }
    },
    changePrompt: (state, action: PayloadAction<{ prompt: boolean }>) => {
      const { prompt } = action.payload;
      state.apps.addUser.prompt = prompt;
    },
    changeEncryptionPassword: (
      state,
      action: PayloadAction<{ encryptionPassword: string }>
    ) => {
      const { encryptionPassword } = action.payload;
      state.apps.addUser.encryptionPassword = encryptionPassword;
    },
    changeNotification: (
      state,
      action: PayloadAction<{ notification: boolean }>
    ) => {
      const { notification } = action.payload;
      state.apps.addUser.notification = notification;
    },
    cleanupAddUser: (state) => {
      state.apps.addUser = initialState.apps.addUser;
    },
    changeUpdateUser: (state, action: PayloadAction<{ id: number }>) => {
      const { id } = action.payload;

      const user = state.domain.users.find((x) => x.id === id);

      if (!user) {
        return;
      }

      state.apps.updateUser.id = user.id;
      state.apps.updateUser.name = user.name;
      state.apps.updateUser.email = user.email;
      state.apps.updateUser.role = user.role as RoleType;
      state.apps.updateUser.authorId = user.authorId?.toUpperCase();
      state.apps.updateUser.encryption = user.encryption;
      state.apps.updateUser.encryptionPassword = undefined;
      state.apps.updateUser.prompt = user.prompt;
      state.apps.updateUser.autoRenew = user.autoRenew;
      state.apps.updateUser.notification = user.notification;

      state.apps.selectedUser.id = user.id;
      state.apps.selectedUser.name = user.name;
      state.apps.selectedUser.email = user.email;
      state.apps.selectedUser.role = user.role as RoleType;
      state.apps.selectedUser.authorId = user.authorId?.toUpperCase();
      state.apps.selectedUser.encryption = user.encryption;
      state.apps.selectedUser.encryptionPassword = undefined;
      state.apps.selectedUser.prompt = user.prompt;
      state.apps.selectedUser.autoRenew = user.autoRenew;
      state.apps.selectedUser.notification = user.notification;

      state.apps.hasPasswordMask = user.encryption;
    },
    changeUpdateRole: (state, action: PayloadAction<{ role: RoleType }>) => {
      const { role } = action.payload;
      state.apps.updateUser.role = role;
    },
    changeUpdateAuthorId: (
      state,
      action: PayloadAction<{ authorId: string }>
    ) => {
      const { authorId } = action.payload;
      state.apps.updateUser.authorId = authorId.toUpperCase();
    },
    changeUpdateEncryption: (
      state,
      action: PayloadAction<{ encryption: boolean }>
    ) => {
      const { encryption } = action.payload;
      state.apps.updateUser.encryption = encryption;
      const initEncryption = state.apps.selectedUser.encryption;
      const password = state.apps.updateUser.encryptionPassword;

      if (initEncryption && encryption && !password) {
        state.apps.hasPasswordMask = true;
      }
      if (!encryption) {
        state.apps.updateUser.encryptionPassword = undefined;
      }
    },
    changeUpdateEncryptionPassword: (
      state,
      action: PayloadAction<{ encryptionPassword: string }>
    ) => {
      const { encryptionPassword } = action.payload;
      state.apps.updateUser.encryptionPassword = encryptionPassword;
    },
    changeUpdatePrompt: (state, action: PayloadAction<{ prompt: boolean }>) => {
      const { prompt } = action.payload;
      state.apps.updateUser.prompt = prompt;
    },
    changeUpdateAutoRenew: (
      state,
      action: PayloadAction<{ autoRenew: boolean }>
    ) => {
      const { autoRenew } = action.payload;
      state.apps.updateUser.autoRenew = autoRenew;
    },
    changeUpdateNotification: (
      state,
      action: PayloadAction<{ notification: boolean }>
    ) => {
      const { notification } = action.payload;
      state.apps.updateUser.notification = notification;
    },
    changeHasPasswordMask: (
      state,
      action: PayloadAction<{ hasPasswordMask: boolean }>
    ) => {
      const { hasPasswordMask } = action.payload;
      state.apps.hasPasswordMask = hasPasswordMask;
    },
    cleanupUpdateUser: (state) => {
      state.apps.updateUser = initialState.apps.updateUser;
    },
    changeLicenseAllocateUser: (
      state,
      action: PayloadAction<{ selectedUser: UserView }>
    ) => {
      const { selectedUser } = action.payload;
      state.apps.licenseAllocateUser.id = selectedUser.id;
      state.apps.licenseAllocateUser.name = selectedUser.name;
      state.apps.licenseAllocateUser.email = selectedUser.email;
      state.apps.licenseAllocateUser.authorId =
        selectedUser.authorId.toUpperCase();
      state.apps.licenseAllocateUser.licenseStatus = selectedUser.licenseStatus;
      state.apps.licenseAllocateUser.expiration = selectedUser.expiration;
      state.apps.licenseAllocateUser.remaining = selectedUser.remaining;
    },
    changeSelectedlicenseId: (
      state,
      action: PayloadAction<{ selectedlicenseId: number }>
    ) => {
      const { selectedlicenseId } = action.payload;
      state.apps.selectedlicenseId = selectedlicenseId;
    },
    cleanupLicenseAllocateInfo: (state) => {
      state.apps.licenseAllocateUser = initialState.apps.licenseAllocateUser;
      state.apps.selectedlicenseId = initialState.apps.selectedlicenseId;
    },
  },
  extraReducers: (builder) => {
    builder.addCase(listUsersAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(listUsersAsync.fulfilled, (state, action) => {
      state.domain.users = action.payload.users;
      state.apps.isLoading = false;
    });
    builder.addCase(listUsersAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(addUserAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(addUserAsync.fulfilled, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(addUserAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(updateUserAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(updateUserAsync.fulfilled, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(updateUserAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(getAllocatableLicensesAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(getAllocatableLicensesAsync.fulfilled, (state, action) => {
      state.domain.allocatableLicenses = action.payload.allocatableLicenses;
      state.apps.isLoading = false;
    });
    builder.addCase(getAllocatableLicensesAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(deallocateLicenseAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(deallocateLicenseAsync.fulfilled, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(deallocateLicenseAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
  },
});

export const {
  changeName,
  changeEmail,
  changeRole,
  changeAuthorId,
  changeAutoRenew,
  changeNotification,
  cleanupAddUser,
  changeUpdateUser,
  changeUpdateRole,
  changeUpdateAuthorId,
  changeUpdateEncryption,
  changeUpdateEncryptionPassword,
  changeUpdatePrompt,
  changeUpdateAutoRenew,
  changeUpdateNotification,
  cleanupUpdateUser,
  changeEncryption,
  changePrompt,
  changeEncryptionPassword,
  changeHasPasswordMask,
  changeLicenseAllocateUser,
  changeSelectedlicenseId,
  cleanupLicenseAllocateInfo,
} = userSlice.actions;

export default userSlice.reducer;
