import { LexoRank } from "lexorank";
import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
import {
    BaseDraggable,
    BaseGroupDraggable,
} from "@/components/dnd/types/types";
import { getNewLexorank } from "@/utils/lexorank/generation";
import { sortByLexorank } from "@/utils/lexorank/sort";

type NewRankGetters<
    TItem extends BaseDraggable,
    TGroup extends BaseGroupDraggable<TItem>,
> = {
    getNewRankForSameStatus: (
        statusItemsAndGroups: (TItem | TGroup)[],
        overItemOrGroupIndex: number,
        activeItemOrGroupIndex: number
    ) => string;
    getNewRankForAnotherStatus: (
        statusItemsAndGroups: (TItem | TGroup)[],
        overItemOrGroupIndex: number
    ) => string;
    getNewStatusRank: (
        activeStatusId: number,
        overStatusId: number
    ) => string | null;
};

const useGetNewRank = <
    TItem extends BaseDraggable,
    TGroup extends BaseGroupDraggable<TItem>,
>(): NewRankGetters<TItem, TGroup> => {
    const { statuses } = useStatusesContext();

    const getNewRankForSameStatus = (
        statusItemsAndGroups: (TItem | TGroup)[],
        overItemOrGroupIndex: number,
        activeItemOrGroupIndex: number
    ): string => {
        const [leftIndex, rightIndex] =
            overItemOrGroupIndex < activeItemOrGroupIndex
                ? [overItemOrGroupIndex - 1, overItemOrGroupIndex]
                : [overItemOrGroupIndex, overItemOrGroupIndex + 1];

        const leftLexorank =
            leftIndex >= 0
                ? LexoRank.parse(statusItemsAndGroups[leftIndex].lexorank)
                : null;
        const rightLexorank =
            rightIndex < statusItemsAndGroups.length
                ? LexoRank.parse(statusItemsAndGroups[rightIndex].lexorank)
                : null;

        return getNewLexorank(leftLexorank, rightLexorank).toString();
    };

    const getNewRankForAnotherStatus = (
        statusItemsAndGroups: (TItem | TGroup)[],
        overItemOrGroupIndex: number
    ): string => {
        const leftLexorank =
            overItemOrGroupIndex > 0
                ? LexoRank.parse(
                      statusItemsAndGroups[overItemOrGroupIndex - 1].lexorank
                  )
                : null;
        const rightLexorank = LexoRank.parse(
            statusItemsAndGroups[overItemOrGroupIndex].lexorank
        );

        return getNewLexorank(leftLexorank, rightLexorank).toString();
    };

    const getNewStatusRank = (
        activeStatusId: number,
        overStatusId: number
    ): string | null => {
        const sortedStatusList = sortByLexorank(statuses);
        const overIndex = sortedStatusList.findIndex(
            s => s.id === overStatusId
        );
        const activeIndex = sortedStatusList.findIndex(
            s => s.id === activeStatusId
        );

        if (overIndex === -1 || activeIndex === -1) return null;

        const [leftIndex, rightIndex] =
            overIndex < activeIndex
                ? [overIndex - 1, overIndex]
                : [overIndex, overIndex + 1];

        const leftLexorank =
            leftIndex >= 0
                ? LexoRank.parse(statuses[leftIndex].lexorank)
                : null;
        const rightLexorank =
            rightIndex < statuses.length
                ? LexoRank.parse(statuses[rightIndex].lexorank)
                : null;

        return getNewLexorank(leftLexorank, rightLexorank).toString();
    };

    return {
        getNewRankForSameStatus,
        getNewRankForAnotherStatus,
        getNewStatusRank,
    };
};

export default useGetNewRank;
