import { createAsyncThunk } from "@reduxjs/toolkit";
import type { RootState } from "app/store";
import { setToken } from "features/auth";
import { KEYS_TO_PRESERVE } from "components/auth/constants";
import {
  AuthApi,
  UsersApi,
  GetMyUserResponse,
  TokenResponse,
} from "../../api/api";
import { Configuration } from "../../api/configuration";
import { ErrorObject, createErrorObject } from "../../common/errors";

export const loginAsync = createAsyncThunk<
  TokenResponse,
  {
    idToken: string;
  },
  {
    // rejectした時の返却値の型
    rejectValue: {
      error: ErrorObject;
    };
  }
>("login/loginAsync", async (args, thunkApi) => {
  const { idToken } = args;
  // apiのConfigurationを取得する
  const { getState } = thunkApi;
  const state = getState() as RootState;
  const { configuration } = state.auth;
  const config = new Configuration(configuration);
  const authApi = new AuthApi(config);

  try {
    const { data } = await authApi.token({
      idToken,
      type: "web",
    });
    // アクセストークン・リフレッシュトークンをlocalStorageに保存
    thunkApi.dispatch(
      setToken({
        accessToken: data.accessToken,
        refreshToken: data.refreshToken,
      })
    );
    // ローカルストレージに残すキー
    const keysToPreserve = KEYS_TO_PRESERVE;

    // すべてのローカルストレージキーを取得
    const allKeys = Object.keys(localStorage);

    // 特定のキーを除外して削除
    allKeys.forEach((key) => {
      if (!keysToPreserve.includes(key)) {
        localStorage.removeItem(key);
      }
    });
    return data;
  } catch (e) {
    // e ⇒ errorObjectに変換"
    const error = createErrorObject(e);
    return thunkApi.rejectWithValue({ error });
  }
});

export const getUserInfoAsync = createAsyncThunk<
  // 正常時の戻り値の型
  GetMyUserResponse,
  // 関数の引数の型
  void,
  {
    // rejectした時の返却値の型
    rejectValue: {
      error: ErrorObject;
    };
  }
>("header/getUserInfoAsync", async (_args, thunkApi) => {
  // apiのConfigurationを取得する
  const { getState } = thunkApi;
  const state = getState() as RootState;
  const { configuration, accessToken } = state.auth;
  const config = new Configuration(configuration);
  const usersApi = new UsersApi(config);

  try {
    const userInfo = await usersApi.getMyUser({
      headers: { authorization: `Bearer ${accessToken}` },
    });
    return userInfo.data;
  } catch (e) {
    // e ⇒ errorObjectに変換"
    const error = createErrorObject(e);
    return thunkApi.rejectWithValue({ error });
  }
});
