/* -------------------------------------------------------------------------- */
/*                                    Types                                   */
/* -------------------------------------------------------------------------- */
import type { User } from "../domain/userEntity";
import { create } from "../domain/userModel";
import { CreateUserRequest, UserDTO } from "./dto";
/* -------------------------------------------------------------------------- */
/*                                   Service                                  */
/* -------------------------------------------------------------------------- */
import {
  getTokens,
  graphQlConfig,
  integratorApiClient,
} from "auth/data/authService";
import Failure from "core/failure";
import NotFoundFailureHandler from "core/handlers/notFoundFailureHandler";
import ExecOnAnyHandler from "core/handlers/execOnAnyFailureHandler";
import jwtDecode from "jwt-decode";
import { AccessTokenDTO } from "auth/data/dto";
import { AxiosError, AxiosResponse } from "axios";
import { print } from "graphql";
import updateGraphQLQuery, { QueryInterface } from "gql/updateUserMutation";
/* -------------------------------------------------------------------------- */
/*                           User service functions                           */
/* -------------------------------------------------------------------------- */
function getUser(): Promise<User> {
  return new Promise(async function (resolve, reject) {
    await integratorApiClient
      .get<UserDTO>("/profile")
      .then((response) => {
        const content = response.data;
        resolve(
          create({
            email: content.data.email,
            username: content.data.username,
            firstname: content.data.first_name,
            lastname: content.data.last_name,
            twoFactorEnabled: false,
          })
        );
      })
      .catch((reason: AxiosError) => {
        const handler = new NotFoundFailureHandler(
          () => {
            createUser()
              .then((user) => {
                resolve(user);
              })
              .catch(() => {
                reject(Failure.fromReason(reason, "getUserRequest"));
              });
          },
          new ExecOnAnyHandler(() => {
            reject(Failure.fromReason(reason, "getUserRequest"));
          })
        );
        handler.handle(Failure.fromReason(reason));
      });
  });
}

function createUser(): Promise<User> {
  return new Promise(async function (resolve, reject) {
    const [access] = getTokens();
    if (!access) {
      reject();
    }
    const jwt = jwtDecode<AccessTokenDTO>(access!);
    const user: User = {
      firstname: jwt.given_name,
      username: jwt.preferred_username,
      lastname: jwt.family_name,
      email: jwt.email,
      twoFactorEnabled: false,
    };

    await integratorApiClient
      .post<any, AxiosResponse, CreateUserRequest>("/profile", {
        first_name: jwt.given_name,
        last_name: jwt.family_name,
        email: jwt.email,
        username: jwt.preferred_username,
      })
      .then(() => resolve(user))
      .catch(() => reject());
  });
}

function updateUser(user: Partial<User>): Promise<void> {
  return new Promise(async function (resolve, reject) {
    await integratorApiClient
      .post<any, AxiosResponse<any, any>, QueryInterface>(
        "",
        {
          query: print(updateGraphQLQuery),
          variables: {
            data: {
              first_name: user.firstname,
              last_name: user.lastname,
              username: user.username,
              email: user.email,
            },
          },
        },
        graphQlConfig
      )
      .then(() => {
        resolve();
      })
      .catch((reason) => {
        reject(Failure.fromReason(reason, "updateUserRequest"));
      });
  });
}

export { getUser, updateUser };
