import { ApiResponse } from "apisauce";
import get from "lodash/get";
import { RootState } from "redux/rootReducer";
import store from "redux/store";
import { logoutActions } from "redux/User/actions";
import { authService } from "services";
import notification from "utils/notification";
import config from "config";

export type GeneralApiProblem =
  /**
   * Times up.
   */
  | { kind: "timeout"; temporary: true; message?: string; status: number }
  /**
   * Cannot connect to the server for some reason.
   */
  | {
      kind: "cannot-connect";
      temporary: true;
      message?: string;
      status: number;
    }
  /**
   * The server experienced a problem. Any 5xx error.
   */
  | { kind: "server"; message?: string; status: number }
  /**
   * We're not allowed because we haven't identified ourself. This is 401.
   */
  | {
      kind: "unauthorized";
      message?: string;
      messageTx?: string;
      status: number;
    }
  /**
   * We don't have access to perform that request. This is 403.
   */
  | {
      kind: "forbidden";
      message?: string;
      status: number;
    }
  /**
   * Unable to find that resource.  This is a 404.
   */
  | {
      kind: "not-found";
      message?: string | [{ fieldName: string; message: string }];
      status: number;
    }
  /**
   * Unable to find that resource.  This is a 405.
   */
  | {
      kind: "not-allow";
      message?: string | [{ fieldName: string; message: string }];
      status: number;
    }
  /**
   * All other 4xx series errors.
   */
  | {
      kind: "rejected";
      message?: string | [{ fieldName: string; message: string }];
      status: number;
    }
  /**
   * Something truly unexpected happened. Most likely can try again. This is a catch all.
   */
  | { kind: "unknown"; temporary: true; message?: string; status: number }
  /**
   * The data we received is not in the expected format.
   */
  | { kind: "bad-data"; message?: string; status: number };

/**
 * Attempts to get a common cause of problems from an api response.
 *
 * @param response The api response.
 */
export function getGeneralApiProblem(
  response: ApiResponse<any>
): GeneralApiProblem | null {
  let message = get(response, "data.message");
  const status = response.status as number;
  const errorNetWorkMessage =
    "Oops, we are currently experiencing some unexpected problems. Please come back to the site a bit later on";
  switch (response.problem) {
    case "CONNECTION_ERROR":
      return {
        kind: "cannot-connect",
        temporary: true,
        message: errorNetWorkMessage,
        status,
      };
    case "NETWORK_ERROR":
      return {
        kind: "cannot-connect",
        temporary: true,
        message: errorNetWorkMessage,
        status,
      };
    case "TIMEOUT_ERROR":
      return {
        kind: "timeout",
        temporary: true,
        message: errorNetWorkMessage,
        status,
      };
    case "SERVER_ERROR":
      return {
        kind: "server",
        message: errorNetWorkMessage,
        status,
      };
    case "UNKNOWN_ERROR":
      return { kind: "unknown", temporary: true, message, status };
    case "CLIENT_ERROR": {
      if (Array.isArray(message)) {
        message = get(response, "data.message[0].message");
      }
      switch (status) {
        case 401:
          if (response.config?.baseURL?.includes(config.api.url)) {
            notification.error({
              message: response.data?.message || "Unauthorized !!!",
            });
            (store as any).dispatch(
              logoutActions.REQUEST({ waiting: 1000, force: true })
            );
          }
          return {
            kind: "unauthorized",
            message,
            messageTx: "errors.auth_invalid_token",
            status,
          };
        case 403:
          return { kind: "forbidden", message, status };
        case 404:
          return { kind: "not-found", message, status };
        case 405:
          if (response.config?.baseURL?.includes(config.api.url)) {
            const userState = (store.getState() as RootState).userState;
            if (
              userState.collaborator ||
              (authService.talentProfileId &&
                typeof authService.talentProfileId === "string")
            ) {
              notification.error({
                message: "Session expired, please login again.",
                duration: 3000,
              });
              (store as any).dispatch(
                logoutActions.REQUEST({ waiting: 1000, force: true })
              );
            }
          }
          return { kind: "not-allow", message, status };
        default: {
          return { kind: "rejected", message, status };
        }
      }
    }
    case "CANCEL_ERROR":
      return null;
    default: {
      return null;
    }
  }
}
