/* ---------------------------------- @mui ---------------------------------- */
import {
  Paper,
  Table as TableContent,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  TextField,
  Button,
  TableSortLabel,
  Box,
  Grid,
  FormControl,
  InputLabel,
  Select,
  MenuItem,
  InputAdornment,
  Typography,
} from '@mui/material';
import { visuallyHidden } from '@mui/utils';
/* ---------------------------------- react --------------------------------- */
import { Fragment } from 'react';
/* -------------------------------- component ------------------------------- */
import BaseTablePagination from './BaseTablePagination';
/* ---------------------------------- utils --------------------------------- */
import { Download, Search as SearchIcon } from '@mui/icons-material';
/* ---------------------------------- types --------------------------------- */
import { DivisionDataProps, StatusDataProps, TableListProps } from '../@types/table';

export default function Table<T>({
  headCells,
  rows,
  paginations,
  orders,
  loadings,
  params,
  filters,
  filterStatus,
  filterStartDate,
  filterEndDate,
  searchs,
  exportReport,
}: TableListProps<T>) {
  /* ------------------------------- handle sort ------------------------------ */
  const handleRequestSort = async (event: React.MouseEvent<unknown>, property: string) => {
    const isAsc = orders?.orderBy === property && orders?.order === 'asc';

    orders?.setOrder(isAsc ? 'desc' : 'asc');
    orders?.setOrderBy(property);
    const parameters = Object.fromEntries([
      ...(params?.searchParams.entries() as IterableIterator<[string, string]>),
      ['order', isAsc ? 'desc' : 'asc'],
      ['orderBy', property],
    ]);
    params?.setAppliedParams(parameters);
  };
  /* -------------------------------------------------------------------------- */

  /* -------------------------- enchanced table head -------------------------- */
  const EnhancedTableHead = () => {
    const createSortHandler = (property: string) => (event: React.MouseEvent<unknown>) => {
      handleRequestSort(event, property);
    };

    return (
      <TableHead>
        <TableRow>
          {headCells &&
            headCells.map((headCell, index) => (
              <TableCell
                key={index}
                sortDirection={orders?.orderBy === headCell.id ? orders.order : false}
                // @ts-ignore
                align={headCell.align}
                sx={{ padding: 2 }}
                width={headCell.width ? headCell.width : 'auto'}
              >
                {headCell.isSort ? (
                  <TableSortLabel
                    active={orders?.orderBy === headCell.id}
                    direction={orders?.orderBy === headCell.id ? orders.order : 'asc'}
                    onClick={createSortHandler(headCell.id)}
                  >
                    {headCell.label}
                    {orders?.orderBy === headCell.id ? (
                      <Box component="span" sx={visuallyHidden}>
                        {orders.order === 'desc' ? 'sorted descending' : 'sorted ascending'}
                      </Box>
                    ) : null}
                  </TableSortLabel>
                ) : (
                  headCell.label
                )}
              </TableCell>
            ))}
        </TableRow>
      </TableHead>
    );
  };
  /* -------------------------------------------------------------------------- */

  /* ------------------------ button change pagination ------------------------ */
  const onPageChangeHandle = async (
    event: React.MouseEvent<HTMLButtonElement> | null,
    newPage: number
  ) => {
    const parameters = Object.fromEntries([
      ...(params?.searchParams.entries() as IterableIterator<[string, string]>),
      ['page', newPage + 1],
      ['per_page', paginations?.rowsPerPage],
    ]);
    paginations?.setPage(newPage);
    await new Promise((resolve) => setTimeout(resolve, 500));
    params?.setAppliedParams(parameters);
  };
  /* -------------------------------------------------------------------------- */

  /* --------------------------- row page per limit --------------------------- */
  const onRowsPerPageChangeHandle = async (event: React.ChangeEvent<HTMLInputElement>) => {
    params?.searchParams.delete('page');
    const parameters = Object.fromEntries([
      ...(params?.searchParams.entries() as IterableIterator<[string, string]>),
      ['per_page', parseInt(event.target.value, 10)],
    ]);

    paginations?.setPage(0);
    paginations?.setRowsPerPage(parseInt(event.target.value, 10));
    await new Promise((resolve) => setTimeout(resolve, 500));
    params?.setAppliedParams(parameters);
  };
  /* -------------------------------------------------------------------------- */

  return (
    // <Card>
    <Grid container>
      {/* Field 1 */}
      <Grid item xs={12} paddingX="24px" paddingY="20px">
        <Grid container spacing={2}>
          {filters && filters.useFilter ? (
            <Fragment>
              <Grid item xs={12} lg={3} xl={2}>
                <FormControl fullWidth>
                  <InputLabel id="simple-division-select-lable">Division</InputLabel>
                  <Select
                    labelId="simple-division-select-lable"
                    id="division-select-lable"
                    value={filters.config.divisionValue}
                    label="Division"
                    onChange={filters.config.handleDivisionChange}
                  >
                    <MenuItem value="all">All</MenuItem>
                    {filters.config.divisionData.map((row: DivisionDataProps, index) => (
                      <MenuItem key={index} value={row.id}>
                        {row.name}
                      </MenuItem>
                    ))}
                  </Select>
                </FormControl>
              </Grid>
              <Grid item xs={12} lg={9} xl={10}>
                <form onSubmit={searchs?.handleSearchSubmit}>
                  <TextField
                    id="search-input"
                    label="Search"
                    variant="outlined"
                    onChange={(event) => searchs?.setSearchText(event.target.value)}
                    value={searchs?.searchText}
                    fullWidth
                  />
                </form>
              </Grid>
            </Fragment>
          ) : null}

          {searchs && searchs.useSearchs ? (
            <Fragment>
              {filterStatus && filterStatus.useFilter ? (
                <Grid item xs={12} lg={4} xl={4}>
                  <form onSubmit={searchs.handleSearchSubmit}>
                    <TextField
                      id="search-input"
                      variant="outlined"
                      onChange={(event) => searchs.setSearchText(event.target.value)}
                      value={searchs.searchText}
                      fullWidth
                      InputProps={{
                        startAdornment: (
                          <InputAdornment position="start">
                            <SearchIcon />
                          </InputAdornment>
                        ),
                      }}
                      placeholder="Search Name or Member ID... "
                    />
                  </form>
                </Grid>
              ) : exportReport && exportReport.useExport && filterStatus === undefined ? (
                <Grid item xs={12} lg={10} xl={10}>
                  <form onSubmit={searchs.handleSearchSubmit}>
                    <TextField
                      id="search-input"
                      variant="outlined"
                      onChange={(event) => searchs.setSearchText(event.target.value)}
                      value={searchs.searchText}
                      fullWidth
                      InputProps={{
                        startAdornment: (
                          <InputAdornment position="start">
                            <SearchIcon />
                          </InputAdornment>
                        ),
                      }}
                      placeholder="Search Name or Member ID... "
                    />
                  </form>
                </Grid>
              ) : (
                <Grid item xs={12} lg={searchs.fullWidth ? 12 : 6} xl={searchs.fullWidth ? 12 : 6}>
                  <form onSubmit={searchs.handleSearchSubmit}>
                    <TextField
                      id="search-input"
                      variant="outlined"
                      onChange={(event) => searchs.setSearchText(event.target.value)}
                      value={searchs.searchText}
                      fullWidth
                      InputProps={{
                        startAdornment: (
                          <InputAdornment position="start">
                            <SearchIcon />
                          </InputAdornment>
                        ),
                      }}
                      placeholder="Search Name or Member ID... "
                    />
                  </form>
                </Grid>
              )}
            </Fragment>
          ) : null}

          {/* Start date */}
          {filterStartDate && filterStartDate.useFilter ? (
            <Grid item xs={12} lg={2} xl={2}>
              <form onChange={filterStartDate.handleStartDateChange}>
                <TextField
                  id="date-input"
                  type="date"
                  variant="outlined"
                  value={filterStartDate.startDate}
                  onChange={(event) => filterStartDate.setStartDate(event.target.value)}
                  fullWidth
                  label="Start Date"
                  InputLabelProps={{
                    shrink: true,
                  }}
                />
              </form>
            </Grid>
          ) : null}

          {/* End Date */}

          {filterEndDate && filterEndDate.useFilter ? (
            <Grid item xs={12} lg={2} xl={2}>
              <form onChange={filterEndDate.handleEndDateChange}>
                <TextField
                  id="date-input"
                  type="date"
                  variant="outlined"
                  value={filterEndDate.endDate}
                  onChange={(event) => filterEndDate.setEndDate(event.target.value)}
                  fullWidth
                  label="End Date"
                  InputLabelProps={{
                    shrink: true,
                  }}
                />
              </form>
            </Grid>
          ) : null}

          {/* Filter status */}
          {filterStatus && filterStatus.useFilter ? (
            <Grid item xs={12} lg={2} xl={2}>
              <FormControl fullWidth>
                <InputLabel id="simple-status-select-lable">Status</InputLabel>
                <Select
                  labelId="simple-status-select-lable"
                  id="status-select-lable"
                  value={filterStatus.config.statusValue}
                  label="Status"
                  onChange={filterStatus.config.handleStatusChange}
                >
                  <MenuItem value="all">All</MenuItem>
                  {filterStatus.config.statusData.map((row: StatusDataProps, index) => (
                    <MenuItem key={index} value={row.id}>
                      {row.name}
                    </MenuItem>
                  ))}
                </Select>
              </FormControl>
            </Grid>
          ) : null}

          {/* Export Report */}
          {exportReport && exportReport.useExport ? (
            <Grid item xs={12} lg={2} xl={2}>
              <FormControl fullWidth>
                <Button
                  variant="contained"
                  sx={{ p: 2 }}
                  onClick={() => exportReport.handleExportReport()}
                >
                  <Download />
                  <Typography variant="inherit" sx={{ marginLeft: 1 }}>
                    Export
                  </Typography>
                </Button>
              </FormControl>
            </Grid>
          ) : null}
        </Grid>
      </Grid>
      {/* End Field 1 */}
      {/* Field 2 */}
      <Grid item xs={12}>
        {/* Table */}
        <TableContainer component={Paper}>
          <TableContent aria-label="collapsible table" size="small">
            {/* Table Header */}
            <EnhancedTableHead />
            {/* End Table Header */}
            {/* Table Body */}
            <TableBody>
              {loadings.isLoading && rows && rows.length >= 1 ? (
                <TableRow>
                  <TableCell colSpan={headCells?.length} align="center">
                    Loading . . .
                  </TableCell>
                </TableRow>
              ) : rows && rows.length >= 1 ? (
                rows.map((row, rowIndex) => (
                  <TableRow key={rowIndex}>
                    {headCells &&
                      //@ts-ignore
                      headCells.map((head, headIndex) => (
                        //@ts-ignore
                        <TableCell align={head.align} key={headIndex}>
                          {row[head.id]}
                        </TableCell>
                      ))}
                  </TableRow>
                ))
              ) : loadings.isLoading === false && rows && rows.length === 0 ? (
                <TableRow>
                  <TableCell colSpan={6} align="center">
                    No Data Found
                  </TableCell>
                </TableRow>
              ) : (
                <TableRow>
                  <TableCell colSpan={6} align="center">
                    Loading . . .
                  </TableCell>
                </TableRow>
              )}
            </TableBody>
            {/* End Table Body */}
          </TableContent>
        </TableContainer>
        {/* End Table */}

        {/* Pagination */}
        {paginations && (
          <BaseTablePagination
            count={paginations.paginationTable.total}
            onPageChange={onPageChangeHandle}
            page={paginations.page}
            rowsPerPage={paginations.rowsPerPage}
            onRowsPerPageChange={onRowsPerPageChangeHandle}
          />
        )}
        {/* End Pagination */}
      </Grid>
      {/* End Field 2 */}
    </Grid>
    // </Card>
  );
}
