import { negmod } from "./utils";

export class ImageViewer {
    root: HTMLDivElement;
    lightboxModal: HTMLDivElement;
    currentImages: string[] = []
    selectedIndex: number = -1;
    currentGallery: HTMLDivElement | null = null;
    static _instance: ImageViewer;

    static get instance(): ImageViewer {
        if (!ImageViewer._instance)
            ImageViewer._instance = new ImageViewer((window as any).app.rootEl)
        return ImageViewer._instance
    }

    get modalImage(): HTMLImageElement | null {
        return this.root.querySelector<HTMLImageElement>("#modalImage");
    }

    constructor(root: HTMLDivElement) {
        this.root = root;
        this.lightboxModal = this.root.querySelector<HTMLDivElement>("#lightboxModal");
    }

    // A full size 'lightbox' preview modal shown when left clicking on gallery previews
    closeModal() {
        this.lightboxModal.style.display = "none";
        this.currentImages = []
        this.selectedIndex = -1;
        this.currentGallery = null;
    }

    static all_gallery_buttons(gallery: HTMLDivElement): HTMLButtonElement[] {
        var allGalleryButtons = gallery.querySelectorAll('.preview > .thumbnails > .thumbnail-item.thumbnail-small');
        var visibleGalleryButtons = [];
        allGalleryButtons.forEach((elem) => {
            if (elem.parentElement.offsetParent) {
                visibleGalleryButtons.push(elem);
            }
        })
        return visibleGalleryButtons;
    }

    static selected_gallery_button(gallery: HTMLDivElement): [HTMLButtonElement | null, number] {
        var allCurrentButtons = gallery.querySelectorAll('.preview > .thumbnails > .thumbnail-item.thumbnail-small');
        console.log(allCurrentButtons)
        var visibleCurrentButton = null;
        let index = -1;
        allCurrentButtons.forEach((elem, i) => {
            if (elem.parentElement.offsetParent && elem.classList.contains("selected")) {
                visibleCurrentButton = elem;
                index = i;
            }
        })
        return [visibleCurrentButton, index];
    }

    showModal(imageUrls: string[], index: number, galleryElem?: HTMLDivElement) {
        this.currentImages = imageUrls
        this.selectedIndex = index
        this.currentGallery = galleryElem;
        this.setModalImageSrc(imageUrls[index])
        this.lightboxModal.style.display = "flex";

        const left = this.lightboxModal.querySelector<HTMLElement>(".modalPrev")
        const right = this.lightboxModal.querySelector<HTMLElement>(".modalNext")
        if (imageUrls.length <= 1) {
            left.style.display = "none"
            right.style.display = "none"
        }
        else {
            left.style.display = "block"
            right.style.display = "block"
        }

        setTimeout(() => {
            this.modalImage.focus()
        }, 200)
    }

    static get_gallery_urls(galleryElem: HTMLDivElement): string[] {
        return ImageViewer.all_gallery_buttons(galleryElem)
            .map(b => (b.children[0] as HTMLImageElement).src)
    }

    refreshImages() {
        if (this.currentGallery) {
            this.currentImages = ImageViewer.get_gallery_urls(this.currentGallery)
            let [_currentButton, index] = ImageViewer.selected_gallery_button(this.currentGallery);
            this.selectedIndex = index;
        }

        const selectedImageUrl = this.currentImages[this.selectedIndex];
        this.setModalImageSrc(selectedImageUrl)
    }

    private setModalImageSrc(src: string, isTiling: boolean = false) {
        const modalImage = this.modalImage
        const modal = this.lightboxModal
        modalImage.src = src;
        if (isTiling) {
            modalImage.style.display = 'none';
            modal.style.setProperty('background-image', `url(${modalImage.src})`)
        } else {
            modalImage.style.display = 'block';
            modal.style.setProperty('background-image', 'none')
        }
    }

    modalImageSwitch(offset: number) {
        this.selectedIndex = negmod(this.selectedIndex + offset, this.currentImages.length);
        const selectedImageUrl = this.currentImages[this.selectedIndex];

        this.setModalImageSrc(selectedImageUrl)

        if (this.currentGallery) {
            const galleryButtons = ImageViewer.all_gallery_buttons(this.currentGallery);
            const nextButton = galleryButtons[this.selectedIndex];
            if (nextButton) {
                nextButton.click()
            }
        }

        setTimeout(() => { this.lightboxModal.focus() }, 10)
    }

    modalNextImage(event) {
        this.modalImageSwitch(1)
        event.stopPropagation()
    }

    modalPrevImage(event) {
        this.modalImageSwitch(-1)
        event.stopPropagation()
    }

    modalKeyHandler(event) {
        switch (event.key) {
            case "ArrowLeft":
                this.modalPrevImage(event)
                break;
            case "ArrowRight":
                this.modalNextImage(event)
                break;
            case "Escape":
                this.closeModal();
                break;
        }
    }

    showLightbox(source: HTMLImageElement) {
        if (this.lightboxModal.style.display != "none")
            this.closeModal();

        const initiallyZoomed = true
        this.modalZoomSet(this.modalImage, initiallyZoomed)

        const galleryElem = source.closest<HTMLDivElement>("div.block")
        console.debug("[ImageViewer] showModal", event, source, galleryElem);
        if (!galleryElem || ImageViewer.all_gallery_buttons(galleryElem).length === 0) {
            console.error("No buttons found on gallery element!", galleryElem)
            return;
        }

        let urls = ImageViewer.get_gallery_urls(galleryElem)
        const [_currentButton, index] = ImageViewer.selected_gallery_button(galleryElem)
        console.warn("Gallery!", index, urls, galleryElem)

        this.showModal(urls, index, galleryElem)
    }

    modalZoomSet(modalImage: HTMLImageElement, enable: boolean) {
        if (enable) {
            modalImage.classList.add('modalImageFullscreen');
        } else {
            modalImage.classList.remove('modalImageFullscreen');
        }
    }

    modalZoomToggle(event: Event) {
        const modalImage = this.modalImage;
        this.modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen'))
        event.stopPropagation()
    }

    modalTileImageToggle(event: Event) {
        const isTiling = this.modalImage.style.display === 'none';
        this.setModalImageSrc(this.modalImage.src, isTiling)
        event.stopPropagation()
    }
}
