// Libs
// -----------------------------------------------------------------------------
import { ComponentType, useEffect } from 'react';
import { observer } from 'mobx-react-lite';
import { Button, Form, FormInstance, TableColumnProps } from 'antd';
import { ValidateErrorEntity } from 'rc-field-form/lib/interface';
import { TableRowSelection } from 'antd/lib/table/interface';

// App
// -----------------------------------------------------------------------------
import { openNotificationWithIcon } from '../Notification';
import Dashboard from '../Dashboard';
import { CardInfoDrawer } from '../Modals/CardInfoDrawer/CardInfoDrawer';
import { GenericDataStore } from 'stores/GenericDataStore';
import { GenericDashboardUiStore } from 'stores/GenericDashboardUiStore';
import { TypeLeftSidebar } from '../Dashboard/types';
import { TypeActionButtonsConfig } from '../DashboardTable/components/useActionsWithSelectedCards/types';
import useActionsWithSelectedCards from '../DashboardTable/components/useActionsWithSelectedCards';
import { GenericDashboardLocale } from './types';
import { useCommonMessages } from '../i18n';
import { openNotificationSuccess } from '../Messages';
import { handleFormRequestError } from '../helpers';

// Props
// -----------------------------------------------------------------------------
type GenericDashboardProps<T, TB = T> = {
  // MobX-стор для состояния интерфейса
  uiStore: GenericDashboardUiStore<T>;
  // MobX-стор для загрузки и хранения данных
  dataStore: GenericDataStore<T, TB>;
  // Конфигурация левой панели навигации
  sidebarContent: Array<TypeLeftSidebar>;
  // Объект локализации
  locale: GenericDashboardLocale;
  // Колонки таблицы Ant Design Table
  columns: Array<TableColumnProps<T>>;
  // Функция для загрузки вспомогательных данных
  fetchRelatedData?: () => Promise<void>;
  // Компонент для отрисовки карточки элемента таблицы
  cardComponent: ComponentType<{
    // Ant Design Form для редактирования элемента таблицы
    form: FormInstance<T>;
    // Объект локализации
    locale: GenericDashboardLocale;
    // Ссылка на родительский MobX-стор для состояния интерфейса
    uiStore: GenericDashboardUiStore<T>;
    // Ссылка на родительский MobX-стор для загрузки и хранения данных
    dataStore: GenericDataStore<T, TB>;
    // Действие для успешной отправки формы (Form.onFinish)
    onFormSubmit: (values: T) => void;
    // Действие для ошибки заполнения формы (Form.onFinishFailed)
    onFormError: (errData: ValidateErrorEntity<T>) => void;
  }>;
  // Конфигурация кнопок коллективных действий с элементами таблицы
  actionButtonsConfig?: Array<TypeActionButtonsConfig>;
  // Включить поддержку выделения нескольких строк
  enableRowSelection?: boolean;
  // Задать дополнительные настройки чекбокса выделения строки
  getCheckboxProps?: TableRowSelection<T>['getCheckboxProps'];
};

export const GenericDashboard = observer(
  <T, TB = T>({
    uiStore,
    dataStore,
    sidebarContent,
    locale,
    columns,
    fetchRelatedData,
    cardComponent: GenericCard,
    actionButtonsConfig,
    enableRowSelection = false,
    getCheckboxProps,
  }: GenericDashboardProps<T, TB>): JSX.Element => {
    // Объект общей локализации
    const commonLocale = useCommonMessages();

    // Форма карточки группы
    const [form] = Form.useForm<T>();

    // При изменении пагинации таблицы перезагрузить контент
    useEffect(() => {
      dataStore.fetchForCurrentPage();
    }, [
      dataStore,
      dataStore.currentPage,
      dataStore.pageSize,
      dataStore.ordering,
    ]);

    // При смене выбранного правила заполнить форму его данными
    useEffect(() => {
      if (uiStore.currentElement) {
        form.resetFields();
        // TODO: remove ts-ignore
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        form.setFieldsValue(uiStore.currentElement);
      }
    }, [form, uiStore.currentElement]);

    // Загрузить дополнительные данные (например, содержимое селектов)
    useEffect(() => {
      if (fetchRelatedData) {
        fetchRelatedData();
      }
    }, [fetchRelatedData]);

    // Выполнить при сохранении формы группы
    const onCardFormSubmit = async (data: T): Promise<void> => {
      if (uiStore.currentElement && !uiStore.isNewElement) {
        try {
          const dataId = dataStore.getId(data);
          await dataStore.update(dataId, data);
          uiStore.closeForm();
          openNotificationSuccess({
            messageTitle: locale.updateSuccess,
          });
        } catch (err) {
          handleFormRequestError(
            err,
            form,
            locale.updateError,
            commonLocale.notification.pleaseCheckData,
          );
        }
      } else {
        try {
          await dataStore.create(data);
          uiStore.closeForm();
          openNotificationSuccess({
            messageTitle: locale.creationSuccess,
          });
        } catch (err) {
          handleFormRequestError(
            err,
            form,
            locale.creationError,
            commonLocale.notification.pleaseCheckData,
          );
        }
      }
    };

    // Выполнить при ошибке валидации формы
    const onCardFormSubmitError = (err: ValidateErrorEntity<T>): void => {
      if (err.errorFields.length !== 0)
        openNotificationWithIcon('error', {
          message: commonLocale.notification.pleaseCheckData,
        });
    };

    // Кнопка добавления группы
    const addNewEntity = {
      entity: (
        <Button
          style={{ position: 'absolute', top: 5, right: 50 }}
          onClick={uiStore.setNewCurrentElement}
          type="primary"
        >
          {locale.add}
        </Button>
      ),
    };

    // Сбросить поля формы и закрыть ее
    const closeAndResetForm = (): void => {
      form.resetFields();
      uiStore.closeForm();
    };

    // Имя выбранного элемента (для заголовка открытой карточки)
    const currentElementName =
      uiStore.currentElement && !uiStore.isNewElement
        ? dataStore.getName(uiStore.currentElement)
        : locale.newEntity;

    return (
      <Dashboard
        cards={dataStore.list}
        columns={columns}
        setCheckedColumns={uiStore.setCheckedColumns}
        getCheckedColumns={uiStore.checkedColumns}
        setSorterField={dataStore.setOrdering}
        onRowEvent={uiStore.setCurrentElement}
        loading={dataStore.isLoading}
        onSearch={null}
        leftSideBarContent={sidebarContent}
        changeRowCount={dataStore.setDashboardState}
        pageState={dataStore.dashboardState}
        addNewEntity={addNewEntity}
        actionsWithCards={
          actionButtonsConfig
            ? useActionsWithSelectedCards(actionButtonsConfig)
            : null
        }
        filters={null}
        rowSelection={
          enableRowSelection
            ? {
                selectedRowKeys: uiStore.selectedRowKeys,
                onSetSelectedRowItem: uiStore.setSelectedRowKeys,
              }
            : undefined
        }
        getRowId={(entity: T) => dataStore.getId(entity)}
        getCheckboxProps={getCheckboxProps}
        cardInfoComponent={
          <CardInfoDrawer
            title={currentElementName}
            formProps={form}
            cardSize={uiStore.cardSize}
            disabled={uiStore.isFormDisabled}
            setDisabled={uiStore.setIsFormDisabled}
            onToggleCardSize={uiStore.toggleCardSize}
            onCloseCard={closeAndResetForm}
          >
            <GenericCard
              form={form}
              locale={locale}
              uiStore={uiStore}
              dataStore={dataStore}
              onFormSubmit={onCardFormSubmit}
              onFormError={onCardFormSubmitError}
            />
          </CardInfoDrawer>
        }
      />
    );
  },
);
