import { useState, useRef, isValidElement } from 'react';
import PropTypes from 'prop-types';
import { TableFilter, TableViewCol } from 'mui-datatables';
import ReactToPrint, { PrintContextConsumer } from 'react-to-print';
import {
  CloudDownload as DownloadIcon,
  Print as PrintIcon,
  ViewColumn as ViewColumnIcon,
  FilterList as FilterIcon,
  MoreVert as MoreVertIcon,
} from '@mui/icons-material';
import {
  ListItemText,
  useMediaQuery,
  LinearProgress,
  ListItemIcon,
  Popover,
  Menu,
  MenuItem,
  Tooltip,
  IconButton,
} from '@mui/material';
import { useDeepCompareEffect } from 'ahooks';

import { handleCSVDownload } from './utils';
import TableSearch from './TableSearch';
import { useDatatableContext } from './DatatableContext';
import { styled, useTheme } from '../Theme';

function useMobile() {
  const theme = useTheme();
  return useMediaQuery(theme.breakpoints.down('sm'));
}

export default function CustomToolbar({ ...props }) {
  const [menuIconEl, setMenuIconEl] = useState(null);
  const moreBtn = useRef(null);
  const isMobile = useMobile();
  const toolbarId = useRef(Math.random().toString(32).slice(2));
  const [searchOpened, setSearchOpened] = useState(false);
  const { customPreButtons, customButtons, loading, disabled } = useDatatableContext();

  const {
    data = [],
    options,
    components = {},
    columns,
    filterList = [],
    filterData = [],
    filterUpdate,
    resetFilters,
    updateFilterByType,
    toggleViewColumn,
    updateColumns,
    title = '',
    searchText = null,
    searchTextUpdate,
    searchClose,
  } = props;

  const [allPopsEl, setAllPopsEl] = useState({});

  const customToolbarEle = options.customToolbar ? options.customToolbar(props) : '';

  const { search, downloadCsv, print, viewColumns, filterTable } = options.textLabels.toolbar;

  const hideSearch = options.search === false || options.search === 'false';
  const hidePrint = options.print === false || options.print === 'false';

  const TableFilterComponent = components.TableFilter || TableFilter;
  const TableViewColComponent = components.TableViewCol || TableViewCol;

  useDeepCompareEffect(() => {
    if (loading || disabled) {
      setAllPopsEl({});
    }
  }, [loading, disabled]);

  const printArea = (func) => {
    return (
      <ReactToPrint content={() => props.tableRef()}>
        <PrintContextConsumer>{func}</PrintContextConsumer>
      </ReactToPrint>
    );
  };

  const getPopId = (key) => `toolbar-pop-${toolbarId.current}-${key}`;

  const defaultButtons = [];

  // download/viewColumns/filter button behaviours, rendered using custom button logic
  if (!(options.download === false || options.download === 'false')) {
    defaultButtons.push({
      icon: <DownloadIcon />,
      title: downloadCsv,
      onClick: () => {
        handleCSVDownload(props);
      },
    });
  }

  if (!(options.viewColumns === false || options.viewColumns === 'false')) {
    defaultButtons.push({
      icon: <ViewColumnIcon />,
      title: viewColumns,
      // eslint-disable-next-line react/no-unstable-nested-components
      popRender() {
        return (
          <TableViewColComponent
            data={data}
            columns={columns}
            options={options}
            onColumnUpdate={toggleViewColumn}
            updateColumns={updateColumns}
            components={components}
          />
        );
      },
    });
  }

  if (!(options.filter === false || options.filter === 'false')) {
    defaultButtons.push({
      icon: <FilterIcon />,
      title: filterTable,
      // eslint-disable-next-line react/no-unstable-nested-components
      popRender() {
        return (
          <TableFilterComponent
            customFooter={options.customFilterDialogFooter}
            columns={columns}
            options={options}
            filterList={filterList}
            filterData={filterData}
            onFilterUpdate={filterUpdate}
            onFilterReset={resetFilters}
            updateFilterByType={updateFilterByType}
            components={components}
          />
        );
      },
    });
  }

  const showMore =
    [...customPreButtons, !hidePrint, ...defaultButtons, ...customButtons].filter((e) => !!e).length > 1 && isMobile;

  const allPops = [];

  // Large screens show the toolbar buttons directly, small screens show the drop-down menu style buttons
  // The right-hand button of the form toolbar in desktop mode
  const toolbarButtons = [...customPreButtons, ...defaultButtons, ...customButtons].map((e, index) => {
    if (isValidElement(e)) {
      return e;
    }

    const popId = getPopId(index);

    if (e.icon) {
      const { popRender, icon } = e;
      // When popRender is present, clicking the button will bubble up the content returned by the popRender
      if (popRender) {
        allPops.push(
          <Popover
            open={!!allPopsEl[popId]}
            anchorEl={() => allPopsEl[popId]}
            onClose={() => {
              setAllPopsEl({});
            }}
            key={popId}
            anchorOrigin={{
              vertical: 'bottom',
              horizontal: 'right',
            }}>
            <div>{popRender()}</div>
          </Popover>
        );
      }

      return (
        <Tooltip title={e.title} key={popId}>
          <IconButton
            data-testid={`${e.title}-iconButton`}
            id={`btn-${popId}`}
            aria-label={e.title}
            onClick={() => {
              if (e.onClick) {
                e.onClick();
              }

              if (popRender) {
                // On the large screen, the bubble is positioned at the corresponding button
                setAllPopsEl({
                  [popId]: document.getElementById(`btn-${popId}`),
                });
              }
            }}>
            <div className="custom-toolbar-icon">{icon}</div>
          </IconButton>
        </Tooltip>
      );
    }

    return e;
  });

  // The toolbar menu in the mobile to replace toolbarButtons
  const menuItems = [...customPreButtons, ...defaultButtons, ...customButtons].map((e, index) => {
    const popId = getPopId(index);

    let content;

    if (isValidElement(e)) {
      content = e;
    } else if (e.icon) {
      const { icon } = e;

      content = (
        <>
          <ListItemIcon>{icon}</ListItemIcon>
          <ListItemText>{e.title}</ListItemText>
        </>
      );
    }

    return (
      <MenuItem
        key={popId}
        onClick={() => {
          setMenuIconEl(null);
          if (e.onClick) {
            e.onClick();
          }

          if (e.popRender) {
            // On the small screen, the bubbles are positioned at the three dot buttons
            setAllPopsEl({
              [popId]: moreBtn.current,
            });
          }
        }}>
        {content}
      </MenuItem>
    );
  });

  return (
    <div>
      <Container>
        <div
          className={`custom-toobar-title ${
            isMobile && searchOpened && isValidElement(title) ? 'toobar-title-hidden' : ''
          }`}>
          <div className="custom-toobar-title-inner">
            <span>{title}</span>
          </div>
        </div>
        <div className={`custom-toobar-btns ${loading || disabled ? 'toobar-btns-disabled' : ''}`}>
          {!hideSearch && (
            <TableSearch
              search={search}
              options={options}
              searchText={searchText}
              searchTextUpdate={searchTextUpdate}
              searchClose={searchClose}
              onSearchOpen={setSearchOpened}
            />
          )}
          {!showMore && (
            <>
              {!hidePrint &&
                printArea(({ handlePrint }) => (
                  <span>
                    <Tooltip title={print}>
                      <IconButton
                        data-testid={`${print}-iconButton`}
                        aria-label={print}
                        disabled={options.print === 'disabled'}
                        onClick={handlePrint}>
                        <PrintIcon />
                      </IconButton>
                    </Tooltip>
                  </span>
                ))}

              {toolbarButtons}
            </>
          )}
          {showMore && (
            <IconButton
              ref={moreBtn}
              aria-haspopup="true"
              aria-expanded={menuIconEl ? 'true' : undefined}
              onClick={(event) => setMenuIconEl(event.currentTarget)}
              style={{ flexShrink: 0 }}>
              <MoreVertIcon />
            </IconButton>
          )}
        </div>
        {customToolbarEle}
      </Container>
      <Menu
        anchorEl={menuIconEl}
        open={!!menuIconEl}
        onClose={() => setMenuIconEl(null)}
        slotProps={{
          list: {
            'aria-labelledby': 'more-button',
          },
        }}>
        {!hidePrint &&
          printArea(({ handlePrint }) => (
            <MenuItem
              onClick={() => {
                setMenuIconEl(null);
                handlePrint();
              }}>
              <ListItemIcon>
                <PrintIcon fontSize="small" />
              </ListItemIcon>
              <ListItemText>{print}</ListItemText>
            </MenuItem>
          ))}
        {menuItems}
      </Menu>
      {allPops.map((e, index) => (
        <div key={getPopId(index)}>{e}</div>
      ))}
      <ProgressContainer>{loading && <LinearProgress className="toolbar-progress" />}</ProgressContainer>
    </div>
  );
}

CustomToolbar.propTypes = {
  data: PropTypes.array,
  options: PropTypes.object.isRequired,
  components: PropTypes.object,
  columns: PropTypes.array.isRequired,
  filterList: PropTypes.array,
  filterData: PropTypes.array,
  filterUpdate: PropTypes.func.isRequired,
  resetFilters: PropTypes.func.isRequired,
  updateFilterByType: PropTypes.func.isRequired,
  toggleViewColumn: PropTypes.func.isRequired,
  updateColumns: PropTypes.func.isRequired,
  title: PropTypes.any,
  searchText: PropTypes.any,
  searchTextUpdate: PropTypes.func.isRequired,
  searchClose: PropTypes.func.isRequired,
  tableRef: PropTypes.func.isRequired,
};

const Container = styled('div')`
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  .custom-toobar-title {
    flex: 1 1 auto;
    font-size: 18px;
    font-weight: 800;
    transition: all ease 0.3s;
    &-inner {
      width: 100%;
      span {
        display: inline-block;
        max-width: 100%;
        white-space: nowrap;
        text-overflow: ellipsis;
        overflow: hidden;
      }
    }
  }
  .custom-toobar-btns {
    display: flex;
    justify-content: center;
    align-items: center;
    &.toobar-btns-disabled {
      position: relative;
      opacity: 0.5;
      &:after {
        position: absolute;
        display: block;
        z-index: 2;
        width: 100%;
        height: 100%;
        left: 0;
        top: 0;
        content: '';
        cursor: not-allowed;
      }
    }
    .custom-toolbar-icon {
      display: flex;
      justify-content: center;
      align-items: center;
      width: 24px;
      height: 24px;
      font-size: 20px;
      overflow: hidden;
    }
  }
  .toobar-title-hidden {
    opacity: 0;
    cursor: none;
  }
`;

const ProgressContainer = styled('div')`
  width: 100%;
  height: 2px;
  .toolbar-progress {
    height: 2px;
  }
`;
