/*
 *  Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *  SPDX-License-Identifier: Apache-2.0
 */

import React, { useState, useEffect } from "react";
import {
    DragDropContext,
    DragStart,
    DragUpdate,
    Droppable,
    DropResult,
    ResponderProvided,
} from "react-beautiful-dnd";
import { Widget, WidgetType } from "../models";
import WidgetTreeItem from "./WidgetTreeItem";
import OrderingService, { WidgetTreeData } from "../services/OrderingService";
import { useTranslation } from "react-i18next";
import SecondaryActionBar from "./SecondaryActionBar";
import Button from "./Button";

interface Props {
    onClick: Function;
    onDelete: (widget: Widget) => void;
    onDuplicate: (widget: Widget) => void;
    onDrag: (widgets: Widget[]) => void;
    widgets: Array<Widget>;
}

function WidgetTree(props: Props) {
    const { t } = useTranslation();
    const droppableId = "widget-tree";
    const [tree, setTree] = useState<WidgetTreeData>();
    const [isDropDisabled, setIsDropDisabled] = useState(false);

    const onDragStarted = (start: DragStart, provided: ResponderProvided) => {
        if (!tree) {
            return;
        }
        const source = tree.map[start.source.index];
        provided.announce(
            t("WidgetTree.ItemLifted", {
                label: source?.label,
                name: source?.widget?.name,
            }),
        );
    };

    const onDragUpdate = (update: DragUpdate, provided: ResponderProvided) => {
        if (!tree) {
            return;
        }

        const source = tree.map[update.source.index];
        if (
            update.source.droppableId === droppableId &&
            update.destination &&
            update.destination.droppableId === droppableId
        ) {
            const destination = tree.map[update.destination.index];
            provided.announce(
                t("WidgetTree.ItemMoved", {
                    sourceLabel: source?.label,
                    sourceName: source?.widget?.name,
                    destinationLabel: destination?.label,
                    destinationName: destination?.widget?.name,
                }),
            );
            const isDisabled =
                source &&
                destination &&
                !!destination.section &&
                source.widget?.widgetType === WidgetType.Section &&
                destination.section !== source.id;
            if (isDisabled !== isDropDisabled) {
                setIsDropDisabled(isDisabled);
            }
        } else {
            provided.announce(
                t("WidgetTree.OutsideTheDroppableAreaError", {
                    label: source?.label,
                    name: source?.widget?.name,
                }),
            );
            setIsDropDisabled(false);
        }
    };

    const moveWidget = (sourceIndex: number, destinationIndex: number): void => {
        if (!tree) {
            return;
        }
        if (sourceIndex < 0) {
            sourceIndex = 0;
        }
        if (destinationIndex >= tree.nodes.length) {
            destinationIndex = tree.nodes.length - 1;
        }

        const widgets = OrderingService.moveWidget(tree, sourceIndex, destinationIndex);
        if (widgets) {
            setTree(OrderingService.buildTree(widgets));
            props.onDrag(widgets);
        }
    };

    const onDragEnd = (result: DropResult, provided: ResponderProvided) => {
        setIsDropDisabled(false);
        const { destination, source } = result;
        if (!destination) {
            return;
        }
        if (destination.droppableId === source.droppableId && destination.index === source.index) {
            return;
        }
        const sourceItem = tree?.map[source.index];
        const destinationItem = tree?.map[destination.index];
        moveWidget(source.index, destination.index);

        provided.announce(
            t("WidgetTree.ItemDropped", {
                sourceLabel: sourceItem?.label,
                sourceName: sourceItem?.widget?.name,
                destinationLabel: destinationItem?.label,
                destinationName: destinationItem?.widget?.name,
            }),
        );
    };

    useEffect(() => {
        const newNodes = OrderingService.buildTree(props.widgets);
        setTree(newNodes);
    }, [props.widgets]);

    return (
        <DragDropContext
            onDragStart={onDragStarted}
            onDragUpdate={onDragUpdate}
            onDragEnd={onDragEnd}
        >
            {
                <Droppable droppableId={droppableId} isDropDisabled={false}>
                    {(provided) => (
                        <div
                            ref={provided.innerRef}
                            {...provided.droppableProps}
                            className="padding-top-2 padding-bottom-2"
                        >
                            <hr className="margin-top-2 border-base-lightest" />
                            <h2 className="margin-bottom-2 margin-top-2">{t("ContentItems")}</h2>
                            <ol className="widget-tree" aria-label={t("ContentItems")}>
                                {tree?.nodes.map((node) => {
                                    return (
                                        <WidgetTreeItem
                                            key={node.id}
                                            node={node}
                                            isDropDisabled={isDropDisabled}
                                            onDuplicate={props.onDuplicate}
                                            onDelete={props.onDelete}
                                            onMove={moveWidget}
                                            canMoveUp={node.dragIndex > 0}
                                            canMoveDown={node.dragIndex < tree.length - 1}
                                        />
                                    );
                                })}
                            </ol>
                            {provided.placeholder}
                            {!props.widgets || props.widgets.length === 0 ? (
                                <SecondaryActionBar className="text-center padding-5 margin-y-2">
                                    <div>
                                        <p>
                                            {t("NoContentItems")} <br />
                                            {t("ChartsTablesMore")}
                                        </p>
                                        <div className="text-center margin-top-4">
                                            <Button
                                                className="margin-top-1"
                                                variant="base"
                                                onClick={() => {
                                                    if (props.onClick) {
                                                        props.onClick();
                                                    }
                                                }}
                                                ariaLabel={t("PlusAddContentItem")}
                                            >
                                                {t("PlusAddContentItem")}
                                            </Button>
                                        </div>
                                    </div>
                                </SecondaryActionBar>
                            ) : (
                                <div className="text-center margin-top-2">
                                    <button
                                        className="usa-button usa-button--base margin-top-1"
                                        onClick={() => {
                                            if (props.onClick) {
                                                props.onClick();
                                            }
                                        }}
                                        aria-label={t("PlusAddContentItem")}
                                    >
                                        {t("PlusAddContentItem")}
                                    </button>
                                </div>
                            )}
                        </div>
                    )}
                </Droppable>
            }
        </DragDropContext>
    );
}

export default WidgetTree;