// noinspection JSUnresolvedReference,JSUnusedGlobalSymbols

document.addEventListener('alpine:init', () => {

    // noinspection JSUnresolvedReference
    Alpine.data('task_drag_and_drop_run', () => ({
        dragging: {mouse_x: null, mouse_y: null},
        snaps: null,
        options: {repositioning_allowed: false, partial_submit_allowed: false, loose_snaps: true},
        tiles_count: null,
        tries_count: 0,
        placements: {},
        submitting: false,
        drag_start(e) {
            this.dragging.mouse_x = e.offsetX;
            this.dragging.mouse_y = e.offsetY;
            e.dataTransfer.effectAllowed = 'move';
        },
        drag_end(tile_id, e) {
            if (!this.options.repositioning_allowed && this.placements[tile_id]) {
                return;
            }

            const drop_location = this.get_drop_location(e);
            const snap = this.get_snap(drop_location);

            if (!snap && !this.options.loose_snaps) {
                return;
            }

            this.tries_count++;

            this.placements[tile_id] = snap ?? drop_location;

            this.$refs.container.appendChild(e.target);

            if (this.check_complete() && !this.options.repositioning_allowed) {
                this.submit();
            }
        },
        get_drop_location(e) {
            const image_offset_x = Math.round(this.$refs.base_image.getBoundingClientRect().left);
            const image_offset_y = Math.round(this.$refs.base_image.getBoundingClientRect().top);

            const drop_offset_x = e.clientX - this.dragging.mouse_x;
            const drop_offset_y = e.clientY - this.dragging.mouse_y;

            const drop_x = drop_offset_x - image_offset_x;
            const drop_y = drop_offset_y - image_offset_y;

            return {x: drop_x, y: drop_y}
        },
        get_snap(drop_location) {
            for (const snap of this.snaps) {
                if (drop_location.x < snap.x - snap.distance) {
                    continue;
                }
                if (drop_location.x > snap.x + snap.distance) {
                    continue;
                }
                if (drop_location.y < snap.y - snap.distance) {
                    continue;
                }
                if (drop_location.y > snap.y + snap.distance) {
                    continue;
                }

                return snap;
            }

            return null;
        },
        check_complete() {
            return Object.keys(this.placements).length === this.tiles_count;
        },
        submit() {
            this.submitting = true;
            this.$wire.call('complete_task_with_result', {
                placements: this.placements,
                tries_count: this.tries_count,
            })
        },
    }));
});
