"use client";

import React, { ChangeEvent, Dispatch, MouseEvent, SetStateAction, useCallback, useState } from "react";
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";

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;
}

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)[]>>;
}

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";
}

// Icon Component Functions
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,
}
function SearchResults<T extends ResultWithId>({
  items,
  columns,
  noWrapper,
  pagingController,
  setPagingController,
  isAutoPaging = true,
  totalCount,
  checkboxIds = [],
  setCheckboxIds = undefined,
}: Props<T>) {
  const [page, setPage] = React.useState(0);
  const [rowsPerPage, setRowsPerPage] = React.useState(10);

  /// this
  const handleChangePage: TablePaginationProps["onPageChange"] = (
    _event,
    newPage
  ) => {
    console.log(_event);
    setPage(newPage);
    if (setPagingController) {
      setPagingController({
        ...pagingController,
        pageNum: newPage + 1,
      });
    }
  };

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

  // checkbox
  const handleRowClick = useCallback((event: MouseEvent<unknown>, item: T, columns: Column<T>[]) => {
    // check is disabled or not
    var disabled = false
    columns.forEach((col) => {
      if (isCheckboxColumn(col) && col.disabled) {
        disabled = col.disabled(item)
        if (disabled) {
          return;
        }
      }
    })

    if (disabled) {
      return;
    }

    // set id
    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])

  const table = (
    <>
      <TableContainer sx={{ maxHeight: 440 }}>
        <Table stickyHeader>
          <TableHead>
            <TableRow>
              {columns.map((column, idx) => (
                <TableCell
                  align={column.headerAlign}
                  sx={column.sx}
                  key={`${column.name.toString()}${idx}`}
                >
                  {column.label}
                </TableCell>
              ))}
            </TableRow>
          </TableHead>
          <TableBody>
            {isAutoPaging
              ? items
                .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                .map((item) => {
                  return (
                    <TableRow
                      hover
                      tabIndex={-1}
                      key={item.id}
                      onClick={setCheckboxIds? (event) => handleRowClick(event, item, columns) : undefined}
                      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>
                  );
                })
              : items.map((item) => {
                return (
                  <TableRow hover tabIndex={-1} key={item.id}>
                    {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>
                );
              })}
          </TableBody>
        </Table>
      </TableContainer>
      <TablePagination
        rowsPerPageOptions={[10, 25, 100]}
        component="div"
        count={!totalCount || totalCount == 0
          ? items.length
          : totalCount
        }
        // count={
        //   !pagingController || pagingController.totalCount == 0
        //     ? items.length
        //     : pagingController.totalCount
        // }
        rowsPerPage={rowsPerPage}
        page={page}
        onPageChange={handleChangePage}
        onRowsPerPageChange={handleChangeRowsPerPage}
      />
    </>
  );

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

// Table cells
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 SearchResults;
