"use client";

import React, { ReactNode, RefObject, useMemo, useState } from "react";
import {
    DndContext,
    DragEndEvent,
    DragOverEvent,
    DragStartEvent,
} from "@dnd-kit/core";
import {
    horizontalListSortingStrategy,
    SortableContext,
} from "@dnd-kit/sortable";
import { FreeMode, Pagination, Scrollbar } from "swiper/modules";
import { Swiper, SwiperRef, SwiperSlide } from "swiper/react";
import { Box } from "@mantine/core";
import CreateStatusButton from "@/app/deals/components/shared/CreateStatusButton/CreateStatusButton";
import useDndSensors from "@/app/deals/hooks/useSensors";
import FunnelColumn from "@/components/dnd/FunnelDnd/components/FunnelColumn";
import FunnelOverlay from "@/components/dnd/FunnelDnd/components/FunnelOverlay";
import {
    getContainerId,
    getDndContainerId,
    isContainerId,
} from "@/components/dnd/FunnelDnd/utils/columnId";
import {
    getGroupId,
    isGroupId,
} from "@/components/dnd/FunnelDnd/utils/groupId";
import {
    BaseDraggable,
    BaseGroupDraggable,
} from "@/components/dnd/types/types";
import useIsMobile from "@/hooks/utils/useIsMobile";
import SortableItem from "../SortableItem";
import classes from "./FunnelDnd.module.css";

type Props<TContainer, TItem, TGroup> = {
    containers: TContainer[];
    itemsAndGroups: (TItem | TGroup)[];
    onDragOver: (event: DragOverEvent) => void;
    onDragEnd: (event: DragEndEvent) => void;
    swiperRef: RefObject<SwiperRef | null>;
    renderContainer: (
        container: TContainer,
        children: ReactNode,
        renderDraggable: () => ReactNode,
        index: number
    ) => ReactNode;
    renderContainerHeader: (container: TContainer) => ReactNode;
    renderContainerOverlay: (
        container: TContainer,
        children: ReactNode
    ) => ReactNode;
    renderItem: (item: TItem) => ReactNode;
    renderGroup: (group: TGroup) => ReactNode;
    getItemsByContainer: (container: TContainer) => (TItem | TGroup)[];
    isCreatingContainerEnabled?: boolean;
    disabledColumns?: boolean;
};

const FunnelDnd = <
    TContainer extends BaseDraggable,
    TItem extends BaseDraggable,
    TGroup extends BaseGroupDraggable<TItem>,
>({
    containers,
    itemsAndGroups,
    onDragOver,
    onDragEnd,
    swiperRef,
    renderContainer,
    renderContainerHeader,
    renderContainerOverlay,
    renderItem,
    renderGroup,
    getItemsByContainer,
    isCreatingContainerEnabled = true,
    disabledColumns = false,
}: Props<TContainer, TItem, TGroup>) => {
    const sensors = useDndSensors();
    const isMobile = useIsMobile();
    const frequency = useMemo(() => (isMobile ? 1 : undefined), [isMobile]);

    const [activeItem, setActiveItem] = useState<TItem | null>(null);
    const [activeContainer, setActiveContainer] = useState<TContainer | null>(
        null
    );
    const [activeGroup, setActiveGroup] = useState<TGroup | null>(null);

    const renderContainers = () =>
        containers.map((container, index) => {
            const containerItems = getItemsByContainer(container);
            const containerId = getDndContainerId(container.id);
            return (
                <SwiperSlide
                    style={{ width: 250 }}
                    key={containerId}>
                    <SortableItem
                        key={containerId}
                        id={containerId}
                        disabled={disabledColumns}
                        renderItem={renderDraggable =>
                            renderContainer(
                                container,
                                <FunnelColumn
                                    id={containerId}
                                    itemsAndGroups={containerItems}
                                    renderItem={renderItem}
                                    renderGroup={renderGroup}
                                />,
                                renderDraggable!,
                                index
                            )
                        }
                        renderDraggable={() => renderContainerHeader(container)}
                    />
                </SwiperSlide>
            );
        });

    const renderBody = () => {
        if (isMobile) {
            return (
                <Box>
                    <Swiper
                        ref={swiperRef}
                        onTouchStart={swiper => {
                            swiper.allowTouchMove = !activeItem;
                        }}
                        onTouchMove={swiper => {
                            swiper.allowTouchMove = !activeItem;
                        }}
                        className={classes["swiper-container"]}
                        spaceBetween={15}
                        style={{
                            paddingInline: "10vw",
                            height: "calc(100vh - 188px)",
                        }}
                        modules={[Pagination]}
                        freeMode={{ enabled: false }}
                        pagination={{ enabled: true, clickable: true }}>
                        {renderContainers()}
                        {isCreatingContainerEnabled && (
                            <SwiperSlide style={{ width: 250 }}>
                                <CreateStatusButton />
                            </SwiperSlide>
                        )}
                    </Swiper>
                </Box>
            );
        }
        return (
            <Swiper
                ref={swiperRef}
                className={classes["swiper-container"]}
                modules={[Scrollbar, FreeMode]}
                spaceBetween={15}
                slidesPerView={"auto"}
                scrollbar={{ hide: false }}
                freeMode={{ enabled: true }}
                touchStartPreventDefault={false}
                grabCursor>
                {renderContainers()}
                {isCreatingContainerEnabled && (
                    <SwiperSlide style={{ width: 50 }}>
                        <CreateStatusButton />
                    </SwiperSlide>
                )}
            </Swiper>
        );
    };

    const onDragStart = ({ active }: DragStartEvent) => {
        const activeId = active.id as string | number;

        if (typeof activeId !== "string") {
            const item = (itemsAndGroups.find(
                item => !("items" in item) && item.id === activeId
            ) ?? null) as TItem | null;
            setActiveItem(item);
            return;
        }

        if (isContainerId(activeId)) {
            const contId = getContainerId(activeId);
            setActiveContainer(
                containers.find(container => container.id === contId) ?? null
            );
            return;
        }

        if (isGroupId(activeId)) {
            const groupId = getGroupId(activeId);
            const group = (itemsAndGroups.find(
                group => "items" in group && group.id === groupId
            ) ?? null) as TGroup | null;
            setActiveGroup(group);
        }
    };

    return (
        <DndContext
            sensors={sensors}
            measuring={{
                droppable: {
                    frequency,
                },
            }}
            onDragStart={onDragStart}
            onDragOver={onDragOver}
            onDragEnd={state => {
                setActiveContainer(null);
                setActiveItem(null);
                setActiveGroup(null);
                onDragEnd(state);
            }}>
            <SortableContext
                items={containers.map(container =>
                    getDndContainerId(container.id)
                )}
                strategy={horizontalListSortingStrategy}>
                {renderBody()}
                <FunnelOverlay
                    activeContainer={activeContainer}
                    activeItem={activeItem}
                    activeGroup={activeGroup}
                    renderContainer={container => {
                        const containerItems = getItemsByContainer(container);
                        const containerId = getDndContainerId(container.id);
                        return renderContainerOverlay(
                            container,
                            <FunnelColumn
                                id={containerId}
                                itemsAndGroups={containerItems}
                                renderItem={renderItem}
                                renderGroup={renderGroup}
                            />
                        );
                    }}
                    renderItem={renderItem}
                    renderGroup={renderGroup}
                />
            </SortableContext>
        </DndContext>
    );
};

export default FunnelDnd;
