<!--
@component

Metro-like tile. Must be in a group to display correctly.
-->

<script lang="ts">
    import randomNumber from "$lib/utils/random-number";
    import { cva } from "class-variance-authority";
    import { onDestroy, onMount } from "svelte";

    /**
     * Base size of a icon in pixels.
     **/
    const ICON_BASE_SIZE = 45;

    /**
     * Icon sizes.
     */
    const ICON_SIZES = {
        small: ICON_BASE_SIZE,
        medium: ICON_BASE_SIZE * 2,
        wide: ICON_BASE_SIZE * 2,
        large: ICON_BASE_SIZE * 4,
    };

    /**
     * Base size of a page in pixels.
     */
    const PAGE_BASE_SIZE = 75;

    /**
     * Page heights.
     */
    const PAGE_HEIGHTS = {
        small: PAGE_BASE_SIZE,
        medium: PAGE_BASE_SIZE * 2,
        wide: PAGE_BASE_SIZE * 2,
        large: PAGE_BASE_SIZE * 4,
    };

    /**
     * Max scroll interval delay in milliseconds.
     */
    const SCROLL_INTERVAL_MAX = 10 * 1000;

    /**
     * Min scroll interval delay in milliseconds.
     */
    const SCROLL_INTERVAL_MIN = SCROLL_INTERVAL_MAX / 2;

    /**
     * Tile element.
     */
    let element: HTMLElement;

    /**
     * Properties.
     */
    let {
        size,
        row,
        icon,
        column,
        children,
    }: {
        /**
         * Size.
         */
        size: "small" | "medium" | "wide" | "large";

        /**
         * Row index. Must be in a small tiles.
         */
        row: number;

        /**
         * Column index. Must be in a small tiles.
         */
        column: number;

        /**
         * Icon. Must be a valid URL.
         */
        icon: string;

        /**
         * Pages.
         */
        children: () => any;
    } = $props();

    /**
     * Tile style.
     **/
    const style = cva(
        ["bg-(--tile-color)", "overflow-y-hidden", "scroll-smooth"],
        {
            variants: {
                size: {
                    small: ["row-span-1", "col-span-1"],
                    medium: ["row-span-2", "col-span-2"],
                    wide: ["row-span-2", "col-span-4"],
                    large: ["row-span-4", "col-span-4"],
                },
            },
        },
    );

    /**
     * Icon size.
     */
    const iconSize = ICON_SIZES[size];

    /**
     * Page height.
     */
    const pageHeight = PAGE_HEIGHTS[size];

    /**
     * Scroll side. Positive value is down, negative value is up.
     */
    let scrollSide = 1;

    /**
     * Get page count based on scroll height.
     */
    const getPageCount = () => Math.floor(element.scrollHeight / pageHeight);

    /**
     * Scroll between pages. Used by scroll interval.
     */
    function scrollPages() {
        if (element.clientHeight === element.scrollHeight - pageHeight) {
            scrollSide = -scrollSide;
        }

        element.scrollBy({ top: pageHeight * scrollSide });
    }

    /**
     * Scroll interval.
     */
    let scrollInterval: NodeJS.Timeout;

    onMount(() => {
        if (size === "small" || getPageCount() === 1) {
            return;
        }

        const scrollDelay = randomNumber(
            SCROLL_INTERVAL_MIN,
            SCROLL_INTERVAL_MAX,
        );

        scrollInterval = setInterval(scrollPages, scrollDelay);
    });

    onDestroy(() => {
        if (!scrollInterval) {
            return;
        }

        clearInterval(scrollInterval);
    });
</script>

<div
    class={style({ size })}
    style="
        --tile-icon: url('{icon}');
        --tile-icon-size: {iconSize}px;
        --tile-page-height: {pageHeight}px;
        --tile-name-display: {size !== 'small' ? 'inline' : 'none'};
        grid-row-start: {row};
        grid-column-start: {column};
    "
    bind:this={element}
>
    {@render children()}
</div>
