"use client";

import React, { useCallback, useEffect, useState } from "react";
import Paper from "@mui/material/Paper";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell 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, IconButtonPropsColorOverrides } from "@mui/material/IconButton";
import { t } from "i18next";
import { useTranslation } from "react-i18next";
import { convertDateArrayToString, moneyFormatter } from "@/app/utils/formatUtil";
import DoneIcon from '@mui/icons-material/Done';
import CloseIcon from '@mui/icons-material/Close';
import { Button, Link, LinkOwnProps } from "@mui/material";
import { orderBy, sortBy } from "lodash";
import ArrowUp from '@mui/icons-material/KeyboardArrowUp';
import ArrowDown from '@mui/icons-material/KeyboardArrowDown';

export interface ResultWithId {
  id: string | number;
}

interface BaseColumn<T extends ResultWithId> {
  name: keyof T;
  label: string;
  needTranslation?: boolean;
  type?: string;
  isHidden?: boolean;
  sortable?: boolean; // NEW
  sortFn?: (a: T, b: T) => number; // NEW (optional custom sort)
}

interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> {
  onClick: (item: T) => void;
  buttonIcon: React.ReactNode;
  color?: IconButtonOwnProps["color"];
  disabled?: boolean;
  disabledRows?: { [columnValue in keyof T]: string[] }; // Filter the row which is going to be disabled
}

interface LinkColumn<T extends ResultWithId> extends BaseColumn<T> {
  // href: string;
  onClick: (item: T) => void;
  underline: LinkOwnProps["underline"];
  underlines: { [columnValue in keyof T]: LinkOwnProps["underline"] };
  color: LinkOwnProps["color"];
  colors: { [columnValue in keyof T]: LinkOwnProps["color"] };
}

export type Column<T extends ResultWithId> =
  | BaseColumn<T>
  | ColumnWithAction<T>
  | LinkColumn<T>
;

interface Props<T extends ResultWithId> {
  items: T[];
  columns: Column<T>[];
  noWrapper?: boolean;
  autoRedirectToFirstPage?: boolean;
}

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

function isLinkColumn<T extends ResultWithId>(
  column: Column<T>,
): column is LinkColumn<T> {
  return column.type === "link";
}

function SearchResults<T extends ResultWithId>({
  items,
  columns,
  noWrapper,
  autoRedirectToFirstPage,
}: Props<T>) {
  const [page, setPage] = React.useState(0);
  const [rowsPerPage, setRowsPerPage] = React.useState(10);
  const { t } = useTranslation()

  // When filtering the seraching critera, update the page to 0
  // Please removce when the search Result has error
  useEffect(() => {
    if (autoRedirectToFirstPage === true) setPage(0);
  }, [items]);

  const handleChangePage: TablePaginationProps["onPageChange"] = (
    _event,
    newPage,
  ) => {
    setPage(newPage);
  };

  const handleChangeRowsPerPage: TablePaginationProps["onRowsPerPageChange"] = (
    event,
  ) => {
    setRowsPerPage(+event.target.value);
    setPage(0);
  };

  const disabledRows = <T extends ResultWithId> (
    column: ColumnWithAction<T>,
    item: T
  ): Boolean => {
    if (column.disabledRows) {
      for (const [key, value] of Object.entries(column.disabledRows)) {
        if (value
          .map(v => v.toLowerCase())
          .includes(String(item[key as keyof T]).toLowerCase())
        ) return true;
      }
    }

    return false;
  };

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

  // Link Component Functions
  function handleLinkColors<T extends ResultWithId>(
    column: LinkColumn<T>,
    value: T[keyof T],
  ): LinkOwnProps["color"] {
    const colors = convertObjectKeysToLowercase(column.colors);
    console.log(colors)
    const valueKey = String(value).toLowerCase() as keyof typeof colors;

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

    return column.color ?? "primary";
  };

  function handleLinkUnderlines<T extends ResultWithId>(
    column: LinkColumn<T>,
    value: T[keyof T],
  ): LinkOwnProps["underline"] {
    const underlines = convertObjectKeysToLowercase(column.underlines);
    console.log(underlines)
    const valueKey = String(value).toLowerCase() as keyof typeof underlines;

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

    return column.underline ?? "always";
  };

  const [orderByCol, setOrderByCol] = useState<keyof T | null>(null);
  const [order, setOrder] = useState<'asc' | 'desc'>('asc');

  const handleSort = (col: Column<T>) => {
    if (!('sortable' in col) || !col.sortable) return;
  
    if (orderByCol === col.name) {
      setOrder(prev => (prev === 'asc' ? 'desc' : 'asc'));
    } else {
      setOrderByCol(col.name);
      setOrder('asc');
    }
  };

  const sortedItems = React.useMemo(() => {
    if (!orderByCol) return items;
    const column = columns.find(col => col.name === orderByCol);
    if (!column) return items;
  
    let sorted = [...items];
    if (column.sortFn) {
      sorted.sort((a, b) =>
        order === 'asc' ? column.sortFn!(a, b) : column.sortFn!(b, a)
      );
    } else {
      sorted.sort((a, b) => {
        const aValue = a[orderByCol];
        const bValue = b[orderByCol];
        if (aValue == null) return 1;
        if (bValue == null) return -1;
        if (aValue < bValue) return order === 'asc' ? -1 : 1;
        if (aValue > bValue) return order === 'asc' ? 1 : -1;
        return 0;
      });
    }
    return sorted;
  }, [items, orderByCol, order, columns]);

  // type OrderProps = Record<keyof T, Boolean>
  // const [sortedItems, setSortedItems] = useState(items)
  // const [orderProps, setOrderProps] = useState<OrderProps>(() => {
  //   if (items.length === 0) {
  //     return {} as OrderProps
  //   }
  //   return Object.keys(sortedItems[0]).reduce((acc, key) => {
  //     if (key === "deleted" || key === "id") return acc
  //     acc[key as keyof T] = false;
  //     return acc;
  //   }, {} as OrderProps);
  // });
  // const changeOrder = useCallback((key: keyof T) => {
  //   // preserve all column sorting
  //   // setOrderProps( 
  //   //   (prev) => ({
  //   //     [...prev]: false,
  //   //     [key]: !prev[key]
  //   //   })
  //   // )
  //   // only sort 1 column
  //   setOrderProps(
  //     (prev) => {
  //       const newOrderProps = Object.keys(prev).reduce((acc, currKey) => {
  //         acc[currKey as keyof T] = currKey === key ? !prev[currKey as keyof T] : false;
  //         return acc;
  //       }, {} as OrderProps);
  //       return newOrderProps;
  //     }
  //   )
  // }, [])
  // const sortingItems = useCallback(
  //   (key: keyof T) => {
  //     // true === asc
  //     // false === desc
  //     console.log(orderProps)
  //     if (orderProps[key]) {
  //      return orderBy(sortedItems, key, 'asc')
  //     } else {
  //       return orderBy(sortedItems, key, 'desc')
  //     }
  //   }
  //   , [sortedItems, orderProps]
  // )
  const table = (
    <>
      <TableContainer sx={{ maxHeight: 440 }}>
        <Table stickyHeader>
          <TableHead>
            <TableRow>
              {columns.filter(item => item.isHidden !== true).map((column, idx) => (
                <TableCell
                  key={`${column.name.toString()}${idx}`}
                  onClick={() => handleSort(column)}
                  style={{ cursor: column.sortable ? 'pointer' : undefined }}
                >
                  <span style={{ display: "flex", alignItems: "center" }}>
                    {column?.type === "money" ? (
                      <div style={{display: "flex", justifyContent: "flex-end", width: "100%"}}>
                        {column.label}
                      </div>
                    ) : (
                      column.label
                    )}
                    {column.sortable && (
                      orderByCol === column.name ?
                        (order === 'asc' ? <ArrowUp fontSize="small" /> : <ArrowDown fontSize="small" />)
                        : <ArrowUp style={{ opacity: 0.3 }} fontSize="small" />
                    )}
                  </span>
                </TableCell>
              ))}
            </TableRow>
          </TableHead>
          <TableBody>
            {sortedItems
              .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
              .map((item) => {
                return (
                  <TableRow hover tabIndex={-1} key={item.id}>
                    {columns.filter(item => item.isHidden !== true).map((column, idx) => {
                      const columnName = column.name;

                      return (
                        <TableCell key={`${columnName.toString()}-${idx}`}>
                          {isActionColumn(column) && !column?.type ? (
                              <IconButton
                                color={column.color ?? "primary"}
                                onClick={() => column.onClick(item)}
                                disabled={Boolean(column.disabled) || Boolean(disabledRows(column, item))}
                              >
                                {column.buttonIcon}
                              </IconButton>
                            ) :
                            column?.type === "date" ? (
                              <>{convertDateArrayToString(item[columnName] as number[])}</>
                            ) :
                            column?.type === "money" ? (
                              <div style={{display: "flex", justifyContent: "flex-end"}}>{moneyFormatter.format(item[columnName] as number)}</div>
                            ) :
                            column?.type === "checkbox" ? (
                              Boolean(item[columnName]) ?
                                <DoneIcon color="primary" /> : <CloseIcon color="error"/>
                            ) :
                            isLinkColumn(column) ? (
                              <Link
                                onClick={() => column.onClick(item)}
                                underline={handleLinkUnderlines(column, item[columnName])}
                                color={handleLinkColors(column, item[columnName])}
                              >
                                {item[columnName] as string}
                              </Link>
                            ) :
                              (
                                <>{column?.needTranslation ? t(item[columnName] as string) : item[columnName] as string}</>
                              )}
                        </TableCell>
                      );
                    })}
                  </TableRow>
                );
              })}
          </TableBody>
        </Table>
      </TableContainer>
      <TablePagination
        rowsPerPageOptions={[10, 25, 100]}
        component="div"
        count={items.length}
        rowsPerPage={rowsPerPage}
        page={page}
        onPageChange={handleChangePage}
        onRowsPerPageChange={handleChangeRowsPerPage}
      />
    </>
  );

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

export default SearchResults;
