const DraggableUtils = {

    boxDragContainer: document.getElementById('box-drag-container'),
    pdfCanvas: document.getElementById('pdf-canvas'),
    nextId: 0,
    pdfDoc: null,
    pageIndex: 0,
    documentsMap: new Map(),

    init() {
        interact('.draggable-canvas')
        .draggable({
            listeners: {
                move: (event) => {
                    const target = event.target;
                    const x = (parseFloat(target.getAttribute('data-bs-x')) || 0) + event.dx;
                    const y = (parseFloat(target.getAttribute('data-bs-y')) || 0) + event.dy;

                    target.style.transform = `translate(${x}px, ${y}px)`;
                    target.setAttribute('data-bs-x', x);
                    target.setAttribute('data-bs-y', y);

                    this.onInteraction(target);
                },
            },
        })
        .resizable({
    edges: { left: true, right: true, bottom: true, top: true },
    listeners: {
        move: (event) => {
            var target = event.target
            var x = (parseFloat(target.getAttribute('data-bs-x')) || 0)
            var y = (parseFloat(target.getAttribute('data-bs-y')) || 0)

            // check if control key is pressed
            if (event.ctrlKey) {
                const aspectRatio = target.offsetWidth / target.offsetHeight;
                // preserve aspect ratio
                let width = event.rect.width;
                let height = event.rect.height;

                if (Math.abs(event.deltaRect.width) >= Math.abs(event.deltaRect.height)) {
                    height = width / aspectRatio;
                } else {
                    width = height * aspectRatio;
                }

                event.rect.width = width;
                event.rect.height = height;
            }

            target.style.width = event.rect.width + 'px'
            target.style.height = event.rect.height + 'px'

            // translate when resizing from top or left edges
            x += event.deltaRect.left
            y += event.deltaRect.top

            target.style.transform = 'translate(' + x + 'px,' + y + 'px)'

            target.setAttribute('data-bs-x', x)
            target.setAttribute('data-bs-y', y)
            target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height)

            this.onInteraction(target);
        },
    },

            modifiers: [
                interact.modifiers.restrictSize({
                    min: { width: 5, height: 5 },
                }),
            ],
            inertia: true,
        });
    },
    onInteraction(target) {
        this.boxDragContainer.appendChild(target);
    },

    createDraggableCanvas() {
        const createdCanvas = document.createElement('canvas');
        createdCanvas.id = `draggable-canvas-${this.nextId++}`;
        createdCanvas.classList.add("draggable-canvas");

        const x = 0;
        const y = 20;
        createdCanvas.style.transform = `translate(${x}px, ${y}px)`;
        createdCanvas.setAttribute('data-bs-x', x);
        createdCanvas.setAttribute('data-bs-y', y);

        createdCanvas.onclick = e => this.onInteraction(e.target);

        this.boxDragContainer.appendChild(createdCanvas);
        return createdCanvas;
    },
    createDraggableCanvasFromUrl(dataUrl) {
        return new Promise((resolve) => {
            var myImage = new Image();
            myImage.src = dataUrl;
            myImage.onload = () => {
                var createdCanvas = this.createDraggableCanvas();

                createdCanvas.width = myImage.width;
                createdCanvas.height = myImage.height;

                const imgAspect = myImage.width / myImage.height;
                const pdfAspect = this.boxDragContainer.offsetWidth / this.boxDragContainer.offsetHeight;

                var scaleMultiplier;
                if (imgAspect > pdfAspect) {
                    scaleMultiplier = this.boxDragContainer.offsetWidth / myImage.width;
                } else {
                    scaleMultiplier = this.boxDragContainer.offsetHeight / myImage.height;
                }

                var newWidth = createdCanvas.width;
                var newHeight = createdCanvas.height;
                if (scaleMultiplier < 1) {
                    newWidth = newWidth * scaleMultiplier;
                    newHeight = newHeight * scaleMultiplier;
                }
                
                createdCanvas.style.width = newWidth+"px";
                createdCanvas.style.height = newHeight+"px";

                var myContext = createdCanvas.getContext("2d");
                myContext.drawImage(myImage,0,0);
                resolve(createdCanvas);
            }
        })
    },
    deleteAllDraggableCanvases() {
        this.boxDragContainer.querySelectorAll(".draggable-canvas").forEach(el => el.remove());
    },
    deleteDraggableCanvas(element) {
        if (element) {
            element.remove();
        }
    },
    getLastInteracted() {
        return this.boxDragContainer.querySelector(".draggable-canvas:last-of-type");
    },

    storePageContents() {
        var pagesMap = this.documentsMap.get(this.pdfDoc);
        if (!pagesMap) {
            pagesMap = {};
        }
        
        const elements = [...this.boxDragContainer.querySelectorAll(".draggable-canvas")];
        const draggablesData = elements.map(el => {return{element:el, offsetWidth:el.offsetWidth, offsetHeight:el.offsetHeight}});
        elements.forEach(el => this.boxDragContainer.removeChild(el));

        pagesMap[this.pageIndex] = draggablesData;
        pagesMap[this.pageIndex+"-offsetWidth"] = this.pdfCanvas.offsetWidth;
        pagesMap[this.pageIndex+"-offsetHeight"] = this.pdfCanvas.offsetHeight;

        this.documentsMap.set(this.pdfDoc, pagesMap);
    },
    loadPageContents() {
        var pagesMap = this.documentsMap.get(this.pdfDoc);
        this.deleteAllDraggableCanvases();
        if (!pagesMap) {
            return;
        }
        
        const draggablesData = pagesMap[this.pageIndex];
        if (draggablesData) {
            draggablesData.forEach(draggableData => this.boxDragContainer.appendChild(draggableData.element));
        }

        this.documentsMap.set(this.pdfDoc, pagesMap);
    },

    async renderPage(pdfDocument, pageIdx) {
        this.pdfDoc = pdfDocument ? pdfDocument : this.pdfDoc;
        this.pageIndex = pageIdx;

        // persist 
        const page = await this.pdfDoc.getPage(this.pageIndex+1);

        // set the canvas size to the size of the page
        if (page.rotate == 90 || page.rotate == 270) {
            this.pdfCanvas.width = page.view[3];
            this.pdfCanvas.height = page.view[2];
        } else {
            this.pdfCanvas.width = page.view[2];
            this.pdfCanvas.height = page.view[3];
        }

        // render the page onto the canvas
        var renderContext = {
            canvasContext: this.pdfCanvas.getContext("2d"),
            viewport: page.getViewport({ scale: 1 })
        };
        await page.render(renderContext).promise;

        //return pdfCanvas.toDataURL();
    },
    async incrementPage() {
        if (this.pageIndex < this.pdfDoc.numPages-1) {
            this.storePageContents();
            await this.renderPage(this.pdfDoc, this.pageIndex+1);
            this.loadPageContents();
        }
    },
    async decrementPage() {
        if (this.pageIndex > 0) {
            this.storePageContents();
            await this.renderPage(this.pdfDoc, this.pageIndex-1);
            this.loadPageContents();
        }
    },

    parseTransform(element) {
        
    },
    async getOverlayedPdfDocument() {
        const pdfBytes = await this.pdfDoc.getData();
        const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, { ignoreEncryption: true });
        this.storePageContents();

        const pagesMap = this.documentsMap.get(this.pdfDoc);
        for (let pageIdx in pagesMap) {
            if (pageIdx.includes("offset")) {
                continue;
            }
            console.log(typeof pageIdx);
            
            const page = pdfDocModified.getPage(parseInt(pageIdx));
            const draggablesData = pagesMap[pageIdx];
            const offsetWidth = pagesMap[pageIdx+"-offsetWidth"];
            const offsetHeight = pagesMap[pageIdx+"-offsetHeight"];

            for (const draggableData of draggablesData) {
                // embed the draggable canvas
                const draggableElement = draggableData.element;
                const response = await fetch(draggableElement.toDataURL());
                const draggableImgBytes = await response.arrayBuffer();
                const pdfImageObject = await pdfDocModified.embedPng(draggableImgBytes);
    
                // calculate the position in the pdf document
                const tansform = draggableElement.style.transform.replace(/[^.,-\d]/g, '');
                const transformComponents = tansform.split(",");
                const draggablePositionPixels = {
                    x: parseFloat(transformComponents[0]),
                    y: parseFloat(transformComponents[1]),
                    width: draggableData.offsetWidth,
                    height: draggableData.offsetHeight,
                };
                const draggablePositionRelative = {
                    x: draggablePositionPixels.x / offsetWidth,
                    y: draggablePositionPixels.y / offsetHeight,
                    width: draggablePositionPixels.width / offsetWidth,
                    height: draggablePositionPixels.height / offsetHeight,
                }
                const draggablePositionPdf = {
                    x: draggablePositionRelative.x * page.getWidth(),
                    y: draggablePositionRelative.y * page.getHeight(),
                    width: draggablePositionRelative.width * page.getWidth(),
                    height: draggablePositionRelative.height * page.getHeight(),
                }
    
                // draw the image
                page.drawImage(pdfImageObject, {
                    x: draggablePositionPdf.x,
                    y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height,
                    width: draggablePositionPdf.width,
                    height: draggablePositionPdf.height,
                });
            }
        }

        this.loadPageContents();
        return pdfDocModified;
    },
}

document.addEventListener("DOMContentLoaded", () => {
    DraggableUtils.init();
});
