import { useRef, useEffect, useState, useCallback } from "react";
import styles from "./style.module.css";
import { PosterItem } from "../types";
import { IRefPhaserGame } from "../game/PhaserGame";
import { IRefPhaserGame as IRefPhaserGameTutorial } from "../tutorial-game/PhaserGame";
import { MdKeyboardArrowUp, MdKeyboardArrowDown } from "react-icons/md";
import { MAIN_BLUE } from "../styles/colors";

interface BlockSelector4Props {
    gameRef: React.RefObject<IRefPhaserGame | IRefPhaserGameTutorial>;
    staticBlock: "up" | "down";
    posterItems: PosterItem[];
    staticBlockItem: PosterItem;
    onSelectedBlockChange?: (item: PosterItem) => void;
    initialSelectedIndex?: number;
}

export default function BlockSelector4({
    gameRef,
    staticBlock,
    staticBlockItem,
    posterItems,
    onSelectedBlockChange,
    initialSelectedIndex,
}: BlockSelector4Props) {
    const containerRef = useRef<HTMLDivElement>(null);
    const scrollContainerRef = useRef<HTMLDivElement>(null);
    const staticBlockRef = useRef<HTMLDivElement>(null);
    const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
    const itemHeight = 58;

    const getInitialSelectedIndex = useCallback(() => {
        const maxIndex = Math.max(posterItems.length - 1, 0);
        const requestedIndex = initialSelectedIndex ?? Math.floor(posterItems.length / 2);
        return Math.min(Math.max(requestedIndex, 0), maxIndex);
    }, [initialSelectedIndex, posterItems.length]);

    const [selectedIndex, setSelectedIndex] = useState(getInitialSelectedIndex);

    const onBlockChange = useCallback((item: PosterItem, index: number) => {
        setSelectedIndex(index);
        onSelectedBlockChange?.(item);
        if (!gameRef.current?.scene) return;

        switch (staticBlock) {
            case "up":
                gameRef.current.scene.selectedCogClickedBlock = item;
                break;
            case "down":
                gameRef.current.scene.selectedCogNoClickBlock = item;
                break;
        }
    }, [gameRef, onSelectedBlockChange, staticBlock]);

    const scrollItemToStaticCenter = useCallback((index: number, behavior: ScrollBehavior = "auto") => {
        if (!staticBlockRef.current || !scrollContainerRef.current) return;
        const item = scrollContainerRef.current.querySelector(`[data-index="${index}"]`);
        if (!(item instanceof HTMLElement)) return;

        const staticRect = staticBlockRef.current.getBoundingClientRect();
        const itemRect = item.getBoundingClientRect();
        const staticCenterY = staticRect.top + staticRect.height / 2;
        const itemCenterY = itemRect.top + itemRect.height / 2;
        const nextScrollTop = scrollContainerRef.current.scrollTop + itemCenterY - staticCenterY;

        scrollContainerRef.current.scrollTo({
            top: Math.max(0, nextScrollTop),
            behavior,
        });
    }, []);

    useEffect(() => {
        const nextSelectedIndex = getInitialSelectedIndex();
        const animationFrame = window.requestAnimationFrame(() => {
            scrollItemToStaticCenter(nextSelectedIndex, "auto");
            if (posterItems[nextSelectedIndex]) {
                onBlockChange(posterItems[nextSelectedIndex], nextSelectedIndex);
            }
        });

        return () => {
            window.cancelAnimationFrame(animationFrame);
            if (scrollTimeoutRef.current) {
                clearTimeout(scrollTimeoutRef.current);
            }
        };
    }, [getInitialSelectedIndex, onBlockChange, posterItems, scrollItemToStaticCenter]);

    const getSnappedItem = (): { item: PosterItem, index: number } | null => {
        if (!staticBlockRef.current || !scrollContainerRef.current) return null;
        const staticRect = staticBlockRef.current.getBoundingClientRect();
        const staticCenterY = staticRect.top + staticRect.height / 2;

        const items = scrollContainerRef.current.querySelectorAll(`.${styles.carouselItem}`);
        let closestEl: Element | null = null;
        let minDist = Infinity;
        items.forEach(el => {
            const r = el.getBoundingClientRect();
            const dist = Math.abs(staticCenterY - (r.top + r.height / 2));
            if (dist < minDist) {
                minDist = dist;
                closestEl = el;
            }
        });

        if (closestEl) {
            const index = parseInt((closestEl as Element).getAttribute("data-index") || "", 10);
            return { item: posterItems[index], index };
        }

        return null;
    };

    const handleScroll = () => {
        if (scrollTimeoutRef.current) {
            clearTimeout(scrollTimeoutRef.current);
        }
        scrollTimeoutRef.current = setTimeout(() => {
            const snapped = getSnappedItem();
            if (snapped) onBlockChange(snapped.item, snapped.index);
        }, 150);
    };

    const scrollByItem = (dir: "up" | "down") => {
        const maxIndex = Math.max(posterItems.length - 1, 0);
        const nextIndex = Math.min(Math.max(selectedIndex + (dir === "up" ? -1 : 1), 0), maxIndex);
        if (nextIndex === selectedIndex || !posterItems[nextIndex]) return;
        if (scrollTimeoutRef.current) {
            clearTimeout(scrollTimeoutRef.current);
        }
        scrollItemToStaticCenter(nextIndex, "auto");
        onBlockChange(posterItems[nextIndex], nextIndex);
    };

    return (
        <div className={styles.outerContainer}>
            <button type="button" aria-label="Previous action" onClick={() => scrollByItem("up")} className={styles.upArrowContainer}>
                <MdKeyboardArrowUp color={MAIN_BLUE} size={40} />
            </button>
            <div className={styles.commandRail}>
                <div ref={staticBlockRef} className={styles.staticBlockItem}>
                    <staticBlockItem.icon className={styles.staticBlockItemIcon} />
                </div>
                <div className={styles.commandConnector} />
                <div ref={containerRef} className={styles.carouselBody}>
                    <div
                        ref={scrollContainerRef}
                        className={styles.scrollContainer}
                        onScroll={handleScroll}
                        style={{
                            overflowY: "auto",
                            paddingTop: itemHeight * 2 - 2,
                            paddingBottom: itemHeight * 2 - 2,
                        }}
                    >

                        {posterItems.map((item, index) => (
                            <div
                                key={index + item.block}
                                data-index={index}
                                className={`${styles.carouselItem} ${selectedIndex === index ? styles.carouselItemSelected : ""}`}
                                style={{ height: itemHeight }}
                            >
                                <item.icon className={styles.carouselItemIcon} />
                            </div>
                        ))}

                    </div>
                </div>
            </div>
            <button type="button" aria-label="Next action" onClick={() => scrollByItem("down")} className={styles.downArrowContainer}>
                <MdKeyboardArrowDown color={MAIN_BLUE} size={40} />
            </button>
        </div>
    );
}
