import { Pagination, PaginationProps } from '@/components/Pagination';
import { FunctionField } from '@/components/ra-fields';
import { Datagrid, ListToolbar, ListToolbarProps } from '@/components/ra-lists';
import { DatagridProps } from '@/components/ra-lists/Datagrid/Datagrid';
import { useUuid } from '@/hooks';
import { CheckBox, CheckBoxOutlineBlankOutlined, Error } from '@mui/icons-material';
import {
  Button,
  Chip,
  Dialog,
  DialogActions,
  DialogContent,
  DialogContentProps,
  DialogProps,
  Stack
} from '@mui/material';
import _ from 'lodash';
import {
  Identifier,
  ListBase,
  ListControllerProps,
  RaRecord,
  RecordRepresentation,
  WithListContext,
  useGetMany,
  useGetRecordRepresentation,
  useTranslate
} from 'ra-core';
import { PropsWithChildren, useCallback } from 'react';

type RecordRepresentationType = (record: RaRecord) => string;
type EntityFieldProps = {
  id: Identifier;
  onClick?: (record: RaRecord) => void;
  onDelete?: (record: RaRecord) => void;
  recordRepresentation?: RecordRepresentationType;
  resource: string;
};
type EntityLookupDialogProps = PropsWithChildren<{
  onCancel: () => void;
  onConfirm: (selectedIds: Identifier[]) => void;
  multiple: boolean;
  slotProps?: {
    dataGrid?: DatagridProps;
    dialog?: DialogProps;
    dialogContent?: DialogContentProps;
    list?: ListControllerProps;
    listToolbar?: Pick<ListToolbarProps, 'filters'>;
    pagination?: PaginationProps;
  };
}>;

function EntityField(props: EntityFieldProps): JSX.Element | null {
  const { id, onClick: onClickCb, onDelete: onDeleteCb, recordRepresentation, resource } = props;
  const fallbackRecordRepresentation = useGetRecordRepresentation(resource);
  const { data, isLoading, error } = useGetMany<RaRecord>(resource, { ids: [id] });
  const record = _.find(data ?? [], { id });
  const canDelete = !_.isNil(record) && _.isFunction(onDeleteCb);
  const onDelete = useCallback(() => {
    if (canDelete) {
      onDeleteCb(record);
    }
  }, [onDeleteCb, record, canDelete]);
  const canClick = !_.isNil(record) && _.isFunction(onClickCb);
  const onClick = useCallback(() => {
    if (canClick) {
      onClickCb(record);
    }
  }, [onClickCb, record, canClick]);

  if (isLoading) {
    return null;
  } else if (error || _.isNil(record)) {
    return <Error color="error" />;
  } else {
    const label = _.isFunction(recordRepresentation)
      ? recordRepresentation(record)
      : fallbackRecordRepresentation(record);
    return <Chip label={label} onDelete={canDelete ? onDelete : undefined} onClick={canClick ? onClick : undefined} />;
  }
}

function EntityLookupDialog(props: EntityLookupDialogProps): JSX.Element {
  const uuid = useUuid();
  const t = useTranslate();
  const { children, multiple, onCancel, onConfirm, slotProps } = props;

  const {
    dialogContent: dialogContentProps = {},
    listToolbar: listToolbarProps = {},
    pagination: paginationProps
  } = slotProps ?? {};

  const listProps = _.chain(slotProps?.list)
    .defaults({ disableSyncWithLocation: true, emptyWhileLoading: true, exporter: false })
    .value();

  const hasListToolbar = !_.isNil(listToolbarProps.filters);

  const dialogProps = _.chain(slotProps?.dialog)
    .defaults({ disableEscapeKeyDown: true, fullWidth: true, keepMounted: false, open: false })
    .value();

  const dataGridProps = _.chain(slotProps?.dataGrid)
    .defaults({})
    .extend({
      bulkActionButtons: false,
      rowClick: 'toggleSelection'
    })
    .value();

  const updateSelection = useCallback(
    (selectedIds: Identifier[], id: Identifier): Identifier[] => {
      if (multiple) {
        return _.includes(selectedIds, id) ? _.without(selectedIds, id) : _.concat(selectedIds, id);
      } else {
        return _.includes(selectedIds, id) ? [] : [id];
      }
    },
    [multiple]
  );
  return (
    <ListBase {...listProps} storeKey={`reference-lookup-input-${uuid}`}>
      <WithListContext
        render={({ onSelect, selectedIds, onUnselectItems }) => {
          return (
            <Dialog
              {...dialogProps}
              onClose={() => {
                onUnselectItems();
                onCancel();
              }}
            >
              <DialogContent {...dialogContentProps}>
                <Stack spacing={2} flexDirection="column">
                  {hasListToolbar ? <ListToolbar {...listToolbarProps} /> : null}
                  <Datagrid {...dataGridProps} onToggleItem={(id) => onSelect(updateSelection(selectedIds, id))}>
                    <FunctionField
                      render={(record) =>
                        _.includes(selectedIds, record.id) ? <CheckBox /> : <CheckBoxOutlineBlankOutlined />
                      }
                    />
                    {children ?? (
                      <FunctionField
                        label={t('ra.input.referenceLookup.dialog.defaultField')}
                        render={(record) => <RecordRepresentation record={record} />}
                      />
                    )}
                  </Datagrid>
                  <Pagination {...paginationProps} />
                  <DialogActions>
                    <Button
                      onClick={() => {
                        onUnselectItems();
                        onCancel();
                      }}
                    >
                      {t('ra.input.referenceLookup.dialog.cancel')}
                    </Button>
                    <Button
                      disabled={_.isEmpty(selectedIds)}
                      onClick={() => {
                        onConfirm(selectedIds);
                        onUnselectItems();
                      }}
                      color="primary"
                    >
                      {t('ra.input.referenceLookup.dialog.confirm')}
                    </Button>
                  </DialogActions>
                </Stack>
              </DialogContent>
            </Dialog>
          );
        }}
      />
    </ListBase>
  );
}

export { EntityField, EntityLookupDialog };
export type { EntityFieldProps, EntityLookupDialogProps, RecordRepresentationType };
