"use client";

import React, {
  ChangeEvent,
  Dispatch,
  MouseEvent,
  SetStateAction,
  useCallback,
  useMemo,
  useState,
} from "react";
import { useTranslation } from "react-i18next";
import Paper from "@mui/material/Paper";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell, { TableCellProps } from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TablePagination, {
  TablePaginationProps,
} from "@mui/material/TablePagination";
import TableRow from "@mui/material/TableRow";
import IconButton, { IconButtonOwnProps } from "@mui/material/IconButton";
import {
  ButtonOwnProps,
  Checkbox,
  Icon,
  IconOwnProps,
  SxProps,
  Theme,
} from "@mui/material";
import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline";
import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil";
import { filter, remove, uniq } from "lodash";

export interface ResultWithId {
  id: string | number;
}

type ColumnType = "icon" | "decimal" | "integer" | "checkbox";

interface BaseColumn<T extends ResultWithId> {
  name: keyof T;
  label: string;
  align?: TableCellProps["align"];
  headerAlign?: TableCellProps["align"];
  sx?: SxProps<Theme> | undefined;
  style?: Partial<HTMLElement["style"]> & { [propName: string]: string };
  type?: ColumnType;
  renderCell?: (params: T) => React.ReactNode;
  renderHeader?: () => React.ReactNode;
}

interface IconColumn<T extends ResultWithId> extends BaseColumn<T> {
  name: keyof T;
  type: "icon";
  icon?: React.ReactNode;
  icons?: { [columnValue in keyof T]: React.ReactNode };
  color?: IconOwnProps["color"];
  colors?: { [columnValue in keyof T]: IconOwnProps["color"] };
}

interface DecimalColumn<T extends ResultWithId> extends BaseColumn<T> {
  type: "decimal";
}

interface IntegerColumn<T extends ResultWithId> extends BaseColumn<T> {
  type: "integer";
}

interface CheckboxColumn<T extends ResultWithId> extends BaseColumn<T> {
  type: "checkbox";
  disabled?: (params: T) => boolean;
  // checkboxIds: readonly (string | number)[],
  // setCheckboxIds: (ids: readonly (string | number)[]) => void
}

interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> {
  onClick: (item: T) => void;
  buttonIcon: React.ReactNode;
  buttonIcons: { [columnValue in keyof T]: React.ReactNode };
  buttonColor?: IconButtonOwnProps["color"];
}

export type Column<T extends ResultWithId> =
  | BaseColumn<T>
  | IconColumn<T>
  | DecimalColumn<T>
  | CheckboxColumn<T>
  | ColumnWithAction<T>;

interface Props<T extends ResultWithId> {
  totalCount?: number;
  items: T[];
  columns: Column<T>[];
  noWrapper?: boolean;
  setPagingController?: Dispatch<
    SetStateAction<{
      pageNum: number;
      pageSize: number;
    }>
  >;
  pagingController?: { pageNum: number; pageSize: number };
  isAutoPaging?: boolean;
  checkboxIds?: (string | number)[];
  setCheckboxIds?: Dispatch<SetStateAction<(string | number)[]>>;
  onRowClick?: (item: T) => void;
  renderExpandedRow?: (item: T) => React.ReactNode;
  hideHeader?: boolean;
}

function isActionColumn<T extends ResultWithId>(
  column: Column<T>,
): column is ColumnWithAction<T> {
  return Boolean((column as ColumnWithAction<T>).onClick);
}

function isIconColumn<T extends ResultWithId>(
  column: Column<T>,
): column is IconColumn<T> {
  return column.type === "icon";
}

function isDecimalColumn<T extends ResultWithId>(
  column: Column<T>,
): column is DecimalColumn<T> {
  return column.type === "decimal";
}

function isIntegerColumn<T extends ResultWithId>(
  column: Column<T>,
): column is IntegerColumn<T> {
  return column.type === "integer";
}

function isCheckboxColumn<T extends ResultWithId>(
  column: Column<T>,
): column is CheckboxColumn<T> {
  return column.type === "checkbox";
}

function convertObjectKeysToLowercase<T extends object>(
  obj: T,
): object | undefined {
  return obj
    ? Object.fromEntries(
      Object.entries(obj).map(([key, value]) => [key.toLowerCase(), value]),
    )
    : undefined;
}

function handleIconColors<T extends ResultWithId>(
  column: IconColumn<T>,
  value: T[keyof T],
): IconOwnProps["color"] {
  const colors = convertObjectKeysToLowercase(column.colors ?? {});
  const valueKey = String(value).toLowerCase() as keyof typeof colors;

  if (colors && valueKey in colors) {
    return colors[valueKey];
  }

  return column.color ?? "primary";
}

function handleIconIcons<T extends ResultWithId>(
  column: IconColumn<T>,
  value: T[keyof T],
): React.ReactNode {
  const icons = convertObjectKeysToLowercase(column.icons ?? {});
  const valueKey = String(value).toLowerCase() as keyof typeof icons;

  if (icons && valueKey in icons) {
    return icons[valueKey];
  }

  return column.icon ?? <CheckCircleOutlineIcon fontSize="small" />;
}
export const defaultPagingController: { pageNum: number; pageSize: number } = {
  pageNum: 1,
  pageSize: 10,
};

export type defaultSetPagingController = Dispatch<
  SetStateAction<{
    pageNum: number;
    pageSize: number;
  }>
>

function EquipmentSearchResults<T extends ResultWithId>({
  items,
  columns,
  noWrapper,
  pagingController,
  setPagingController,
  isAutoPaging = true,
  totalCount,
  checkboxIds = [],
  setCheckboxIds = undefined,
  onRowClick = undefined,
  renderExpandedRow = undefined,
  hideHeader = false,
}: Props<T>) {
  const { t } = useTranslation("common"); 
  const [page, setPage] = React.useState(0);
  const [rowsPerPage, setRowsPerPage] = React.useState(10);
  
  const handleChangePage: TablePaginationProps["onPageChange"] = (
    _event,
    newPage,
  ) => {
    console.log(_event);
    setPage(newPage);
    if (setPagingController) {
      setPagingController({
        ...(pagingController ?? defaultPagingController),
        pageNum: newPage + 1,
      });
    }
  };

  const handleChangeRowsPerPage: TablePaginationProps["onRowsPerPageChange"] = (
    event,
  ) => {
    console.log(event);
    const newSize = +event.target.value;
    setRowsPerPage(newSize);
    setPage(0);
    if (setPagingController) {
      setPagingController({
        ...(pagingController ?? defaultPagingController),
        pageNum: 1,
        pageSize: newSize,
      });
    }
  };

  const currItems = useMemo(() => {
    return items.length > 10 ? items
    .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
    .map((i) => i.id)
    : items.map((i) => i.id)
  }, [items, page, rowsPerPage])

  const currItemsWithChecked = useMemo(() => {
    return filter(checkboxIds, function (c) { 
      return currItems.includes(c);
    })
  }, [checkboxIds, items, page, rowsPerPage])

  const handleRowClick = useCallback(
    (event: MouseEvent<unknown>, item: T, columns: Column<T>[]) => {
      let disabled = false;
      columns.forEach((col) => {
        if (isCheckboxColumn(col) && col.disabled) {
          disabled = col.disabled(item);
          if (disabled) {
            return;
          }
        }
      });

      if (disabled) {
        return;
      }

      const id = item.id;
      if (setCheckboxIds) {
        const selectedIndex = checkboxIds.indexOf(id);
        let newSelected: (string | number)[] = [];

        if (selectedIndex === -1) {
          newSelected = newSelected.concat(checkboxIds, id);
        } else if (selectedIndex === 0) {
          newSelected = newSelected.concat(checkboxIds.slice(1));
        } else if (selectedIndex === checkboxIds.length - 1) {
          newSelected = newSelected.concat(checkboxIds.slice(0, -1));
        } else if (selectedIndex > 0) {
          newSelected = newSelected.concat(
            checkboxIds.slice(0, selectedIndex),
            checkboxIds.slice(selectedIndex + 1),
          );
        }
        setCheckboxIds(newSelected);
      }
    },
    [checkboxIds, setCheckboxIds],
  );

  const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>) => {
    if (setCheckboxIds) {
      const pageItemId = currItems

      if (event.target.checked) {
        setCheckboxIds((prev) => uniq([...prev, ...pageItemId]))
      } else {
        setCheckboxIds((prev) => filter(prev, function (p) { return !pageItemId.includes(p); }))
      }
    }
  }

  const table = (
    <>
      <TableContainer sx={{ maxHeight: 440 }}>
        <Table stickyHeader={!hideHeader}>
          {!hideHeader && (
            <TableHead>
              <TableRow>
                {columns.map((column, idx) => (
                  isCheckboxColumn(column) ?
                    <TableCell
                      align={column.headerAlign}
                      sx={column.sx}
                      key={`${column.name.toString()}${idx}`}
                    >
                      <Checkbox
                        color="primary"
                        indeterminate={currItemsWithChecked.length > 0 && currItemsWithChecked.length < currItems.length}
                        checked={currItems.length > 0 && currItemsWithChecked.length >= currItems.length}
                        onChange={handleSelectAllClick}
                      />
                    </TableCell>
                    : <TableCell
                      align={column.headerAlign}
                      sx={column.sx}
                      key={`${column.name.toString()}${idx}`}
                    >
                      {column.renderHeader ? (
                        column.renderHeader()
                      ) : (
                        column.label.split('\n').map((line, index) => (
                          <div key={index}>{line}</div> 
                        ))
                      )}
                    </TableCell>
                ))}
              </TableRow>
            </TableHead>
          )}
          <TableBody>
            {isAutoPaging
              ? items
                .slice((pagingController?.pageNum ? pagingController?.pageNum - 1 :page) * (pagingController?.pageSize ?? rowsPerPage), 
                (pagingController?.pageNum ? pagingController?.pageNum - 1 :page) * (pagingController?.pageSize ?? rowsPerPage) + (pagingController?.pageSize ?? rowsPerPage))
                .map((item) => {
                  return (
                    <React.Fragment key={item.id}>
                      <TableRow
                        hover
                        tabIndex={-1}
                        onClick={(event) => {
                          setCheckboxIds
                            ? handleRowClick(event, item, columns)
                            : undefined

                          if (onRowClick) {
                            onRowClick(item)
                          }
                        }
                        }
                        role={setCheckboxIds ? "checkbox" : undefined}
                      >
                        {columns.map((column, idx) => {
                          const columnName = column.name;

                          return (
                            <TabelCells
                              key={`${columnName.toString()}-${idx}`}
                              column={column}
                              columnName={columnName}
                              idx={idx}
                              item={item}
                              checkboxIds={checkboxIds}
                            />
                          );
                        })}
                      </TableRow>
                      {renderExpandedRow && renderExpandedRow(item)}
                    </React.Fragment>
                  );
                })
              : items.map((item) => {
                return (
                  <React.Fragment key={item.id}>
                    <TableRow hover tabIndex={-1}
                      onClick={(event) => {
                        setCheckboxIds
                          ? handleRowClick(event, item, columns)
                          : undefined

                        if (onRowClick) {
                          onRowClick(item)
                        }
                      }
                      }
                      role={setCheckboxIds ? "checkbox" : undefined}
                    >
                      {columns.map((column, idx) => {
                        const columnName = column.name;

                        return (
                          <TabelCells
                            key={`${columnName.toString()}-${idx}`}
                            column={column}
                            columnName={columnName}
                            idx={idx}
                            item={item}
                            checkboxIds={checkboxIds}
                          />
                        );
                      })}
                    </TableRow>
                    {renderExpandedRow && renderExpandedRow(item)}
                  </React.Fragment>
                );
              })}
          </TableBody>
        </Table>
      </TableContainer>
      <TablePagination
  rowsPerPageOptions={[10, 25, 100]}
  component="div"
  count={!totalCount || totalCount == 0 ? items.length : totalCount}
  rowsPerPage={pagingController?.pageSize ? pagingController?.pageSize : rowsPerPage}
  page={pagingController?.pageNum ? pagingController?.pageNum - 1 : page}
  onPageChange={handleChangePage}
  onRowsPerPageChange={handleChangeRowsPerPage}
  labelRowsPerPage={t("Rows per page")}
  labelDisplayedRows={({ from, to, count }) => 
    `${from}-${to} of ${count !== -1 ? count : `more than ${to}`}`
  }
/>
    </>
  );

  return noWrapper ? table : <Paper sx={{ overflow: "hidden" }}>{table}</Paper>;
}

interface TableCellsProps<T extends ResultWithId> {
  column: Column<T>;
  columnName: keyof T;
  idx: number;
  item: T;
  checkboxIds: (string | number)[];
}

function TabelCells<T extends ResultWithId>({
  column,
  columnName,
  idx,
  item,
  checkboxIds = [],
}: TableCellsProps<T>) {
  const isItemSelected = checkboxIds.includes(item.id);

  return (
    <TableCell
      align={column.align}
      sx={column.sx}
      key={`${columnName.toString()}-${idx}`}
    >
      {isActionColumn(column) ? (
        <IconButton
          color={column.buttonColor ?? "primary"}
          onClick={() => column.onClick(item)}
        >
          {column.buttonIcon}
        </IconButton>
      ) : isIconColumn(column) ? (
        <Icon color={handleIconColors(column, item[columnName])}>
          {handleIconIcons(column, item[columnName])}
        </Icon>
      ) : isDecimalColumn(column) ? (
        <>{decimalFormatter.format(Number(item[columnName]))}</>
      ) : isIntegerColumn(column) ? (
        <>{integerFormatter.format(Number(item[columnName]))}</>
      ) : isCheckboxColumn(column) ? (
        <Checkbox
          disabled={column.disabled ? column.disabled(item) : undefined}
          checked={isItemSelected}
        />
      ) : column.renderCell ? (
        column.renderCell(item)
      ) : (
        <>{item[columnName] as string}</>
      )}
    </TableCell>
  );
}

export default EquipmentSearchResults;