import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { WorktypeState } from "./state";
import {
  addWorktypeAsync,
  editOptionItemsAsync,
  editWorktypeAsync,
  getOptionItemsAsync,
  listWorktypesAsync,
  updateActiveWorktypeAsync,
} from "./operations";
import { OptionItem, isOptionItemDefaultValueType } from "./types";
import { OPTION_ITEMS_DEFAULT_VALUE_TYPE } from "./constants";

const initialState: WorktypeState = {
  apps: {
    isLoading: false,
    isAddLoading: false,
    isEditLoading: false,
    isOptionItemsLoading: false,
    selectedId: NaN,
    worktypeId: "",
    description: undefined,
    optionItems: undefined,
    activeWorktypeId: undefined,
  },
  domain: {},
};

export const worktypeSlice = createSlice({
  name: "worktype",
  initialState,
  reducers: {
    cleanupWorktype: (state) => {
      state.apps.selectedId = initialState.apps.selectedId;
      state.apps.worktypeId = initialState.apps.worktypeId;
      state.apps.description = initialState.apps.description;
      state.apps.optionItems = initialState.apps.optionItems;
    },
    changeSelectedId: (state, action: PayloadAction<{ id: number }>) => {
      const { id } = action.payload;
      state.apps.selectedId = id;
    },
    changeWorktypeId: (
      state,
      action: PayloadAction<{ worktypeId: string }>
    ) => {
      const { worktypeId } = action.payload;
      state.apps.worktypeId = worktypeId;
    },
    changeDescription: (
      state,
      action: PayloadAction<{ description?: string }>
    ) => {
      const { description } = action.payload;
      state.apps.description = description;
    },
    changeOptionItems: (
      state,
      action: PayloadAction<{ optionItem: OptionItem }>
    ) => {
      const { optionItem } = action.payload;

      // defaultValueTypeがDefault以外の場合はinitialValueを空文字にする
      if (
        optionItem.defaultValueType !== OPTION_ITEMS_DEFAULT_VALUE_TYPE.DEFAULT
      ) {
        optionItem.initialValue = "";
      }

      // idが一致するoptionItemを削除して、新しいoptionItemを追加する。一致するidがない場合は何もしない
      const optionItems = state.apps.optionItems?.filter(
        (item) => item.id !== optionItem.id
      );
      if (optionItems) {
        optionItems.push(optionItem);
        // optionItemsをidで昇順にソートする
        optionItems.sort((a, b) => a.id - b.id);
        state.apps.optionItems = optionItems;
      }
    },
  },
  extraReducers: (builder) => {
    builder.addCase(listWorktypesAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(listWorktypesAsync.fulfilled, (state, action) => {
      const { worktypes, active } = action.payload;

      state.domain.worktypes = worktypes;
      state.apps.activeWorktypeId = active;
      state.apps.isLoading = false;
    });
    builder.addCase(listWorktypesAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(addWorktypeAsync.pending, (state) => {
      state.apps.isAddLoading = true;
    });
    builder.addCase(addWorktypeAsync.rejected, (state) => {
      state.apps.isAddLoading = false;
    });
    builder.addCase(addWorktypeAsync.fulfilled, (state) => {
      state.apps.isAddLoading = false;
    });
    builder.addCase(editWorktypeAsync.pending, (state) => {
      state.apps.isEditLoading = true;
    });
    builder.addCase(editWorktypeAsync.rejected, (state) => {
      state.apps.isEditLoading = false;
    });
    builder.addCase(editWorktypeAsync.fulfilled, (state) => {
      state.apps.isEditLoading = false;
    });
    builder.addCase(getOptionItemsAsync.pending, (state) => {
      state.apps.isOptionItemsLoading = true;
    });
    builder.addCase(getOptionItemsAsync.fulfilled, (state, action) => {
      state.apps.isOptionItemsLoading = false;
      const optionItems: OptionItem[] = action.payload.optionItems.map(
        (item) => ({
          id: item.id,
          itemLabel: item.itemLabel,
          defaultValueType: isOptionItemDefaultValueType(item.defaultValueType)
            ? item.defaultValueType
            : OPTION_ITEMS_DEFAULT_VALUE_TYPE.DEFAULT,
          initialValue: item.initialValue,
        })
      );
      state.apps.optionItems = optionItems;
    });
    builder.addCase(getOptionItemsAsync.rejected, (state) => {
      state.apps.isOptionItemsLoading = false;
    });
    builder.addCase(editOptionItemsAsync.pending, (state) => {
      state.apps.isOptionItemsLoading = true;
    });
    builder.addCase(editOptionItemsAsync.fulfilled, (state) => {
      state.apps.isOptionItemsLoading = false;
    });
    builder.addCase(editOptionItemsAsync.rejected, (state) => {
      state.apps.isOptionItemsLoading = false;
    });
    builder.addCase(updateActiveWorktypeAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(updateActiveWorktypeAsync.fulfilled, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(updateActiveWorktypeAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
  },
});
export const {
  changeDescription,
  changeWorktypeId,
  changeSelectedId,
  cleanupWorktype,
  changeOptionItems,
} = worktypeSlice.actions;
export default worktypeSlice.reducer;
