import { useEffect, useMemo } from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
import Animated, { runOnJS, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import { grid } from '../../utils/grid';
import { useTableItem } from '../../hooks/useTableItem';
import { getStyles } from './styles';
import { formatNumberString } from '../../utils/formatNumberString';
import { isIOS } from '../../utils/Utils';
import { divideDate, type RenderItem } from "react-native-week-schedule-1";

export const Item: RenderItem = ({ item, currentItem, titleKey, dataKey, scrollY, contentHeight, overlappingIds = [], onDragEnd, onPress, scrollOnDrag }) => {
    const styles = useMemo(() => getStyles(), []);
    const { top, left, height } = useTableItem(item);
    const width = grid.cellWight / (overlappingIds.length || 1);
    const fullWidth = grid.cellWight;
    const title = item?.[titleKey] as string;
    const offset = useSharedValue({ x: left, y: top });
    const animationY = useSharedValue(0);
    const inProgress = useSharedValue(0);

    useEffect(() => {
        offset.value = { x: left, y: top };
    }, [left, offset, top]);

    const additionalOffset = useMemo(() => {
        const prev: string[] = [];
        overlappingIds.forEach((overlappingItem) => {
            if (!(overlappingItem && item?.[dataKey])) return;
            if (overlappingItem >= item?.[dataKey]) return;
            prev.push(overlappingItem);
        });
        return width * prev.length;
    }, [item, dataKey, width, overlappingIds]);

    const handleOnPress = () => {
        onPress?.(item);
    };

    const animatedStyles = useAnimatedStyle(() => {
        let valueX = offset.value.x;
        if (offset.value.x < 0) {
            valueX = 0;
        } else if (offset.value.x > fullWidth * 6) {
            valueX = fullWidth * 6;
        }
        return {
            transform: [
                { translateX: valueX },
                { translateY: offset.value.y },
            ],
        };
    });

    const onEnd = () => {
        const date = new Date(item.date)
        const time = Math.floor(offset.value.y / grid.cellHeight) < 0 ? 0 : Math.floor(offset.value.y / grid.cellHeight);
        const day = Math.floor(offset.value.x / grid.cellWight) < 0 ? 0 : Math.floor(offset.value.x / grid.cellWight);
        const monthDate = date.getDate() + ((day - new Date(item.date).getDay()));
        const [year, month] = divideDate(item.date);
        const lastDay = new Date(year, month, 0).getDate();
        const dragValue = { time, day, item, date: `${year}-${formatNumberString(month)}-${formatNumberString(monthDate)}T${formatNumberString(time)}:00:00` }
        if (monthDate <= 0) {
            const m = month === 1 ? 12 : month + 1
            const d = new Date(year, m + 1, 0).getDate() - 1 - Math.abs(monthDate);
            onDragEnd?.({
                ...dragValue,
                date: `${year}-${formatNumberString(month - 1)}-${formatNumberString(d)}T${formatNumberString(time)}:00:00`,
            });
            return;
        };
        if (monthDate > lastDay) {
            const d = monthDate - lastDay;
            const m = month === 12 ? 1 : month + 1
            onDragEnd?.({
                ...dragValue,
                date: `${year}-${formatNumberString(m)}-${formatNumberString(d)}T${formatNumberString(time)}:00:00`,
            });
            return;
        };
        onDragEnd?.(dragValue);
    };

    const handleScroll = (itemY: number) => {
        const difference = itemY - scrollY.value;
        if (difference < 15 && !inProgress.value && itemY) {
            inProgress.value = 1;
            scrollOnDrag(scrollY.value - 100);
            const destination =
                itemY - 100 > 0
                    ? animationY.value - (isIOS ? 100 : 0)
                    : animationY.value - itemY;
            animationY.value = withTiming(destination, { duration: 250 });
            setTimeout(() => {
                inProgress.value = 0;
            }, 500);
        }

        const isNeedScrollDown =
            scrollY.value + contentHeight - (itemY + height) < 40;
        if (isNeedScrollDown && !inProgress.value) {
            inProgress.value = 1;
            scrollOnDrag(scrollY.value + 100);
            const destination =
                grid.cellHeight * 24 - (itemY + height + 100) < 0
                    ? animationY.value + grid.cellHeight * 24 - (itemY + height)
                    : animationY.value + (isIOS ? 100 : 0);
            animationY.value = withTiming(destination, { duration: 250 });
            setTimeout(() => {
                inProgress.value = 0;
            }, 700);
        }
    };

    const gesture = Gesture.Pan()
        .onUpdate((event) => {
            offset.value = {
                x: event.translationX + left,
                y:
                    event.translationY + top + animationY.value < 0
                        ? 0
                        : event.translationY + top + animationY.value,
            };
            runOnJS(handleScroll)(offset.value.y);
        })
        .onEnd(() => {
            offset.value = {
                x: offset.value.x,
                y: offset.value.y,
            };
        })
        .onFinalize(() => {
            animationY.value = 0;
            runOnJS(onEnd)();
        });

    return (currentItem?.[dataKey] === item[dataKey]
        ? <GestureDetector gesture={gesture}>
            <Animated.View style={[{ width: grid.cellWight, zIndex: 1 }, animatedStyles]}>
                <View
                    style={[
                        styles.container,
                        styles.selectedContainer,
                        {
                            backgroundColor: item.color ?? grid.colors.primary,
                            height,
                            width: grid.cellWight,
                        },
                    ]}
                >
                    <Text style={styles.text}>{title}</Text>
                </View>
            </Animated.View>
        </GestureDetector>
        : <TouchableOpacity
            style={[
                styles.container,
                {
                    backgroundColor: item.color ?? grid.colors.primary,
                    width,
                    height,
                    top,
                    left: left + additionalOffset,
                },
            ]}
            onPress={handleOnPress}
        >
            <Text style={styles.text}>{title}</Text>
        </TouchableOpacity>
    );
}
