import { createAsyncThunk } from "@reduxjs/toolkit";
import type { RootState } from "app/store";
import { openSnackbar } from "features/ui/uiSlice";
import { getTranslationID } from "translation";
import { getAccessToken } from "features/auth";
import {
  AccountsApi,
  GetTypistGroupsResponse,
  GetTypistsResponse,
  CreateTypistGroupRequest,
  Typist,
  TypistGroup,
} from "../../../api/api";
import { Configuration } from "../../../api/configuration";
import { ErrorObject, createErrorObject } from "../../../common/errors";

export const listTypistGroupsAsync = createAsyncThunk<
  GetTypistGroupsResponse,
  void,
  {
    // rejectした時の返却値の型
    rejectValue: {
      error: ErrorObject;
    };
  }
>("workflow/listTypistGroupsAsync", async (args, thunkApi) => {
  // apiのConfigurationを取得する
  const { getState } = thunkApi;
  const state = getState() as RootState;
  const { configuration } = state.auth;
  const accessToken = getAccessToken(state.auth);
  const config = new Configuration(configuration);
  const accountsApi = new AccountsApi(config);

  try {
    const typistGroup = await accountsApi.getTypistGroups({
      headers: { authorization: `Bearer ${accessToken}` },
    });

    return typistGroup.data;
  } catch (e) {
    // e ⇒ errorObjectに変換"
    const error = createErrorObject(e);
    thunkApi.dispatch(
      openSnackbar({
        level: "error",
        message: getTranslationID("common.message.internalServerError"),
      })
    );
    return thunkApi.rejectWithValue({ error });
  }
});

export const listTypistsAsync = createAsyncThunk<
  GetTypistsResponse,
  void,
  {
    // rejectした時の返却値の型
    rejectValue: {
      error: ErrorObject;
    };
  }
>("workflow/listTypistsAsync", async (args, thunkApi) => {
  // apiのConfigurationを取得する
  const { getState } = thunkApi;
  const state = getState() as RootState;
  const { configuration } = state.auth;
  const accessToken = getAccessToken(state.auth);
  const config = new Configuration(configuration);
  const accountsApi = new AccountsApi(config);

  try {
    const typists = await accountsApi.getTypists({
      headers: { authorization: `Bearer ${accessToken}` },
    });

    return typists.data;
  } catch (e) {
    // e ⇒ errorObjectに変換"
    const error = createErrorObject(e);
    thunkApi.dispatch(
      openSnackbar({
        level: "error",
        message: getTranslationID("common.message.internalServerError"),
      })
    );
    return thunkApi.rejectWithValue({ error });
  }
});

export const createTypistGroupAsync = createAsyncThunk<
  {
    /* Empty Object */
  },
  CreateTypistGroupRequest,
  {
    // rejectした時の返却値の型
    rejectValue: {
      error: ErrorObject;
    };
  }
>("workflow/createTypistGroupAsync", async (args, thunkApi) => {
  // apiのConfigurationを取得する
  const { getState } = thunkApi;
  const state = getState() as RootState;
  const { configuration } = state.auth;
  const accessToken = getAccessToken(state.auth);
  const config = new Configuration(configuration);
  const accountsApi = new AccountsApi(config);

  try {
    await accountsApi.createTypistGroup(args, {
      headers: { authorization: `Bearer ${accessToken}` },
    });
    thunkApi.dispatch(
      openSnackbar({
        level: "info",
        message: getTranslationID("common.message.success"),
      })
    );
    return {};
  } catch (e) {
    // e ⇒ errorObjectに変換"
    const error = createErrorObject(e);
    let message = getTranslationID("common.message.internalServerError");
    if (error.code === "E010204") {
      message = getTranslationID(
        "typistGroupSetting.message.groupSaveFailedError"
      );
    }
    if (error.code === "E010909") {
      message = getTranslationID(
        "typistGroupSetting.message.GroupNameAlreadyExistError"
      );
    }

    thunkApi.dispatch(
      openSnackbar({
        level: "error",
        message,
      })
    );
    return thunkApi.rejectWithValue({ error });
  }
});

export const getTypistGroupAsync = createAsyncThunk<
  {
    typists: Typist[];
    typistGroup: TypistGroup;
    selectedTypistIds: number[];
  },
  { typistGroupId: number },
  {
    // rejectした時の返却値の型
    rejectValue: {
      error: ErrorObject;
    };
  }
>("workflow/getTypistGroupAsync", async (args, thunkApi) => {
  const { typistGroupId } = args;
  // apiのConfigurationを取得する
  const { getState } = thunkApi;
  const state = getState() as RootState;
  const { configuration } = state.auth;
  const accessToken = getAccessToken(state.auth);
  const config = new Configuration(configuration);
  const accountsApi = new AccountsApi(config);

  try {
    // タイピスト取得処理が別にあるが、storeの状態を意識せずに処理を行うためにここで取得する
    const { typists } = (
      await accountsApi.getTypists({
        headers: { authorization: `Bearer ${accessToken}` },
      })
    ).data;
    const { typistGroupName, typistIds } = (
      await accountsApi.getTypistGroup(typistGroupId, {
        headers: { authorization: `Bearer ${accessToken}` },
      })
    ).data;
    return {
      typists,
      typistGroup: { id: typistGroupId, name: typistGroupName },
      selectedTypistIds: typistIds,
    };
  } catch (e) {
    // e ⇒ errorObjectに変換"
    const error = createErrorObject(e);

    const message = getTranslationID("common.message.internalServerError");

    thunkApi.dispatch(
      openSnackbar({
        level: "error",
        message,
      })
    );
    return thunkApi.rejectWithValue({ error });
  }
});

export const updateTypistGroupAsync = createAsyncThunk<
  {
    /* Empty Object */
  },
  void,
  {
    // rejectした時の返却値の型
    rejectValue: {
      error: ErrorObject;
    };
  }
>("workflow/updateTypistGroupAsync", async (args, thunkApi) => {
  // apiのConfigurationを取得する
  const { getState } = thunkApi;
  const state = getState() as RootState;
  const { configuration } = state.auth;
  const accessToken = getAccessToken(state.auth);
  const { updateTypistGroupId, selectedTypists, groupName } =
    state.typistGroup.apps;
  const config = new Configuration(configuration);
  const accountsApi = new AccountsApi(config);
  if (!updateTypistGroupId) {
    throw new Error("updateTypistGroupId is undefined.");
  }

  try {
    await accountsApi.updateTypistGroup(
      updateTypistGroupId,
      {
        typistGroupName: groupName,
        typistIds: selectedTypists.map((x) => x.id),
      },
      {
        headers: { authorization: `Bearer ${accessToken}` },
      }
    );

    thunkApi.dispatch(
      openSnackbar({
        level: "info",
        message: getTranslationID("common.message.success"),
      })
    );
    return {};
  } catch (e) {
    // e ⇒ errorObjectに変換"
    const error = createErrorObject(e);

    let message = getTranslationID("common.message.internalServerError");
    if (error.code === "E010204" || error.code === "E010908") {
      message = getTranslationID(
        "typistGroupSetting.message.groupSaveFailedError"
      );
    }
    if (error.code === "E010909") {
      message = getTranslationID(
        "typistGroupSetting.message.GroupNameAlreadyExistError"
      );
    }

    thunkApi.dispatch(
      openSnackbar({
        level: "error",
        message,
      })
    );
    return thunkApi.rejectWithValue({ error });
  }
});
