/* eslint-disable react/display-name */
import {
  Box,
  Button,
  InputAdornment,
  MenuItem,
  Select,
  TextField,
  Tooltip,
} from "@mui/material";
import { MaterialReactTable } from "material-react-table";
import PreviousIcon from "@mui/icons-material/ArrowBack";
import NextIcon from "@mui/icons-material/ArrowForward";
import PropTypes from "prop-types";
import React, {
  forwardRef,
  memo,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
  useState,
} from "react";
import SearchIcon from "@mui/icons-material/Search";
import Typography from "@mui/material/Typography";
import Pagination from "@mui/material/Pagination";
import PaginationItem from "@mui/material/PaginationItem";
import { debounce } from "lodash";
import { ExpandMore } from "@mui/icons-material";
import { useNavigate } from "react-router-dom";

import { useStyles } from "./styles/tableStyles";
import ProtectedComponent from "../components/ProtectedComponent";
import { DesktopDatePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns";
import { DateRangePicker } from "@mui/x-date-pickers-pro";
import { enGB } from "date-fns/locale";

const Table = memo(
  forwardRef((props, ref) => {
    const classes = useStyles();
    const {
      getData,
      columns,
      options,
      actions,
      hideTopToolbar = false,
      showAction,
      handleBulkAction,
      handleRowClick = () => {},
      showDownloadAction,
      renderTopToolbar,
      enableRowNumbers,
      rowNumberMode,
      hideShowPerPage = false,
      getRowStyle = () => {},
      searchText,
      navigateTo,
      showDateFilters = false,
    } = props;
    const [data, setData] = useState([]);
    const [formattedColumns, setFormattedColumns] = useState([]);
    const [isError, setIsError] = useState(false);
    const [isLoading, setIsLoading] = useState(true);
    const [isRefetching, setIsRefetching] = useState(false);
    const [rowCount, setRowCount] = useState(0);
    const [columnFilters, setColumnFilters] = useState([]);
    const [globalFilter, setGlobalFilter] = useState("");
    const [sorting, setSorting] = useState([]);
    const [dateRange, setDateRange] = useState([null, null]);
    const tableRef = useRef();
    const [pagination, setPagination] = useState({
      pageIndex: options?.pageIndex ?? 0,
      pageSize: options?.pageSize ?? 10,
    });
    const navigate = useNavigate();

    useImperativeHandle(ref, () => ({
      reFetchData() {
        setIsLoading(true);
        setIsRefetching(true);
        fetchData();
        // tableRef.current.resetRowSelection();
      },
      getSelectedRowData() {
        const selectedRows = tableRef.current.getSelectedRowModel().flatRows;
        const selectedData = selectedRows.map((row) => row.original);
        return selectedData;
      },
      resetPage(checkPage) {
        setPagination((prev) => ({
          ...prev,
          pageIndex: !checkPage
            ? 0
            : data.length === 1 && prev.pageIndex > 0
            ? prev.pageIndex - 1
            : prev.pageIndex,
        }));
      },
    }));
    useEffect(() => {
      // Process columns and add any action columns that have a render function
      const processedColumns = [...columns];

      // Add action columns with render functions
      if (actions && actions.length > 0) {
        actions.forEach((action) => {
          if (action.render && action.field) {
            processedColumns.push({
              accessorKey: action.field,
              header: action.title || "",
              Cell: ({ row }) => action.render(row.original),
            });
          }
        });
      }

      setFormattedColumns(
        processedColumns.map((column, i) => {
          if (column.isBold) {
            return {
              ...column,
              Cell: ({ cell }) => (
                <Typography
                  sx={(theme) => ({
                    opacity: 1,
                    fontWeight: 600,
                    fontSize: "16px",
                    fontFamily: theme.fontFamily.semiBold,
                    color: theme.palette.grey[10],
                  })}
                >
                  {cell.getValue()}
                </Typography>
              ),
            };
          }
          return column;
        })
      );
    }, [columns, actions]);

    const fetchData = async () => {
      if (!data.length) {
        setIsLoading(true);
      } else {
        setIsRefetching(true);
      }
      let filterString = "";
      columnFilters.forEach((filter) => {
        filterString += `${filter.id}=${filter.value}&`;
      });
      let sortingString = sorting
        .map(
          (sort) => `orderBy=${sort.id}&order=${sort.desc ? "DESC" : "ASC"}&`
        )
        .join("");
      let startDate = "";
      let endDate = "";
      if (dateRange) {
        startDate = dateRange[0];
        endDate = dateRange[1];
      }
      try {
        const response = await getData({
          pagination,
          filterString,
          globalFilter,
          sortingString,
          startDate,
          endDate,
        });
        setData(response.data);
        setRowCount(response.rowCount);
      } catch (error) {
        setIsError(true);
        return;
      } finally {
        setIsLoading(false);
        setIsRefetching(false);
      }
      setIsError(false);
    };

    useEffect(() => {
      if (columnFilters && pagination && sorting) {
        fetchData();
      }
    }, [
      columnFilters,
      globalFilter,
      pagination.pageIndex,
      pagination.pageSize,
      sorting,
      dateRange,
    ]);

    const debouncedSearch = useMemo(
      () =>
        debounce((value) => {
          setGlobalFilter(value);

          /* --- set page index to 0 --- */
          setPagination((prevPagination) => ({
            ...prevPagination,
            pageIndex: 0,
          }));
        }, 500),
      []
    );

    // Function to handle page size change
    const handlePageSizeChange = (event) => {
      const newPageSize = event.target.value;

      // Calculate the new page index to maintain the current set of records visible
      const currentPage = pagination.pageIndex;
      const currentRecordIndex = currentPage * pagination.pageSize;
      const newPageIndex = Math.floor(currentRecordIndex / newPageSize);

      // Update pagination state with new page size and index
      setPagination((prevPagination) => ({
        ...prevPagination,
        pageSize: newPageSize,
        pageIndex: newPageIndex,
      }));
    };

    return (
      <>
        <div className={classes.searchContainer}>
          <TextField
            className={classes.searchBar}
            color="secondary"
            id="globalSearch"
            placeholder={`Search ${searchText} here`}
            variant="outlined"
            onChange={(event) => debouncedSearch(event.target.value.trim())}
            InputProps={{
              startAdornment: (
                <InputAdornment position="end">
                  <SearchIcon />
                </InputAdornment>
              ),
            }}
          />
          {showDateFilters && (
            <LocalizationProvider
            className={classes.searchContainer}
            dateAdapter={AdapterDateFns}
            adapterLocale={enGB} // Import: import { enGB } from 'date-fns/locale'
          >
            <DateRangePicker
              className={classes.searchDatePicker}
              slotProps={{
                field: {
                  clearable: true,
                },
                textField: {
                  variant: "outlined"
                }
              }}
              value={dateRange}
              onChange={(newValue) => {
                setDateRange(newValue);
              }}
              format="dd/MM/yyyy"
            />
          </LocalizationProvider>
          )}
          {!hideShowPerPage && (
            <Box className={classes.pageSizeDropdown}>
              <Typography className={classes.dropDownLabel}>Show:</Typography>
              <Select
                select
                value={pagination.pageSize}
                onChange={handlePageSizeChange}
                className={classes.perPageDropdown}
                IconComponent={ExpandMore}
              >
                {[10, 20, 40, 50, 100].map((value) => (
                  <MenuItem key={value} value={value}>
                    {value}
                  </MenuItem>
                ))}
              </Select>
            </Box>
          )}
        </div>
        <MaterialReactTable
          renderBottomToolbar={(props) => (
            <CustomPagination table={props.table} />
          )}
          muiTableBodyCellProps={{
            sx: (theme) => ({
              opacity: "1",
              margin: theme.spacing(1),
              fontWeight: 500,
              fontSize: "16px",
              fontStretch: "normal",
              fontStyle: "normal",
              letterSpacing: "normal",
              fontFamily: theme.fontFamily.medium,
              color: theme.palette.grey[22],
              textAlign: "left",
            }),
          }}
          muiTopToolbarProps={{
            sx: (theme) => ({
              borderRadius: theme.shape.borderRadius,
              "& div": {
                "& div": {
                  "& .MuiIconButton-sizeMedium": {
                    display: "none",
                  },
                },
              },
              backgroundColor: theme.palette.common.white,
            }),
          }}
          renderTopToolbar={false}
          muiTableHeadCellProps={{
            className: classes?.muiTableHeadCell,
            sx: {
              // Fix for extra space in header cells
              padding: "16px 8px",
              whiteSpace: "nowrap",
              justifyContent: "flex-start",
              "& .MuiTableSortLabel-root": {
                width: "100%",
                justifyContent: "flex-start",
              },
            },
          }}
          enableRowNumbers={enableRowNumbers}
          rowNumberMode={rowNumberMode}
          muiTablePaperProps={{
            elevation: 8,
            sx: (theme) => ({
              borderRadius: theme.shape.borderRadius,
              backgroundColor: theme.palette.common.white,
              boxShadow: "none",
              "& .MuiTableContainer-root": {
                border: "0px solid",
                borderRadius: "16px",
              },
            }),
          }}
          muiTableHeadCellFilterTextFieldProps={{
            variant: "outlined",
          }}
          muiTableBodyProps={{
            sx: (theme) => ({
              borderRadius: theme.shape.borderRadius,
            }),
          }}
          columns={formattedColumns ?? []}
          data={data}
          enableTopToolbar={
            !hideTopToolbar &&
            (options?.showTopBar ||
              tableRef?.current?.getIsSomeRowsSelected() ||
              tableRef?.current?.getIsAllRowsSelected())
          }
          manualPagination={true}
          manualFiltering
          manualSorting
          enableFilterMatchHighlighting={false}
          enableColumnActions={false}
          enableRowSelection={options?.enableRowSelection ?? true}
          muiToolbarAlertBannerProps={
            isError
              ? {
                  color: "error",
                  children: "Error loading data",
                }
              : undefined
          }
          positionToolbarAlertBanner={"none"}
          onColumnFiltersChange={setColumnFilters}
          onGlobalFilterChange={setGlobalFilter}
          onPaginationChange={setPagination}
          onSortingChange={setSorting}
          rowCount={rowCount}
          enableFullScreenToggle={false}
          enableDensityToggle={false}
          enableHiding={false}
          enableSorting={options?.enableSorting ?? true}
          enableColumnFilters={options?.showFilters ?? false}
          enableGlobalFilter={options?.showSearch ?? false}
          enableRowActions={showAction ?? false}
          positionActionsColumn="last"
          muiTableHeadRowProps={{
            className: classes?.tableHeadRow,
          }}
          displayColumnDefOptions={{
            "mrt-row-actions": {
              header: "",
            },
          }}
          muiTableBodyRowProps={({ row }) => ({
            onClick: (event) => {
              if (
                Object.values(event.target)?.[1]
                  ?.className?.split(" ")
                  .includes("MuiBackdrop-root")
              ) {
                return;
              }
              handleRowClick(row?.original);
              if (navigateTo) {
                navigate(`/${navigateTo}/${row?.original?.id}`);
              }
            },
            className: classes?.tableBodyRow,
            sx: getRowStyle(row),
          })}
          muiSelectCheckboxProps={{
            className: classes?.tableCheckbox,
          }}
          muiSelectAllCheckboxProps={{
            className: classes?.tableCheckbox,
          }}
          renderRowActionMenuItems={({ row, closeMenu }) =>
            actions
              ?.filter((action) => !action.render)
              ?.map((action, index) =>
                !(action?.renderAction?.(row) ?? true) ? null : (
                  <MenuItem
                    key={index}
                    className={classes.menuItem}
                    onClick={(event) => {
                      event.stopPropagation();
                      action.onClick && action.onClick(row);
                      closeMenu();
                    }}
                    disabled={
                      action?.isDisabledValue
                        ? action?.isDisabledValue ===
                          row?.original?.[action?.rowKey]
                        : false
                    }
                  >
                    {action?.icon} {action?.text}{" "}
                    {action.textFn && action.textFn(row)}
                  </MenuItem>
                )
              ) ?? []
          }
          renderTopToolbarCustomActions={({ table }) => {
            const handleActive = () => {
              const data = table
                .getSelectedRowModel()
                .flatRows.map((row) => row?.original);
              return handleBulkAction("ACTIVE", data);
            };
            const handleDelete = () => {
              const data = table
                .getSelectedRowModel()
                .flatRows.map((row) => row?.original);
              return handleBulkAction("DELETE", data, table);
            };
            const handleDownload = () => {
              const data = table
                .getSelectedRowModel()
                .flatRows.map((row) => row?.original);
              return handleBulkAction("DOWNLOAD", data);
            };
            return table.getIsSomeRowsSelected() ||
              table.getIsAllRowsSelected() ? (
              <Box
                style={{
                  display: "flex",
                  alignItems: "center",
                  justifyContent: "center",
                }}
              >
                <Tooltip title="Change Status">
                  <Box
                    component="img"
                    // Replace with actual image path or icon component
                    // src={inactive}
                    style={{
                      marginLeft: "5px",
                      cursor: "pointer",
                      marginTop: "8px",
                    }}
                    onClick={handleActive}
                  />
                </Tooltip>
                <Tooltip title="Delete">
                  <Box
                    component="img"
                    // src={deleteIcon}
                    style={{
                      marginLeft: "24px",
                      cursor: "pointer",
                      marginTop: "8px",
                    }}
                    onClick={handleDelete}
                  />
                </Tooltip>
                {showDownloadAction && (
                  <Tooltip title="Download Report">
                    <Box
                      component="img"
                      // src={downloadActivity}
                      style={{
                        marginLeft: "24px",
                        cursor: "pointer",
                        marginTop: "9px",
                        height: "20px",
                      }}
                      onClick={handleDownload}
                    />
                  </Tooltip>
                )}
              </Box>
            ) : (
              <div></div>
            );
          }}
          muiTablePaginationProps={{
            labelRowsPerPage: "Records Per Page",
          }}
          tableInstanceRef={tableRef}
          state={{
            showColumnFilters: true,
            columnFilters,
            globalFilter,
            isLoading,
            pagination,
            showAlertBanner: isError,
            showProgressBars: isRefetching,
            sorting,
          }}
        />
      </>
    );
  })
);
Table.propTypes = {
  getData: PropTypes.func.isRequired,
  columns: PropTypes.any.isRequired,
  options: PropTypes.shape({
    pageSize: PropTypes.number,
    pageIndex: PropTypes.number,
    tableTitle: PropTypes.string,
    showSearch: PropTypes.bool,
    showTopBar: PropTypes.bool,
    showFilters: PropTypes.bool,
    isBold: PropTypes.bool,
  }),
};

const CustomPagination = ({ table }) => {
  const classes = useStyles();

  const totalPage =
    Math.ceil(
      table.options.rowCount / table.options.state.pagination.pageSize
    ) || 1;

  const previousPage = () => {
    table.setPageIndex(
      table.options?.state.pagination.pageIndex > 0
        ? table.options?.state.pagination.pageIndex - 1
        : table.options?.state.pagination.pageIndex
    );
  };

  const nextPage = () => {
    table.setPageIndex(
      table.options?.state.pagination.pageIndex < totalPage
        ? table.options?.state.pagination.pageIndex + 1
        : table.options?.state.pagination.pageIndex
    );
  };

  const setPageIndex = (newIndex) => {
    table.setPageIndex(newIndex);
  };

  const currentPage = table.options.state.pagination.pageIndex + 1;

  return (
    <Box
      sx={{
        display: "flex",
        flexDirection: { xs: "column", md: "row" },
        alignItems: "center",
        padding: 2,
      }}
    >
      <Pagination
        shape="rounded"
        count={totalPage}
        page={currentPage}
        siblingCount={0}
        boundaryCount={3}
        onChange={(event, page) => setPageIndex(page - 1)}
        renderItem={(item) => {
          if (item.type === "previous") {
            return (
              <PaginationItem
                component={() => (
                  <Button
                    className={classes.prevNextBtn}
                    variant="outlined"
                    disabled={currentPage === 1}
                    onClick={() => previousPage()}
                  >
                    <PreviousIcon style={{ marginRight: "6px" }} />
                    Previous
                  </Button>
                )}
              />
            );
          } else if (item.type === "next") {
            return (
              <PaginationItem
                component={() => (
                  <Button
                    className={classes.prevNextBtn}
                    variant="outlined"
                    disabled={currentPage === totalPage}
                    onClick={() => nextPage()}
                  >
                    Next
                    <NextIcon style={{ marginLeft: "6px" }} />
                  </Button>
                )}
                disabled={currentPage === totalPage}
              />
            );
          } else {
            return <PaginationItem {...item} />;
          }
        }}
        sx={{
          display: "flex",
          justifyContent: "center",
          flex: "1",
          "& .MuiPagination-ul": {
            width: "100%",
            display: "flex",
            cursor: "pointer",
          },
          "& .MuiPagination-ul > :first-child": {
            marginRight: "auto",
          },
          " & .MuiPagination-ul > :last-child": {
            marginLeft: "auto",
          },
        }}
      />
    </Box>
  );
};

export default Table;
