"use client";

import React 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, 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";

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 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>
    | ColumnWithAction<T>;

interface Props<T extends ResultWithId> {
    items: T[],
    columns: Column<T>[],
    noWrapper?: boolean,
    setPagingController?: (value: (((prevState: { pageNum: number; pageSize: number; totalCount: number }) => {
        pageNum: number;
        pageSize: number;
        totalCount: number
    }) | { pageNum: number; pageSize: number; totalCount: number })) => void,
    pagingController: { pageNum: number; pageSize: number; totalCount: number },
    isAutoPaging?: 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";
}

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

function SearchResults<T extends ResultWithId>({
    items,
    columns,
    noWrapper,
    pagingController,
    setPagingController,
    isAutoPaging = true,
}: 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: +event.target.value,
            })
        }
    };

    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}>
                                                {columns.map((column, idx) => {
                                                    const columnName = column.name;

                                                    return (
                                                        <TabelCells key={`${columnName.toString()}-${idx}`} column={column} columnName={columnName} idx={idx} item={item}/>
                                                    );
                                                })}
                                            </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}/>
                        );
                                                })}
                                            </TableRow>
                                        );
                                    })
                        }
                    </TableBody>
                </Table>
            </TableContainer>
            <TablePagination
                rowsPerPageOptions={[10, 25, 100]}
                component="div"
                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,
}

function TabelCells<T extends ResultWithId>({
    column,
    columnName,
    idx,
    item
}: TableCellsProps<T>) {
    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]))}</>
        ) :
        (
            column.renderCell ? column.renderCell(item) : <>{item[columnName] as string}</>
        )}
    </TableCell>)
}

export default SearchResults;
