'use client';
import { LexoRank } from 'lexorank';
import { useEffect, useState } from 'react';
import { DragDropContext } from 'react-beautiful-dnd';
import { toast } from '@payloadcms/ui';
import BoardColumn from '../BoardColumn/BoardColumn.js';
import { sortAndFilterDocumentsForStatus, sortAndFilterDocumentsWithoutStatus, } from '../utils/documents.util.js';
import './styles.scss';
const Board = (props) => {
    const { statusDefinition, documents: initDocuments, hideNoStatusColumn, onDocumentkanbanStatusChange, collection, dragEnabled, collectionSlug, } = props;
    const [documents, setDocuments] = useState(initDocuments ?? []);
    useEffect(() => {
        setDocuments(initDocuments);
    }, [initDocuments]);
    const updateDocument = async (documentId, destinationStatus, orderRank, sourceId) => {
        try {
            // Store the original document state before updating
            const originalDocuments = [...documents];
            const documentIndex = originalDocuments.findIndex((doc) => doc.id === documentId);
            const originalDocumentState = documentIndex !== -1 ? { ...originalDocuments[documentIndex] } : null;
            // Update the UI optimistically
            setDocuments((prev) => {
                const updatedDocumentIndex = prev.findIndex((_doc) => _doc.id === documentId);
                if (updatedDocumentIndex === -1) {
                    return prev;
                }
                const newDocuments = [...prev];
                newDocuments[updatedDocumentIndex] = {
                    ...newDocuments[updatedDocumentIndex],
                    kanbanStatus: destinationStatus,
                    kanbanOrderRank: orderRank,
                };
                return newDocuments;
            });
            // Call the status change function and wait for the status code
            const response = await onDocumentkanbanStatusChange(documentId, destinationStatus, orderRank);
            const statusCode = response.status;
            if (statusCode !== 200) {
                const res = await response.json();
                const errorMessage = res.errors[0].message;
                // Revert the UI state if the API call fails
                toast.error(errorMessage ? errorMessage : 'You are not authorised to update document status');
                // Restore the original state for this document
                if (originalDocumentState) {
                    setDocuments((prev) => {
                        const revertIndex = prev.findIndex((_doc) => _doc.id === documentId);
                        if (revertIndex === -1) {
                            return prev;
                        }
                        const revertedDocuments = [...prev];
                        revertedDocuments[revertIndex] = originalDocumentState;
                        return revertedDocuments;
                    });
                }
                return false;
            }
            return true;
        }
        catch (error) {
            console.error('Error updating document:', error);
            toast.error('Something went wrong');
            // Revert to original documents on error
            setDocuments(initDocuments);
            return false;
        }
    };
    const onDragEnd = async (result) => {
        if (!dragEnabled) {
            toast.error('You are not authorized to perform this action');
            return;
        }
        if (!result.destination) {
            return;
        }
        const source = result.source;
        const destination = result.destination;
        if (source.droppableId === destination.droppableId && source.index === destination.index) {
            return;
        }
        const documentId = result.draggableId;
        const sourceStatus = source.droppableId;
        const destinationStatus = destination.droppableId;
        const destinationIndex = destination.index;
        try {
            const destinationStatusGroup = sortAndFilterDocumentsForStatus(documents, destinationStatus);
            const minOrderRank = documents[0]?.kanbanOrderRank ?? LexoRank.min().toString();
            const maxOrderRank = documents[documents.length - 1]?.kanbanOrderRank ?? LexoRank.max().toString();
            // First in entire collection when added to empty group
            if (destinationStatusGroup.length === 0 &&
                documents.findIndex((_doc) => _doc.id === documentId) === 0) {
                return updateDocument(documentId, destinationStatus, LexoRank.min().toString(), source.droppableId);
            }
            // First in list on empty group
            if (destinationStatusGroup.length === 0 && destinationIndex === 0) {
                return updateDocument(documentId, destinationStatus, LexoRank.min().genNext().toString(), source.droppableId);
            }
            // First in list
            if (destinationIndex === 0) {
                const previousFirstDoc = [...destinationStatusGroup].shift();
                // If the value has not been set, set a default value
                if (!(typeof previousFirstDoc?.kanbanOrderRank === 'string')) {
                    const updatedOrderRank = LexoRank.parse(minOrderRank).between(LexoRank.max()).toString();
                    return updateDocument(documentId, destinationStatus, updatedOrderRank, source.droppableId);
                }
                const updatedOrderRank = LexoRank.parse(previousFirstDoc.kanbanOrderRank).genPrev();
                return updateDocument(documentId, destinationStatus, updatedOrderRank.toString(), source.droppableId);
            }
            // Last in the list
            if ((sourceStatus === destinationStatus &&
                destinationIndex + 1 === destinationStatusGroup.length) ||
                (sourceStatus !== destinationStatus && destinationIndex === destinationStatusGroup.length)) {
                const previousLastDoc = [...destinationStatusGroup].pop();
                // If the value has not been set, set a default value
                if (!(typeof previousLastDoc?.kanbanOrderRank === 'string')) {
                    const updatedOrderRank = LexoRank.parse(maxOrderRank).between(LexoRank.min()).toString();
                    return updateDocument(documentId, destinationStatus, updatedOrderRank, source.droppableId);
                }
                const updatedOrderRank = LexoRank.parse(previousLastDoc.kanbanOrderRank).genNext();
                return updateDocument(documentId, destinationStatus, updatedOrderRank.toString(), source.droppableId);
            }
            // Between 2 documents
            let documentBefore = destinationStatusGroup[destinationIndex - 1];
            let documentAfter = destinationStatusGroup[destinationIndex];
            // Within the same list re-ordering to the bottom, switch the document before and after
            if (sourceStatus === destinationStatus && source.index < destinationIndex) {
                documentBefore = destinationStatusGroup[destinationIndex];
                documentAfter = destinationStatusGroup[destinationIndex + 1];
            }
            const documentBeforeRank = LexoRank.parse(documentBefore.kanbanOrderRank);
            const documentAfterRank = LexoRank.parse(documentAfter.kanbanOrderRank);
            // Status change accepted
            return updateDocument(documentId, destinationStatus, documentBeforeRank.between(documentAfterRank).toString(), source.droppableId);
        }
        catch (error) {
            console.error('Error updating document:', error);
            toast.error('Something went wrong');
        }
    };
    return (<DragDropContext onDragEnd={(result) => onDragEnd(result)}>
      <div className="scrumboard">
        <div className="scrumboard-body">
          {hideNoStatusColumn ? (<></>) : (<BoardColumn collection={collection} title={'No status'} identifier={'null'} contents={sortAndFilterDocumentsWithoutStatus(documents)} collapsible={true} dragEnabled={dragEnabled}/>)}

          {statusDefinition?.options.map((status) => (<BoardColumn collection={collection} key={status.value} title={status.label} identifier={status.value} dragEnabled={dragEnabled} contents={sortAndFilterDocumentsForStatus(documents, status.value)}/>))}
        </div>
      </div>
    </DragDropContext>);
};
export { Board };
