import axios, {
  AxiosError,
  AxiosPromise,
  AxiosRequestConfig,
  AxiosResponse,
} from 'axios';
import { environment } from 'enviroments/enviroments';
import { openNotificationError } from '../components/Messages';
import Cookies from 'js-cookie';
import { getCurrentLocale } from 'core/i18n';

/**
 * Create an Axios Client with defaults
 */

const BASE_ERROR_MESSAGE = {
  serverErrorMsg: 'Ошибка на сервере. Обратитесь к администратору',
  badRequestMsg: 'Ошибка запроса. Попробуйте изменить параметры запроса',
  accessForbidden: 'Доступ запрещен',
  internalServerError: 'Ошибка сервера',
  notFound: 'Сервер не может найти данные согласно запросу',
};

const csrftokens = Cookies.get('csrftoken');

const { localhostDev, apiPrefix, localhost } = environment;

const client = axios.create({
  headers: {
    Authorization: `Token ${localStorage.getItem('Token')}`,
    'Content-Type': 'application/json',
    'X-CSRFToken': csrftokens || true,
  },
  withCredentials: true,
  xsrfHeaderName: 'X-CSRFToken',
  xsrfCookieName: 'csrftoken',
});

const showErrorNotificationWithUrlCheck = (
  error: AxiosError,
  message: string,
): void => {
  const configRequest =
    error.config.url?.match('config_request') ||
    error.config.url?.match('upload_config') ||
    error.config.url?.match('download_config') ||
    error.config.url?.match('reboot') ||
    error.config.url === 'company/' ||
    error.config.url === 'license/';

  // Todo
  // Для страницы компании пришлось написать данный if, чтобы работать с ошибками,
  // И есть один помент, если компании нет то бэк отдает мне 404. что неправильно. Переделают на 200 с объектом {"detail":"Not found."} и потом раскоментирую

  // if (error.config.url === 'company/') {
  //   return error.response?.data;
  // } else

  // Перебросить исключение дальше по этому условию.
  const shouldRethrow =
    error.config.url?.match('users/') ||
    error.config.url?.match('correlation/');

  if (error.config.url?.match('upload_ids_rulesets')) {
    throw new Error(error.message);
  } else if (configRequest) {
    throw new Error(error.response?.data || error.message);
  } else if (shouldRethrow) {
    throw error;
  } else {
    openNotificationError({ messageTitle: message });
  }
};

const request = <OT = any, RT = any>(
  options: AxiosRequestConfig<OT>,
): AxiosPromise<RT> => {
  const onSuccess = function (response: AxiosResponse): any {
    return response;
  };

  const onError = async function (error: AxiosError): Promise<void> {
    console.error('Request Failed:', error.config);

    if (error.response) {
      const { status } = error.response;
      let msg: string = error?.message || error?.response.data?.[0]?.value;
      switch (status) {
        case 400:
          msg = BASE_ERROR_MESSAGE.badRequestMsg;
          break;
        case 403:
          msg = BASE_ERROR_MESSAGE.accessForbidden;
          break;
        case 404:
          msg = BASE_ERROR_MESSAGE.notFound;
          break;
        case 500:
          msg = BASE_ERROR_MESSAGE.internalServerError;
          break;
        case 502:
          msg = BASE_ERROR_MESSAGE.internalServerError;
          break;
        default:
          msg = msg ?? BASE_ERROR_MESSAGE.serverErrorMsg;
          break;
      }
      await showErrorNotificationWithUrlCheck(error, msg);
    } else {
      console.error('Error Message:', error.message);
    }

    return Promise.reject(error.response || error.message);
  };

  return client({
    baseURL:
      process.env.NODE_ENV === 'development'
        ? `${localhostDev}${getCurrentLocale()}/${apiPrefix}`
        : `${localhost}${getCurrentLocale()}/${apiPrefix}`,
    ...options,
  })
    .then(onSuccess)
    .catch(onError);
};

export default request;
