"use client";

import { Dispatch, SetStateAction, useState } from "react";
import type { DragStart, DropResult } from "@hello-pangea/dnd";
import { ServicesTab } from "@/app/services/components/shared/ServiceTabSegmentedControl/ServiceTabSegmentedControl";
import { useServicesContext } from "@/app/services/contexts/ServicesContext";
import ServiceDragState from "@/app/services/enums/DragState";
import makeContext from "@/lib/contextFactory/contextFactory";
import { getNewDndLexorank } from "@/utils/lexorank/generation";

type ServicesDndContextState = {
    onDragStart: (start: DragStart) => void;
    onDragEnd: (result: DropResult) => void;
    dragState: ServiceDragState;
    setDragState: Dispatch<SetStateAction<ServiceDragState>>;
};

const useServiceDndContextState = (): ServicesDndContextState => {
    const {
        categories,
        groupedServices,
        servicesTab,
        categoriesCrud,
        servicesCrud,
        servicesList,
    } = useServicesContext();

    const [dragState, setDragState] = useState<ServiceDragState>(
        ServiceDragState.DRAG_ENDED
    );

    const onDragStart = (start: DragStart) => {
        if (start.draggableId.includes("category")) {
            setDragState(ServiceDragState.DRAG_CATEGORY);
            return;
        }
        setDragState(ServiceDragState.DRAG_SERVICE);
    };

    const getCategoriesFromGroupedServices = () => [
        ...new Set(groupedServices.map(grouped => grouped.category)),
    ];

    const onCategoryDrag = (result: DropResult) => {
        if (
            !result.draggableId.startsWith("category-") ||
            result.source.index === result.destination!.index
        )
            return;

        const draggingCatId = Number(
            result.draggableId.replace("category-", "")
        );

        const rankKey =
            servicesTab === ServicesTab.DEAL_SERVICE
                ? "dealServiceRank"
                : "productServiceRank";

        const categories = getCategoriesFromGroupedServices();

        const newLexorank = getNewDndLexorank(
            result.source.index,
            result.destination!.index,
            categories,
            rankKey
        );

        categoriesCrud.onUpdate(draggingCatId, {
            [rankKey]: newLexorank,
        });
    };

    const onServiceDrag = (result: DropResult) => {
        if (!result.draggableId.startsWith("service-") || !result.destination)
            return;

        const sourceCatId = Number(
            result.source.droppableId.replace("services-", "")
        );
        const targetCatId = Number(
            result.destination!.droppableId.replace("services-", "")
        );

        const draggingServiceId = Number(
            result.draggableId.replace("service-", "")
        );

        const services = servicesList.services.filter(
            s => s.category.id === targetCatId && s.serviceType === servicesTab
        );

        const newLexorank = getNewDndLexorank(
            result.source.index,
            result.destination!.index,
            services,
            "lexorank"
        );

        const category =
            sourceCatId !== targetCatId
                ? categories.find(c => c.id === targetCatId)
                : null;

        servicesCrud.onUpdate(draggingServiceId, {
            lexorank: newLexorank,
            category,
        });
    };

    const onDragEnd = (result: DropResult) => {
        if (!result.destination) return;
        const sourceId = result.source.droppableId;

        if (sourceId === "categories") {
            onCategoryDrag(result);
            return;
        }
        onServiceDrag(result);
    };

    return {
        dragState,
        setDragState,
        onDragStart,
        onDragEnd,
    };
};

export const [ServicesDndContextProvider, useServicesDndContext] =
    makeContext<ServicesDndContextState>(
        useServiceDndContextState,
        "ServicesDnd"
    );
