import { Badge, Button, Flex, Input, Modal, ScrollAreaAutosize, Select, Stack, Table, TextInput } from '@mantine/core';
import { Cell, ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
import { useEffect, useMemo, useState } from 'react';
import styles from './CustomTable.module.scss'
import { useRoles } from '../hooks/swrHooks';
import { IRole } from '../interfaces/role';
import { IconPlus } from '@tabler/icons-react';
import { CreateField } from '../interfaces/create';
import { AxiosResponse } from 'axios';
import FormFields from './FormFields';
import { useDisclosure } from '@mantine/hooks';

type CustomTableProps<T> = {
    data: T[];
    columns: ColumnDef<T>[];
    createFields?: CreateField[];
    submitHandler?: (data: T) => Promise<AxiosResponse>
}

const CustomTable = <T extends object>({
    data: initialData,
    columns,
    createFields,
    submitHandler
}: CustomTableProps<T>) => {
    const [data, setData] = useState<T[]>(initialData);
    const [searchText, setSearchText] = useState('');
    const [editingCell, setEditingCell] = useState<{ rowIndex: string | number | null, columnId: string | number | null }>({ rowIndex: null, columnId: null });

    const tableColumns = useMemo(() => columns, [columns]);

    // Function to handle cell edit
    const handleEditCell = (
        rowIndex: number,
        columnId: keyof T,
        value: T[keyof T]
    ) => {
        const updatedData = [...data];
        updatedData[rowIndex][columnId] = value;
        setData(updatedData);
        //setEditingCell({ rowIndex: null, columnId: null });
    };

    const filteredData = useMemo(() => {
        if (!searchText) return data;

        return data.filter((row) =>
            Object.values(row).some((value) =>
                value?.toString().toLowerCase().includes(searchText.toLowerCase())
            )
        );
    }, [data, searchText])

    const table = useReactTable({
        data: filteredData,
        columns: tableColumns,
        getCoreRowModel: getCoreRowModel(),
        columnResizeMode: "onChange",
    });

    const [opened, { open, close }] = useDisclosure(false);

    return (
        <Stack h='100%'>
            {createFields && submitHandler &&
                <Modal opened={opened} onClose={close} title="Добавление объекта" centered>
                    <FormFields
                        fields={createFields}
                        submitHandler={submitHandler}
                    />
                </Modal>
            }

            <Flex w='100%' gap='sm'>
                <TextInput
                    placeholder="Поиск"
                    value={searchText}
                    onChange={(e) => setSearchText(e.target.value)}
                    w='100%'
                />
                {createFields && submitHandler &&
                    <Button
                        leftSection={<IconPlus />}
                        onClick={open}
                        style={{ flexShrink: 0 }}
                    >
                        Добавить
                    </Button>
                }
            </Flex>

            <ScrollAreaAutosize offsetScrollbars style={{ borderRadius: '4px' }}>
                <Table stickyHeader striped withColumnBorders highlightOnHover className={styles.table}>
                    <Table.Thead className={styles.thead}>
                        {table.getHeaderGroups().map(headerGroup => (
                            <Table.Tr key={headerGroup.id} className={styles.tr}>
                                {headerGroup.headers.map((header) => (
                                    <Table.Th key={header.id} className={styles.th} w={header.getSize()}>
                                        {flexRender(header.column.columnDef.header, header.getContext())}
                                        <div
                                            className={styles.resize_handler}
                                            onMouseDown={header.getResizeHandler()} //for desktop
                                            onTouchStart={header.getResizeHandler()}
                                        >
                                        </div>
                                    </Table.Th>
                                ))}
                            </Table.Tr>
                        ))}
                    </Table.Thead>
                    <Table.Tbody className={styles.tbody}>
                        {table.getRowModel().rows.map((row, rowIndex) => (
                            <Table.Tr key={row.id} className={styles.tr}>
                                {row.getVisibleCells().map(cell => {
                                    const isEditing = editingCell.rowIndex === rowIndex && editingCell.columnId === cell.column.id;

                                    return (
                                        <Table.Td
                                            key={cell.id}
                                            onDoubleClick={() => setEditingCell({ rowIndex, columnId: cell.column.id })}
                                            style={{ width: cell.column.getSize() }}
                                            className={styles.td}
                                        >
                                            {isEditing ? (
                                                <Input
                                                    type='text'
                                                    value={(data[rowIndex][cell.column.id as keyof T] as string)}
                                                    onChange={(e) => handleEditCell(rowIndex, (cell.column.id as keyof T), e.target.value as T[keyof T])}
                                                    onBlur={() => setEditingCell({ rowIndex: null, columnId: null })}
                                                    autoFocus
                                                />
                                            ) : (
                                                <CellDisplay cell={cell} />
                                            )}
                                        </Table.Td>
                                    );
                                })}
                            </Table.Tr>
                        ))}
                    </Table.Tbody>
                </Table>
            </ScrollAreaAutosize>
        </Stack>
    );
};

type CellDisplayProps<T> = {
    cell: Cell<T, unknown>;
}

const CellDisplay = <T extends object>({
    cell
}: CellDisplayProps<T>) => {
    const { roles } = useRoles()

    const [roleOptions, setRoleOptions] = useState<{ label: string, value: string }[]>()

    useEffect(() => {
        if (Array.isArray(roles)) {
            setRoleOptions(roles.map((role: IRole) => ({ label: role.name, value: role.id.toString() })))
        }
    }, [roles])

    switch (cell.column.id) {
        case 'activity':
            return (
                cell.getValue() ? (
                    <Badge fullWidth variant="light">
                        Активен
                    </Badge>
                ) : (
                    <Badge color="gray" fullWidth variant="light">
                        Отключен
                    </Badge>
                )
            )
        case 'is_active':
            return (
                cell.getValue() ? (
                    <Badge fullWidth variant="light">
                        Активен
                    </Badge>
                ) : (
                    <Badge color="gray" fullWidth variant="light">
                        Отключен
                    </Badge>
                )
            )
        case 'role_id':
            return (
                <Select
                    data={roleOptions}
                    value={Number(cell.getValue()).toString()}
                    variant="unstyled"
                    allowDeselect={false}
                />
            )
        default:
            return (
                flexRender(cell.column.columnDef.cell, cell.getContext())
            )
    }
}

export default CustomTable;
