import { captureException, withScope } from '@sentry/browser';
import axios, { AxiosError } from 'axios';

import useHuSnackbar from '@material-hu/components/design-system/Snackbar';
import { SnackbarProps } from '@material-hu/components/design-system/Snackbar/types';

import {
  isArticlesAccessDeniedError,
  isGroupsAccessDeniedError,
} from 'src/hooks/useGeneralError.helpers';
import {
  isGroupPostNotFoundError,
  isPostNotFoundError,
} from 'src/hooks/useGeneralErrorFilters';
import { ResponseCode } from 'src/types/services';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';

class CustomHumandError extends Error {
  constructor(errorData: any) {
    super();
    this.name = 'CustomHumandError';
    this.message = errorData;
  }
}

type Props = {
  showEnqueueSnackbar?: boolean;
};
export type ShowGeneralErrorFn = ReturnType<typeof useGeneralError>;

const useGeneralError = (props?: Props) => {
  const { showEnqueueSnackbar = true } = props || {};
  const { enqueueSnackbar: huEnqueueSnackbar } = useHuSnackbar();
  const { t } = useTranslation();

  const showGeneralError = (
    errorData: any,
    errorMessage?: string,
    isError: boolean = true,
    snackBarProps?: Partial<SnackbarProps>,
  ) => {
    if (!navigator.onLine) {
      return;
    }

    let error = errorData;
    let shouldReportToSentry = true;

    if (!(errorData instanceof Error)) {
      error = new CustomHumandError(errorData);
    }

    let id;
    withScope(scope => {
      if (axios.isAxiosError(errorData)) {
        errorData = errorData as AxiosError;
        error.name = 'CustomHumandRequestError';
        const normalizedRequestUrl = errorData.config?.url?.replace(
          /[0-9]/g,
          '',
        );
        error.message = `${errorData?.response?.data?.code || ''} ${
          errorData?.response?.status
        } ${normalizedRequestUrl || ''}`.trim();
        scope.setTag('requestBody', errorData.config?.data);
        scope.setTag('requestUrl', errorData.config?.url);
        scope.setTag('responseBody', errorData?.response?.data);
        scope.setTag('statusCode', errorData?.response?.status);
        id = error.response?.headers?.['x-request-id'];
        scope.setTag('request-id', id);
        scope.setTag('errorCode', errorData?.response?.data?.code);

        if (
          !errorData?.response?.status ||
          errorData?.response?.data?.code == ResponseCode.TOKEN_EXPIRED ||
          isGroupsAccessDeniedError(
            errorData as AxiosError<{ code?: string }>,
          ) ||
          isArticlesAccessDeniedError(
            errorData as AxiosError<{ code?: string }>,
          )
        ) {
          shouldReportToSentry = false;
        }

        if (
          isGroupPostNotFoundError(errorData) ||
          isPostNotFoundError(errorData)
        ) {
          shouldReportToSentry = false;
        }
      }

      shouldReportToSentry && captureException(error);
    });

    if (!showEnqueueSnackbar) {
      return;
    }

    const message = errorMessage || t('ERROR_MESSAGE');

    let description = id ? `Error ID: ${id}` : '';
    if (snackBarProps?.description) {
      description = `${snackBarProps?.description}. ${description}`;
    }

    huEnqueueSnackbar({
      title: message,
      variant: isError ? 'error' : 'warning',
      ...snackBarProps,
      description,
    });
  };

  return showGeneralError;
};

export default useGeneralError;
