import { createAsyncThunk } from "@reduxjs/toolkit";
import type { RootState } from "app/store";
import { openSnackbar } from "features/ui";
import { getTranslationID } from "translation";
import { ErrorObject, createErrorObject } from "common/errors";
import {
  AccessTokenResponse,
  AuthApi,
  DelegationAccessTokenResponse,
  DelegationTokenResponse,
} from "../../api/api";
import { Configuration } from "../../api/configuration";
import { getAccessToken, getRefreshToken, loadRefreshToken } from "./utils";

export const updateTokenAsync = createAsyncThunk<
  AccessTokenResponse,
  void,
  {
    // rejectした時の返却値の型
    rejectValue: {
      /* Empty Object */
    };
  }
>("auth/updateTokenAsync", async (args, thunkApi) => {
  // apiのConfigurationを取得する
  const { getState } = thunkApi;
  const state = getState() as RootState;
  const { configuration } = state.auth;
  const refreshToken = loadRefreshToken();
  const config = new Configuration(configuration);
  const authApi = new AuthApi(config);

  try {
    const { data } = await authApi.accessToken({
      headers: { authorization: `Bearer ${refreshToken}` },
    });

    return data;
  } catch (e) {
    return thunkApi.rejectWithValue({});
  }
});

export const updateDelegationTokenAsync = createAsyncThunk<
  DelegationAccessTokenResponse,
  void,
  {
    // rejectした時の返却値の型
    rejectValue: {
      /* Empty Object */
    };
  }
>("auth/updateDelegationTokenAsync", async (args, thunkApi) => {
  // apiのConfigurationを取得する
  const { getState } = thunkApi;
  const state = getState() as RootState;
  const { configuration } = state.auth;
  const refreshToken = getRefreshToken(state.auth);
  const config = new Configuration(configuration);
  const authApi = new AuthApi(config);

  try {
    const { data } = await authApi.delegationAccessToken({
      headers: { authorization: `Bearer ${refreshToken}` },
    });

    return data;
  } catch (e) {
    const error = createErrorObject(e);

    let errorMessage = getTranslationID("common.message.internalServerError");
    if (error.code === "E010503") {
      errorMessage = getTranslationID(
        "partnerPage.message.delegateCancelError"
      );
    }

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

// パートナーのアカウントを代理操作するトークンを取得する
export const getDelegationTokenAsync = createAsyncThunk<
  // 正常時の戻り値の型
  DelegationTokenResponse,
  void,
  {
    // rejectした時の返却値の型
    rejectValue: {
      error: ErrorObject;
    };
  }
>("auth/getDelegationTokenAsync", async (args, thunkApi) => {
  const { getState } = thunkApi;
  const state = getState() as RootState;
  const { configuration } = state.auth;
  const accessToken = getAccessToken(state.auth);
  const { delegatedAccountId } = state.partner.apps;
  const config = new Configuration(configuration);
  const authApi = new AuthApi(config);

  try {
    if (!delegatedAccountId) {
      throw new Error("delegatedAccountId is not set");
    }

    const { data } = await authApi.delegationToken(
      { delegatedAccountId },
      { headers: { authorization: `Bearer ${accessToken}` } }
    );

    thunkApi.dispatch(
      openSnackbar({
        level: "info",
        message: getTranslationID("common.message.success"),
      })
    );
    return data;
  } catch (e) {
    const error = createErrorObject(e);
    let errorMessage = getTranslationID("common.message.internalServerError");

    if (error.code === "E010503") {
      errorMessage = getTranslationID(
        "partnerPage.message.delegateNotAllowedError"
      );
    }
    if (error.code === "E010501") {
      errorMessage = getTranslationID("partnerPage.message.deleteFailedError");
    }

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

    return thunkApi.rejectWithValue({ error });
  }
});
