import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { Assignee } from "api";
import {
  createWorkflowAsync,
  getworkflowRelationsAsync,
  deleteWorkflowAsync,
  listWorkflowAsync,
  updateWorkflowAsync,
} from "./operations";
import { WorkflowState } from "./state";

const initialState: WorkflowState = {
  apps: {
    isLoading: false,
    isAddLoading: false,
    selectedAssignees: [],
  },
  domain: {},
};

export const workflowSlice = createSlice({
  name: "workflow",
  initialState,
  reducers: {
    clearWorkflow: (state) => {
      state.apps.selectedWorkflow = undefined;
      state.apps.selectedAssignees = [];
      state.apps.authorId = undefined;
      state.apps.worktypeId = undefined;
      state.apps.templateId = undefined;
      state.domain.workflowRelations = undefined;
    },
    setAssignees: (state, action: PayloadAction<{ assignees: Assignee[] }>) => {
      const { assignees } = action.payload;
      state.apps.selectedAssignees = assignees;
    },
    addAssignee: (state, action: PayloadAction<{ assignee: Assignee }>) => {
      const { assignee } = action.payload;
      const { selectedAssignees } = state.apps;

      // assigneeがselectedAssigneesに存在するか確認する
      const isDuplicate = selectedAssignees.some(
        (x) =>
          x.typistUserId === assignee.typistUserId &&
          x.typistGroupId === assignee.typistGroupId
      );

      // 重複していなければ追加する
      if (!isDuplicate) {
        const newSelectedAssignees = [...selectedAssignees, assignee];
        // stateに保存する
        state.apps.selectedAssignees = newSelectedAssignees;
      }
    },
    removeAssignee: (state, action: PayloadAction<{ assignee: Assignee }>) => {
      const { assignee } = action.payload;
      const { selectedAssignees } = state.apps;
      // selectedAssigneeの要素からassigneeを削除する
      state.apps.selectedAssignees = selectedAssignees.filter(
        (x) =>
          x.typistUserId !== assignee.typistUserId ||
          x.typistGroupId !== assignee.typistGroupId
      );
    },
    changeAuthor: (
      state,
      action: PayloadAction<{ authorId?: number | undefined }>
    ) => {
      const { authorId } = action.payload;
      state.apps.authorId = authorId;
    },
    changeWorktype: (
      state,
      action: PayloadAction<{ worktypeId?: number | undefined }>
    ) => {
      const { worktypeId } = action.payload;
      state.apps.worktypeId = worktypeId;
    },
    changeTemplate: (
      state,
      action: PayloadAction<{ templateId?: number | undefined }>
    ) => {
      const { templateId } = action.payload;
      state.apps.templateId = templateId;
    },
    changeSelectedWorkflow: (
      state,
      action: PayloadAction<{ workflowId: number }>
    ) => {
      const { workflowId } = action.payload;
      const workflow = state.domain.workflows?.find((x) => x.id === workflowId);
      state.apps.selectedWorkflow = workflow;
    },
  },
  extraReducers: (builder) => {
    builder.addCase(listWorkflowAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(listWorkflowAsync.fulfilled, (state, action) => {
      const { workflows } = action.payload;

      state.domain.workflows = workflows;
      state.apps.isLoading = false;
    });
    builder.addCase(listWorkflowAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(getworkflowRelationsAsync.pending, (state) => {
      state.apps.isAddLoading = true;
    });
    builder.addCase(getworkflowRelationsAsync.fulfilled, (state, action) => {
      const { authors, typistGroups, typists, templates, worktypes } =
        action.payload;

      // 取得したtypistsとtypistGroupsを型変換
      const assineeTypists = typists.map(
        (typist): Assignee => ({
          typistUserId: typist.id,
          typistGroupId: undefined,
          typistName: typist.name,
        })
      );
      const assineeTypistGroups = typistGroups.map(
        (typistGroup): Assignee => ({
          typistUserId: undefined,
          typistGroupId: typistGroup.id,
          typistName: typistGroup.name,
        })
      );
      // 取得したtypistsとtypistGroupsを結合
      const assinees = [...assineeTypists, ...assineeTypistGroups];
      // storeに保存
      state.domain.workflowRelations = {
        authors,
        assignees: assinees,
        templates,
        worktypes,
      };

      state.apps.isAddLoading = false;
    });
    builder.addCase(getworkflowRelationsAsync.rejected, (state) => {
      state.apps.isAddLoading = false;
    });
    builder.addCase(createWorkflowAsync.pending, (state) => {
      state.apps.isAddLoading = true;
    });
    builder.addCase(createWorkflowAsync.fulfilled, (state) => {
      state.apps.isAddLoading = false;
    });
    builder.addCase(createWorkflowAsync.rejected, (state) => {
      state.apps.isAddLoading = false;
    });
    builder.addCase(updateWorkflowAsync.pending, (state) => {
      state.apps.isAddLoading = true;
    });
    builder.addCase(updateWorkflowAsync.fulfilled, (state) => {
      state.apps.isAddLoading = false;
    });
    builder.addCase(updateWorkflowAsync.rejected, (state) => {
      state.apps.isAddLoading = false;
    });
    builder.addCase(deleteWorkflowAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(deleteWorkflowAsync.fulfilled, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(deleteWorkflowAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
  },
});

export const {
  setAssignees,
  addAssignee,
  removeAssignee,
  changeAuthor,
  changeWorktype,
  changeTemplate,
  changeSelectedWorkflow,
  clearWorkflow,
} = workflowSlice.actions;

export default workflowSlice.reducer;
