import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { Assignee, Task } from "api/api";
import { DictationState } from "./state";
import {
  backupTasksAsync,
  getSortColumnAsync,
  listBackupPopupTasksAsync,
  listTasksAsync,
  listTypistGroupsAsync,
  listTypistsAsync,
  playbackAsync,
  updateAssigneeAsync,
  cancelAsync,
} from "./operations";
import {
  SORTABLE_COLUMN,
  DIRECTION,
  DisplayInfoType,
  INIT_DISPLAY_INFO,
  LIMIT_TASK_NUM,
  DirectionType,
  SortableColumnType,
} from "./constants";

const initialState: DictationState = {
  domain: {
    limit: LIMIT_TASK_NUM,
    offset: 0,
    total: 0,
    tasks: [],
    typists: [],
    typistGroups: [],
    backup: {
      tasks: [],
      offset: 0,
      total: 0,
    },
  },
  apps: {
    displayInfo: INIT_DISPLAY_INFO,
    direction: DIRECTION.ASC,
    paramName: SORTABLE_COLUMN.JobNumber,
    selectedTask: undefined,
    assignee: {
      selected: [],
      pool: [],
    },
    isLoading: true,
    isBackupListLoading: false,
    isDownloading: false,
  },
};

export const dictationSlice = createSlice({
  name: "dictation",
  initialState,
  reducers: {
    changeDisplayInfo: (
      state,
      action: PayloadAction<{ column: DisplayInfoType }>
    ) => {
      const { column } = action.payload;
      state.apps.displayInfo = column;
    },
    changeDirection: (
      state,
      action: PayloadAction<{ direction: DirectionType }>
    ) => {
      const { direction } = action.payload;
      state.apps.direction = direction;
    },
    changeParamName: (
      state,
      action: PayloadAction<{ paramName: SortableColumnType }>
    ) => {
      const { paramName } = action.payload;
      state.apps.paramName = paramName;
    },
    changeSelectedTask: (state, action: PayloadAction<{ task: Task }>) => {
      const { task } = action.payload;
      state.apps.selectedTask = task;
    },
    changeAssignee: (
      state,
      action: PayloadAction<{ selected: Assignee[] }>
    ) => {
      const { selected } = action.payload;

      const typists = state.domain.typists.map(
        (x) => ({ typistUserId: x.id, typistName: x.name } as Assignee)
      );
      const typistGroups = state.domain.typistGroups.map(
        (x) => ({ typistGroupId: x.id, typistName: x.name } as Assignee)
      );

      const transcriptionists = [...typists, ...typistGroups];

      const pool = transcriptionists.filter(
        (x) =>
          selected.find(
            (assign) =>
              assign.typistGroupId === x.typistGroupId &&
              assign.typistUserId === x.typistUserId
          ) === undefined
      );

      state.apps.assignee.selected = selected;
      state.apps.assignee.pool = pool;
    },
    changeBackupTaskChecked: (
      state,
      action: PayloadAction<{ audioFileId: number; checked: boolean }>
    ) => {
      const { audioFileId, checked } = action.payload;
      const tasks = state.domain.backup.tasks.map((task) => {
        if (task.audioFileId === audioFileId) {
          task.checked = checked;
        }
        return task;
      });
      state.domain.backup.tasks = tasks;
    },
    changeBackupTaskAllCheched: (
      state,
      action: PayloadAction<{ checked: boolean }>
    ) => {
      const { checked } = action.payload;
      const tasks = state.domain.backup.tasks.map((task) => {
        task.checked = checked;
        return task;
      });
      state.domain.backup.tasks = tasks;
    },
    openFilePropertyInfo: (state, action: PayloadAction<{ task: Task }>) => {
      const { task } = action.payload;
      state.apps.selectedFileTask = task;
    },
  },
  extraReducers: (builder) => {
    builder.addCase(listTasksAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(listTasksAsync.fulfilled, (state, action) => {
      state.domain.limit = action.payload.limit;
      state.domain.offset = action.payload.offset;
      state.domain.total = action.payload.total;
      state.domain.tasks = action.payload.tasks;

      state.apps.isLoading = false;
    });
    builder.addCase(listTasksAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(getSortColumnAsync.fulfilled, (state, action) => {
      state.apps.direction = action.payload.direction;
      state.apps.paramName = action.payload.paramName;
    });
    // 画面起動時にgetSortColumnAsyncがrejectedするとisLoadingがtrueのままになるため
    builder.addCase(getSortColumnAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(listTypistsAsync.fulfilled, (state, action) => {
      state.domain.typists = action.payload.typists;
    });
    builder.addCase(listTypistGroupsAsync.fulfilled, (state, action) => {
      state.domain.typistGroups = action.payload.typistGroups;
    });
    builder.addCase(updateAssigneeAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(updateAssigneeAsync.fulfilled, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(updateAssigneeAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(playbackAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(playbackAsync.fulfilled, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(playbackAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(cancelAsync.pending, (state) => {
      state.apps.isLoading = true;
    });
    builder.addCase(cancelAsync.fulfilled, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(cancelAsync.rejected, (state) => {
      state.apps.isLoading = false;
    });
    builder.addCase(listBackupPopupTasksAsync.pending, (state) => {
      state.apps.isBackupListLoading = true;
    });
    builder.addCase(listBackupPopupTasksAsync.fulfilled, (state, action) => {
      const { offset, total, tasks } = action.payload;
      state.domain.backup.tasks = tasks.map((task) => ({
        ...task,
        checked: true,
      }));
      state.domain.backup.offset = offset;
      state.domain.backup.total = total;

      state.apps.isBackupListLoading = false;
    });
    builder.addCase(listBackupPopupTasksAsync.rejected, (state) => {
      state.apps.isBackupListLoading = false;
    });
    builder.addCase(backupTasksAsync.pending, (state) => {
      state.apps.isDownloading = true;
    });
    builder.addCase(backupTasksAsync.fulfilled, (state) => {
      state.apps.isDownloading = false;
    });
    builder.addCase(backupTasksAsync.rejected, (state) => {
      state.apps.isDownloading = false;
    });
  },
});

export const {
  changeDisplayInfo,
  changeDirection,
  changeParamName,
  changeSelectedTask,
  changeAssignee,
  changeBackupTaskChecked,
  changeBackupTaskAllCheched,
  openFilePropertyInfo,
} = dictationSlice.actions;

export default dictationSlice.reducer;
