<script lang="ts">
    import { onDestroy } from "svelte"
    import MedialibFile from "./MedialibFile.svelte"

    interface Props {
        id: string
        filter?:
            | null
            | "xs"
            | "s"
            | "m"
            | "l"
            | "xl"
            | "xxl"
            | "xs-webp"
            | "s-webp"
            | "m-webp"
            | "l-webp"
            | "xl-webp"
            | "xxl-webp"
        minWidth?: number
        noPlaceholder?: boolean
        style?: string
        widthMultiplier?: number
        lazy?: boolean
    }

    let {
        id,
        filter,
        minWidth = null,
        noPlaceholder = false,
        style,
        widthMultiplier = 1,
        lazy = false,
    }: Props = $props()

    let imgElement: HTMLImageElement = $state()

    function getSrcWithFilter(_imgElement: HTMLImageElement, entry: MedialibEntry, src: string) {
        if (typeof window === "undefined") {
            return src + `?filter=${filter || "xs-webp"}`
        }
        let internalFilter = filter
        if (imgElement) {
            if (!entry.file?.type?.match(/^image\/(png|jpe?g|webp)/)) return src // no filter for svg
            if (!internalFilter) {
                let imgWidth = _imgElement.width

                if (widthMultiplier) {
                    imgWidth *= widthMultiplier
                }

                // get the width of the image element
                const width = minWidth ? (imgWidth < minWidth ? minWidth : imgWidth) : imgWidth
                switch (true) {
                    case width <= 90:
                        internalFilter = "xs-webp"
                        break
                    case width <= 300:
                        internalFilter = "s-webp"
                        break
                    case width <= 600:
                        internalFilter = "m-webp"
                        break
                    case width <= 1200:
                        internalFilter = "l-webp"
                        break
                    case width <= 2000:
                        internalFilter = "xl-webp"
                        break
                    case width <= 4000:
                        internalFilter = "xxl-webp"
                        break
                }
            }
            return src + (internalFilter ? `?filter=${internalFilter}` : "")
        } else {
            // placeholder
            return "/assets/img/placeholder-image.png"
        }
    }

    let resizeObserver: ResizeObserver

    function initResizeObserver(node: HTMLImageElement, { entry, src }: { entry: MedialibEntry; src: string }) {
        if (!filter && typeof ResizeObserver !== "undefined") {
            resizeObserver?.disconnect()
            resizeObserver = new ResizeObserver(() => {
                const oldWidth = parseInt(node.getAttribute("data-width")) || 0
                const newWidth = node.width

                if (oldWidth >= newWidth) return

                const newSrc = getSrcWithFilter(imgElement, entry, src)
                if (newSrc !== node.getAttribute("src")) {
                    node.setAttribute("src", newSrc)
                }
                node.setAttribute("data-width", newWidth.toString())
            })
            resizeObserver.observe(node)
        }

        return {
            destroy() {
                resizeObserver?.disconnect()
            },
        }
    }

    onDestroy(() => {
        resizeObserver?.disconnect()
    })
    let properties = {}
    if (lazy) {
        properties = { loading: "lazy" }
    }
</script>

{#if id}
    <MedialibFile {id} {noPlaceholder}>
        {#snippet childrenSnippet({ entry, src }: { entry: MedialibEntry; src: string })}
            <img
                {style}
                bind:this={imgElement}
                src={getSrcWithFilter(imgElement, entry, src)}
                alt={entry.alt || "icon"}
                data-entry-id={id}
                use:initResizeObserver={{ entry, src }}
                loading="lazy"
                {...properties}
            />
        {/snippet}
        {#snippet loadingSnippet({ entry, src }: { entry: MedialibEntry; src: string })}{/snippet}

        {#snippet notFoundSnippet()}{/snippet}
    </MedialibFile>
{/if}
