import {Controller} from "@hotwired/stimulus";
import "cropperjs";
import "@cropper/elements";

export default class extends Controller {
    static targets = ["input"];

    static values = {
        publicUrl: String,
        options: Object
    }

    connect() {
        const publicUrl = this.publicUrlValue;
        const options = this.optionsValue || {};

        const canvas = document.createElement('cropper-canvas');
        canvas.setAttribute('scaleStep', '0')
        canvas.classList.add('h-96')

        const image = document.createElement('cropper-image');
        image.setAttribute('src', publicUrl);
        image.setAttribute('alt', 'Cropper Image');
        image.setAttribute('scalable', '');
        image.setAttribute('translatable', '');

        const selection = document.createElement('cropper-selection');
        selection.setAttribute('movable', '');
        selection.setAttribute('resizable', '');
        selection.setAttribute('outlined', '');

        const initialData = options.data && (options.data.width > 0 || options.data.height > 0)
            ? options.data
            : null;

        const handleSelect = document.createElement('cropper-handle');
        handleSelect.setAttribute('action', 'select');
        handleSelect.setAttribute('plain', '');

        const handleMove = document.createElement('cropper-handle');
        handleMove.setAttribute('action', 'move');
        handleMove.setAttribute('plain', '');

        const handleN = document.createElement('cropper-handle');
        handleN.setAttribute('action', 'n-resize');

        const handleE = document.createElement('cropper-handle');
        handleE.setAttribute('action', 'e-resize');

        const handleS = document.createElement('cropper-handle');
        handleS.setAttribute('action', 's-resize');

        const handleW = document.createElement('cropper-handle');
        handleW.setAttribute('action', 'w-resize');

        const handleNE = document.createElement('cropper-handle');
        handleNE.setAttribute('action', 'ne-resize');

        const handleNW = document.createElement('cropper-handle');
        handleNW.setAttribute('action', 'nw-resize');

        const handleSE = document.createElement('cropper-handle');
        handleSE.setAttribute('action', 'se-resize');

        const handleSW = document.createElement('cropper-handle');
        handleSW.setAttribute('action', 'sw-resize');

        selection.appendChild(handleMove);
        selection.appendChild(handleN);
        selection.appendChild(handleE);
        selection.appendChild(handleS);
        selection.appendChild(handleW);
        selection.appendChild(handleNE);
        selection.appendChild(handleNW);
        selection.appendChild(handleSE);
        selection.appendChild(handleSW);

        canvas.appendChild(image);
        canvas.appendChild(handleSelect);
        canvas.appendChild(selection);

        this.element.appendChild(canvas);

        const getImageRect = () => {
            const canvasRect = canvas.getBoundingClientRect();
            const imageRect = image.getBoundingClientRect();
            return {
                x: imageRect.left - canvasRect.left,
                y: imageRect.top - canvasRect.top,
                width: imageRect.width,
                height: imageRect.height,
            };
        };

        const waitForImage = () => {
            if (typeof image.$ready === 'function') {
                return image.$ready();
            }
            return new Promise((resolve) => {
                const check = () => {
                    const r = image.getBoundingClientRect();
                    if (r.width > 0 && r.height > 0) {
                        resolve();
                    } else {
                        requestAnimationFrame(check);
                    }
                };
                check();
            });
        };

        if (initialData) {
            waitForImage().then(() => {
                const r = getImageRect();
                if (r.width === 0 || r.height === 0) {
                    return;
                }
                selection.$change(
                    r.x + initialData.x * r.width,
                    r.y + initialData.y * r.height,
                    initialData.width * r.width,
                    initialData.height * r.height,
                );
            });
        }

        // image.addEventListener('transform', (event) => {
        //     const cropperCanvasRect = canvas.getBoundingClientRect();
        //     const cropperImageClone = image.cloneNode();
        //     cropperImageClone.style.transform = `matrix(${event.detail.matrix.join(', ')})`;
        //     cropperImageClone.style.opacity = '0';
        //     canvas.appendChild(cropperImageClone);
        //     const cropperImageRect = cropperImageClone.getBoundingClientRect();
        //     canvas.removeChild(cropperImageClone);
        //
        //     const maxSelection = {
        //         x: cropperImageRect.left - cropperCanvasRect.left,
        //         y: cropperImageRect.top - cropperCanvasRect.top,
        //         width: cropperImageRect.width,
        //         height: cropperImageRect.height,
        //     };
        //
        //     if (!this.inSelection(selection, maxSelection)) {
        //         event.preventDefault();
        //     }
        // });

        selection.addEventListener('change', (event) => {
            const selectionData = event.detail;
            const r = getImageRect();

            if (!this.inSelection(selectionData, r)) {
                event.preventDefault();
                return;
            }

            if (r.width === 0 || r.height === 0) {
                return;
            }

            this.inputTarget.value = JSON.stringify({
                x: (selectionData.x - r.x) / r.width,
                y: (selectionData.y - r.y) / r.height,
                width: selectionData.width / r.width,
                height: selectionData.height / r.height,
            });

            this.inputTarget.dispatchEvent(new Event('change', { bubbles: true }));
        });

        this.selection = selection;
    }

    inSelection(selection, maxSelection) {
        return (
            selection.x >= maxSelection.x
            && selection.y >= maxSelection.y
            && (selection.x + selection.width) <= (maxSelection.x + maxSelection.width)
            && (selection.y + selection.height) <= (maxSelection.y + maxSelection.height)
        );
    }
}
