import { Vec } from '@tldraw/vec';
import type { TldrawApp } from '@toeverything/components/board-state';
import { TLDR } from '@toeverything/components/board-state';
import type {
    PagePartial,
    TldrawCommand,
} from '@toeverything/components/board-types';

export function translateShapes(
    app: TldrawApp,
    ids: string[],
    delta: number[]
): TldrawCommand {
    const { currentPageId, selectedIds } = app;

    // Clear session cache
    app.rotationInfo.selectedIds = [...selectedIds];

    const before: PagePartial = {
        shapes: {},
        bindings: {},
    };

    const after: PagePartial = {
        shapes: {},
        bindings: {},
    };

    const idsToMutate = ids
        .flatMap(id => {
            const shape = app.getShape(id);
            return shape.children ? shape.children : shape.id;
        })
        .filter(id => !app.getShape(id).isLocked);

    const change = TLDR.mutate_shapes(
        app.state,
        idsToMutate,
        shape => ({
            point: Vec.toFixed(Vec.add(shape.point, delta)),
        }),
        currentPageId
    );

    before.shapes = change.before;
    after.shapes = change.after;

    // Delete bindings from nudged shapes, unless both bound and bound-to shapes are selected
    const bindingsToDelete = TLDR.get_bindings(app.state, currentPageId).filter(
        binding => ids.includes(binding.fromId) && !ids.includes(binding.toId)
    );

    bindingsToDelete.forEach(binding => {
        before.bindings[binding.id] = binding;
        after.bindings[binding.id] = undefined;

        for (const id of [binding.toId, binding.fromId]) {
            // Let's also look at the bound shape...
            const shape = app.getShape(id);

            if (!shape.handles) continue;

            // If the bound shape has a handle that references the deleted binding, delete that reference

            Object.values(shape.handles)
                .filter(handle => handle.bindingId === binding.id)
                .forEach(handle => {
                    before.shapes[id] = {
                        ...before.shapes[id],
                        handles: {
                            ...before.shapes[id]?.handles,
                            [handle.id]: { bindingId: binding.id },
                        },
                    };
                    after.shapes[id] = {
                        ...after.shapes[id],
                        handles: {
                            ...after.shapes[id]?.handles,
                            [handle.id]: { bindingId: undefined },
                        },
                    };
                });
        }
    });

    return {
        id: 'translate',
        before: {
            document: {
                pages: {
                    [currentPageId]: before,
                },
                pageStates: {
                    [currentPageId]: {
                        selectedIds: ids,
                    },
                },
            },
        },
        after: {
            document: {
                pages: {
                    [currentPageId]: after,
                },
                pageStates: {
                    [currentPageId]: {
                        selectedIds: ids,
                    },
                },
            },
        },
    };
}
