import type {
  IErrorResponse,
  RequestBody,
  RequestResponse,
} from "./request.types";
import { ContentType, RequestHeader, RequestMethod } from "./common.types";
import { TextUtil } from "@greatness/util";

import { NavigationPath } from "@/constants/navigation";
import JWTUtil from "@/util/JWTUtil";

const GOLANG_API_PATHS = [
  "/admin/",
  "/crime-user-service/millionaires-questions",
  "/services-list",
];

export class RequestHelper {
  public static async handleFetch(
    pathname: string,
    requestOptions?: RequestInit,
  ): Promise<Response> {
    return fetch(RequestHelper.getApiPath(pathname), {
      ...requestOptions,
      headers: {
        [RequestHeader.CONTENT_TYPE]: ContentType.APPLICATION_JSON,
        ...RequestHelper.getAuthenticationHeaders(),
      },
    });
  }

  public static getAuthenticationHeaders() {
    const headers: Record<string, string> = {};
    const { accessToken } = JWTUtil.get();
    if (!TextUtil.isEmpty(accessToken)) {
      headers[RequestHeader.X_JWT] = accessToken!;
    }
    return headers;
  }

  public static getApiPath(pathname: string, apiBasePath?: string): string {
    const apiPath = GOLANG_API_PATHS.some((p) => pathname.includes(p))
      ? import.meta.env.VITE_NEW_API_PATH
      : import.meta.env.VITE_API_PATH;
    return `${apiBasePath ?? apiPath}${pathname}`;
  }

  public static redirectToLoginPage(): void {
    JWTUtil.unset();

    const loginPath = NavigationPath.Login;
    if (window.location.pathname !== loginPath) {
      window.location.pathname = loginPath;
    }
  }
}

export const queryFetcher = async <T>({
  queryKey,
}: {
  queryKey: readonly unknown[];
}): Promise<T> =>
  RequestHelper.handleFetch(queryKey[0] as string).then(async (res) => res.json());

export const request = async <T extends object | undefined>(
  method: RequestMethod,
  pathname: string,
  body?: RequestBody,
): RequestResponse<T> => {
  let response = null;
  let responseData: T | null = null;
  try {
    const isFormData = body instanceof FormData;
    response = await fetch(RequestHelper.getApiPath(pathname), {
      headers: {
        ...(!isFormData && {
          [RequestHeader.CONTENT_TYPE]: ContentType.APPLICATION_JSON,
        }),
        ...RequestHelper.getAuthenticationHeaders(),
      },
      method,
      ...([RequestMethod.POST, RequestMethod.PUT].includes(method) && {
        body: isFormData ? body : JSON.stringify(body),
      }),
    });
    try {
      responseData = (await response.json()) as T;
    } catch {
      // eslint-disable-next-line no-console
      console.warn("No response data", responseData);
    }
    if (
      response.status === 401 &&
      !window.location.pathname.startsWith(NavigationPath.Login)
    ) {
      RequestHelper.redirectToLoginPage();
      throw new Error();
    }
    return {
      isResponseOk: true,
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      response: responseData as any,
      responseStatus: response.status,
    };
  } catch (error) {
    console.error("Request error", error);
    return {
      isResponseOk: false,
      response: (() => {
        // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
        if (responseData !== null) {
          return responseData as IErrorResponse;
        }
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        return "" as unknown as IErrorResponse;
      })(),
      responseStatus: null,
    };
  }
};
