import {ActionIcon, Flex, MultiSelect, rem, Tooltip} from "@mantine/core";
import {DatePickerInput, MonthPickerInput} from "@mantine/dates";
import useWorkTableState from "../hooks/useWorkTableState.tsx";
import {BaseTable} from "../../../../../components/BaseTable/BaseTable.tsx";
import {useEffect, useState} from "react";
import useWorkTableColumns, {EmployeeData} from "../hooks/useWorkTableColumns.tsx";
import {TimeTrackingRecord, TimeTrackingService, UserSchema} from "../../../../../client";
import {dateWithoutTimezone, getDatesBetween, getDatesInMonth} from "../../../../../shared/lib/date.ts";
import useUsersList from "../../../hooks/useUsersList.tsx";
import {notifications} from "../../../../../shared/lib/notifications.ts";
import {PaySchemeType} from "../../../../../shared/enums/PaySchemeType.ts";
import {IconEyeOff} from "@tabler/icons-react";
import {MRT_TableOptions} from "mantine-react-table";
import {difference, omit} from "lodash";


const WorkTimeTable = () => {
    const [data, setData] = useState<EmployeeData[]>([]);
    const {
        dateBoundaries,
        month,
        setMonth,
        trackingRecords,
        refetch
    } = useWorkTableState();
    const [hiddenUsers, setHiddenUsers] = useState<UserSchema[]>([]);
    const [selectedBoundaries, setSelectedBoundaries] = useState<[Date | null, Date | null]>([null, null]);

    const users = useUsersList().objects.filter(user => user.payRate?.payrollScheme.key === PaySchemeType.HOURLY);

    const getRange = () => {
        const startDate = selectedBoundaries[0];
        const endDate = selectedBoundaries[1];
        if (startDate && endDate) {
            return getDatesBetween(startDate, endDate);
        } else {
            return getDatesInMonth(month);
        }
    }
    const range = getRange();

    const transformTrackingRecordsToData = (trackingRecords: TimeTrackingRecord[]): EmployeeData[] => {
        if (!month) return [];
        const rangeDays = range.map(r => r.date());

        trackingRecords = trackingRecords.map(tr => ({
            ...tr,
            data: tr.data.filter(d => rangeDays.includes((new Date(d.date)).getDate()))
        }));
        const existingUserIds = trackingRecords.map(tr => tr.user.id);
        const firstResult = trackingRecords.map((record) => ({
            name: `${record.user.firstName} ${record.user.secondName}`,
            comment: record.user.comment,
            userId: record.user.id,
            totalAmount: record.totalAmount,
            data: record.data,
            ...Object.fromEntries(getDatesInMonth(month).reduce((acc, day) => {
                return acc.set(day.date().toString(), 0);
            }, new Map<string, number>)),
            ...Object.fromEntries(record.data.reduce((acc, recordData) => {
                return acc.set((new Date(recordData.date).getDate().toString()), recordData.hours);
            }, new Map<string, number>))
        }));
        const restUsersResult = users.filter(user => !existingUserIds.includes(user.id)).map(user => ({
            name: `${user.firstName} ${user.secondName}`,
            userId: user.id,
            comment: user.comment,
            totalAmount: 0,
            ...Object.fromEntries(getDatesInMonth(month).reduce((acc, day) => {
                return acc.set(day.date().toString(), 0);
            }, new Map<string, number>)),
        }))
        const hiddenUserIds = hiddenUsers.map(user => user.id);


        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-expect-error
        const result = (firstResult.concat(restUsersResult)).filter(r => !hiddenUserIds.includes(r.userId));
        const firstDate = selectedBoundaries[0];
        const lastDate = selectedBoundaries[1];
        if (firstDate && lastDate) {
            const allDays = getDatesInMonth(month).map(d => d.date().toString());
            const allowedDays = getDatesBetween(firstDate, lastDate).map(d => d.date().toString());
            const omitDays = difference(allDays, allowedDays);

            return result.map(r => {
                return omit(r, omitDays);
            }) as unknown as EmployeeData[];
        }
        return (result as unknown as EmployeeData[]).sort((a, b) => a.userId - b.userId);
    }

    const optimisticUpdate = (date: Date, userId: number, value: number) => {
        const user = users.find(user => user.id === userId);
        if (!user) return;
        setData(prevState => prevState.map(record => {
            if (record.userId !== userId) return record;
            record[date.getDate()] = value;
            return record;
        }))


        TimeTrackingService.updateTimeTrackingRecord({
            requestBody: {
                date: dateWithoutTimezone(date),
                hours: value,
                userId: user.id
            }
        }).then(async ({ok, message}) => {
            if (!ok) {
                notifications.guess(ok, {message});
            }
            await refetch();

        })
    }
    const columns = useWorkTableColumns({
        month,
        selectedBoundaries,
        data,
        onUpdate: optimisticUpdate,
        selectedCells: [],
        setSelectedCells: () => {
        },
        range
    });
    useEffect(() => {
        setData(transformTrackingRecordsToData(trackingRecords));
    }, [trackingRecords, hiddenUsers, selectedBoundaries]);
    useEffect(() => {
        setSelectedBoundaries([null, null]);
    }, [month])
    return (
        <Flex
            direction={"column"}
            p={rem(10)}
            gap={rem(10)}
        >
            <Flex
                align={"center"}
                justify={"space-between"}
                gap={rem(10)}
            >

                <MultiSelect
                    data={users.map(user => ({
                        label: `${user.firstName} ${user.secondName}`,
                        value: user.id.toString()
                    }))}
                    onChange={(event) => setHiddenUsers(users.filter(user => event.includes(user.id.toString())))}
                    value={hiddenUsers.map(user => user.id.toString())}
                    placeholder={hiddenUsers.length > 0 ? "" : "Скрытые пользователи"}
                />
                <Flex gap={rem(10)}>

                    <DatePickerInput
                        styles={{
                            input: {
                                textAlign: "center"
                            }
                        }}
                        miw={rem(80)}
                        valueFormat={"DD"}
                        type={"range"}
                        minDate={dateBoundaries[0]}
                        maxDate={dateBoundaries[1]}
                        value={selectedBoundaries}
                        onChange={setSelectedBoundaries}
                        placeholder={"Даты"}
                    />
                    <MonthPickerInput
                        allowDeselect={false}
                        onChange={(event) => event && setMonth(event)}
                        value={month}
                        placeholder={"Выберите месяц"}
                    />
                </Flex>

            </Flex>
            <Flex>
                <BaseTable
                    data={data}
                    columns={columns}
                    restProps={{
                        enableColumnActions: false,
                        enableSorting: false,
                        enableRowActions: true,
                        renderRowActions: ({row}) => (
                            <Flex gap="md">
                                <Tooltip label="Скрыть">
                                    <ActionIcon
                                        onClick={() => {
                                            const user = users.find(user => user.id === row.original.userId);
                                            if (!user) return;
                                            setHiddenUsers(prevState => [...prevState, user]);
                                        }}
                                        variant={"default"}>
                                        <IconEyeOff/>
                                    </ActionIcon>
                                </Tooltip>

                            </Flex>
                        ),
                    } as MRT_TableOptions<EmployeeData>}
                />
            </Flex>
        </Flex>
    )
}

export default WorkTimeTable;