// Libs
// -----------------------------------------------------------------------------
import React, { FC, Fragment, useState, useMemo, useCallback } from 'react';
import {
  Modal,
  Table,
  Button,
  Row,
  Col,
  Input,
  Space,
  Form,
  TablePaginationConfig,
} from 'antd';
import { PlusOutlined, EditOutlined } from '@ant-design/icons';

// App
// -----------------------------------------------------------------------------
import { TypeNameDescriptionModel } from 'types/default';
import { makeForeignKeyEntitiesTableColumns } from './makeForeignKeyEntitiesTableColumns';
import {
  openNotificationSuccess,
  openNotificationError,
} from 'components/Messages';
import { useForeignKeyEntitiesTableMessages } from './i18n';
import { GenericDataStore } from 'stores/GenericDataStore';

// Props
// -----------------------------------------------------------------------------
type ForeignKeyEntitiesTableProps = {
  title: string;
  dataStore: GenericDataStore<TypeNameDescriptionModel>;
  isDisabled?: boolean;
};

/**
 * Таблица-редактор для значений внешних ключей.
 */
export const ForeignKeyEntitiesTable: FC<ForeignKeyEntitiesTableProps> = ({
  title,
  dataStore,
  isDisabled = false,
}) => {
  const [isVisible, setIsVisible] = useState<boolean>(false);
  const [editedId, setEditedId] = useState<number | null>(null);
  const [isAddingNew, setIsAddingNew] = useState<boolean>(false);
  const [searchString, setSearchString] = useState<string>('');

  const [form] = Form.useForm<TypeNameDescriptionModel>();

  const locale = useForeignKeyEntitiesTableMessages();

  const onEntityCreate = useCallback(
    async (entity: TypeNameDescriptionModel): Promise<void> => {
      await dataStore.create(entity);
    },
    [dataStore],
  );

  const onEntityUpdate = useCallback(
    async (entity: TypeNameDescriptionModel): Promise<void> => {
      await dataStore.update(entity.id, entity);
    },
    [dataStore],
  );

  const onEntityDelete = useCallback(
    async (entity: TypeNameDescriptionModel['id']): Promise<void> => {
      await dataStore.delete(entity);
    },
    [dataStore],
  );

  const columns = useMemo(() => {
    return makeForeignKeyEntitiesTableColumns({
      editedId,
      searchString,
      locale,
      actions: {
        onSave: () => {
          form.submit();
        },
        onDelete: async (entity) => {
          try {
            if (onEntityDelete) {
              await onEntityDelete(entity.id);
              openNotificationSuccess({ messageTitle: locale.success });
            }
          } catch {
            openNotificationError({ messageTitle: locale.failure });
          }
        },
        onEdit: (entity) => {
          form.setFieldsValue(entity);
          setEditedId(entity.id);
        },
        onCancel: () => {
          form.resetFields();
          setEditedId(null);
        },
      },
    });
  }, [form, editedId, onEntityDelete, searchString, locale]);

  const pagination: TablePaginationConfig = useMemo(
    () => ({
      showTotal: (total: number) => `${locale.total}: ${total}`,
      showSizeChanger: true,
      size: 'default',
      locale: {
        items_per_page: '',
      },
      pageSizeOptions: [5, 10, 20, 50, 100],
      defaultPageSize: 5,
    }),
    [locale],
  );

  const onFormFinish = useCallback(
    async (values: TypeNameDescriptionModel) => {
      try {
        if (isAddingNew && onEntityCreate) {
          await onEntityCreate(values);
          setIsAddingNew(false);
          openNotificationSuccess({ messageTitle: locale.success });
        } else if (onEntityUpdate) {
          await onEntityUpdate(values);
          setEditedId(null);
          openNotificationSuccess({ messageTitle: locale.success });
        }
      } catch {
        openNotificationError({ messageTitle: locale.failure });
      }
    },
    [isAddingNew, onEntityCreate, onEntityUpdate, locale],
  );

  const filteredEntityList: Array<TypeNameDescriptionModel> = useMemo(() => {
    return searchString
      ? dataStore.list.filter((entity) =>
          entity.name.toUpperCase().includes(searchString.toUpperCase()),
        )
      : dataStore.list;
  }, [dataStore.list, searchString]);

  return (
    <Fragment>
      <Button
        onClick={() => {
          setIsVisible(true);
        }}
        disabled={isDisabled}
        icon={<EditOutlined />}
        title={locale.editList}
      />

      <Modal
        title={title}
        visible={isVisible}
        onCancel={() => {
          setIsVisible(false);
        }}
        width="80%"
        footer={null}
      >
        <Form form={form} component={false} onFinish={onFormFinish}>
          <Space direction="vertical" style={{ display: 'flex' }}>
            <Row>
              <Col flex="none">
                <Button
                  icon={<PlusOutlined />}
                  disabled={
                    dataStore.isLoading || isAddingNew || editedId !== null
                  }
                  onClick={() => {
                    form.resetFields();
                    setIsAddingNew(true);
                  }}
                >
                  {locale.addNew}
                </Button>
              </Col>

              <Col flex="auto"></Col>

              <Col flex="none">
                <Input.Search
                  placeholder={locale.searchByName}
                  disabled={dataStore.isLoading}
                  value={searchString}
                  onChange={(ev) => {
                    setSearchString(ev.target.value);
                  }}
                />
              </Col>
            </Row>

            <Table
              rowKey="id"
              dataSource={filteredEntityList}
              columns={columns}
              pagination={pagination}
              loading={dataStore.isLoading}
              size="small"
              locale={{
                emptyText: locale.emptyList,
              }}
            />
          </Space>

          <Modal
            title={locale.createItem}
            visible={isAddingNew}
            onOk={() => {
              form.submit();
            }}
            onCancel={() => {
              form.resetFields();
              setIsAddingNew(false);
            }}
            okText={locale.create}
            okButtonProps={{ disabled: dataStore.isLoading }}
            cancelText={locale.cancel}
            cancelButtonProps={{ disabled: dataStore.isLoading }}
          >
            <Form.Item name="name" label={locale.name} labelCol={{ span: 8 }}>
              <Input />
            </Form.Item>

            <Form.Item
              name="description"
              label={locale.description}
              labelCol={{ span: 8 }}
            >
              <Input.TextArea rows={5} />
            </Form.Item>
          </Modal>
        </Form>
      </Modal>
    </Fragment>
  );
};
