// Libs
// -----------------------------------------------------------------------------
import { FormInstance } from 'antd';
import { FieldData } from 'rc-field-form/lib/interface';
import axios from 'axios';

// App
// -----------------------------------------------------------------------------
import { openNotificationError } from '../Messages';

type RecursiveObject = {
  [key: string]: Array<string> | RecursiveObject;
};

type PossibleErrorData = {
  detail?: string | Array<string>;
  non_field_errors?: Array<string>;
} & RecursiveObject;

// Преобразовать структуру ошибок полей Django для Ant Form
const buildFieldErrors = (
  errData: PossibleErrorData,
  path: Array<string> = [],
): Array<FieldData> => {
  let res: Array<FieldData> = [];

  for (const [key, value] of Object.entries(errData)) {
    if (Array.isArray(value)) {
      res.push({ name: [...path, key], errors: value });
    } else if (typeof value === 'object') {
      res = [...res, ...buildFieldErrors(value, [...path, key])];
    }
  }

  return res;
};

const digForText = (obj: RecursiveObject): string | undefined => {
  let res: string | undefined;
  for (const [key, value] of Object.entries(obj)) {
    if (Array.isArray(value) && value.length > 0) {
      res = value[0];
      break;
    } else if (typeof obj[key] === 'object') {
      res = digForText(obj[key] as RecursiveObject);
    }
  }
  return res;
};

// Попробовать получить описание ошибки формы из полей detail или non_field_errors
const getMessageDescription = (
  errData: PossibleErrorData,
): string | undefined => {
  let errorMessageDescription: string | undefined = undefined;

  if (typeof errData === 'object' && errData !== null) {
    if ('detail' in errData) {
      if (typeof errData.detail === 'string') {
        errorMessageDescription = errData.detail;
      } else if (Array.isArray(errData.detail) && errData.detail.length > 0) {
        errorMessageDescription = errData.detail[0].toString();
      }
    } else if ('non_field_errors' in errData) {
      if (
        Array.isArray(errData.non_field_errors) &&
        errData.non_field_errors.length > 0
      ) {
        errorMessageDescription = errData.non_field_errors[0].toString();
      }
    } else {
      errorMessageDescription = digForText(errData);
    }
  }

  return errorMessageDescription;
};

// Обработать ошибки отправки форм (создание/обновление элемента таблицы)
export const handleFormRequestError = <T>(
  // Объект ошибки с бэкенда
  err: unknown,
  // Ссылка на инстанс формы
  form: FormInstance<T>,
  // Заголовок уведомления
  messageTitle: string,
  // Заголовок уведомления для неопознанных ошибок
  commonMessageTitle: string,
): void => {
  if (axios.isAxiosError(err)) {
    const errData = err.response?.data;

    const errorMessageDescription = errData
      ? getMessageDescription(errData)
      : err.message;

    try {
      const fieldErrors: Array<FieldData> = buildFieldErrors(errData);
      form.setFields(fieldErrors);
    } catch (fieldErr) {
      console.error(
        'FIXME: possible Ant and Django form fields mismatch',
        form,
        err,
      );
      throw fieldErr;
    }

    openNotificationError({
      messageTitle: messageTitle,
      messageDescription: errorMessageDescription,
    });
  } else if (err instanceof Error) {
    openNotificationError({
      messageTitle: commonMessageTitle,
      messageDescription: err.message,
    });
  } else {
    openNotificationError({
      messageTitle: commonMessageTitle,
    });
  }
};
