// react
import React, { useCallback, useEffect, useRef, useState } from "react";
// third-party
import classNames from "classnames";
import { useRouter } from "next/router";
import PhotoSwipe from "photoswipe";
import PhotoSwipeUIDefault from "photoswipe/dist/photoswipe-ui-default";
import Slick from "react-slick";
// application
import AppImage from "~/components/shared/AppImage";
import AppLink from "~/components/shared/AppLink";
import AppSlick, { ISlickProps } from "~/components/shared/AppSlick";
import { baseUrl } from "~/services/utils";
import { useDirection } from "~/services/i18n/hooks";
import { ZoomIn24Svg } from "~/svg";

type CreateGalleryFn = (
    images: PhotoSwipe.Item[],
    options: PhotoSwipe.Options,
) => PhotoSwipe<PhotoSwipeUIDefault.Options>;

export type IProductGalleryLayout = "product-sidebar" | "product-full" | "quickview";

interface Props extends React.HTMLAttributes<HTMLElement> {
    images: string[];
    layout: IProductGalleryLayout;
}

const slickSettingsFeatured = {
    dots: false,
    arrows: false,
    infinite: false,
    speed: 400,
    slidesToShow: 1,
    slidesToScroll: 1,
};

const slickSettingsThumbnails: Record<IProductGalleryLayout, ISlickProps> = {
    "product-sidebar": {
        dots: false,
        arrows: false,
        infinite: false,
        speed: 400,
        slidesToShow: 8,
        slidesToScroll: 1,
        responsive: [
            { breakpoint: 1399, settings: { slidesToShow: 6 } },
            { breakpoint: 1199, settings: { slidesToShow: 8 } },
            { breakpoint: 991, settings: { slidesToShow: 8 } },
            { breakpoint: 767, settings: { slidesToShow: 6 } },
            { breakpoint: 575, settings: { slidesToShow: 5 } },
            { breakpoint: 419, settings: { slidesToShow: 4 } },
        ],
    },
    "product-full": {
        dots: false,
        arrows: false,
        infinite: false,
        speed: 400,
        slidesToShow: 6,
        slidesToScroll: 1,
        responsive: [
            { breakpoint: 1399, settings: { slidesToShow: 5 } },
            { breakpoint: 1199, settings: { slidesToShow: 7 } },
            { breakpoint: 991, settings: { slidesToShow: 5 } },
            { breakpoint: 767, settings: { slidesToShow: 6 } },
            { breakpoint: 575, settings: { slidesToShow: 5 } },
            { breakpoint: 419, settings: { slidesToShow: 4 } },
        ],
    },
    quickview: {
        dots: false,
        arrows: false,
        infinite: false,
        speed: 400,
        slidesToShow: 5,
        slidesToScroll: 1,
        responsive: [
            { breakpoint: 991, settings: { slidesToShow: 6 } },
            { breakpoint: 519, settings: { slidesToShow: 5 } },
            { breakpoint: 439, settings: { slidesToShow: 4 } },
            { breakpoint: 339, settings: { slidesToShow: 3 } },
        ],
    },
};

function ProductGallery(props: Props) {
    const { images, layout, className, ...rootProps } = props;
    const router = useRouter();
    const direction = useDirection();
    const [state, setState] = useState({ currentIndex: 0, transition: false });
    const imagesRefs = useRef<Array<HTMLImageElement | null>>([]);
    const slickFeaturedRef = useRef<Slick>(null);
    const createGalleryRef = useRef<Promise<CreateGalleryFn> | null>(null);
    const galleryRef = useRef<PhotoSwipe<PhotoSwipeUIDefault.Options> | null>(null);
    const getIndexDependOnDirRef = useRef<((index: number) => number) | null>(null);
    const unmountedRef = useRef(false);

    const getIndexDependOnDir = useCallback(
        (index: number) => {
            // we need to invert index id direction === 'rtl' due to react-slick bug
            if (direction === "rtl") {
                return images.length - 1 - index;
            }

            return index;
        },
        [direction, images],
    );

    const openPhotoswipe = (index: number) => {
        if (!createGalleryRef.current) {
            return;
        }

        const items = imagesRefs.current.map((tag, index) => {
            if (!tag) {
                throw Error("Image ref is null");
            }

            const width = (tag.dataset.width ? parseFloat(tag.dataset.width) : null) || tag.naturalWidth;
            const height = (tag.dataset.height ? parseFloat(tag.dataset.height) : null) || tag.naturalHeight;

            return {
                src: baseUrl(images[index]),
                msrc: baseUrl(images[index]),
                w: width,
                h: height,
            };
        });

        if (direction === "rtl") {
            items.reverse();
        }

        // noinspection JSUnusedGlobalSymbols
        const options: PhotoSwipe.Options = {
            getThumbBoundsFn: (index) => {
                // IMPORTANT: Inside this function, we can use variables and functions only through ref.
                if (!getIndexDependOnDirRef.current) {
                    return { x: 0, y: 0, w: 0 };
                }

                const dirDependentIndex = getIndexDependOnDirRef.current(index);
                const tag = imagesRefs.current[dirDependentIndex];

                if (!tag) {
                    return { x: 0, y: 0, w: 0 };
                }

                const width = tag.naturalWidth;
                const height = tag.naturalHeight;
                const rect = tag.getBoundingClientRect();
                const ration = Math.min(rect.width / width, rect.height / height);
                const fitWidth = width * ration;
                const fitHeight = height * ration;

                return {
                    x: rect.left + (rect.width - fitWidth) / 2 + window.pageXOffset,
                    y: rect.top + (rect.height - fitHeight) / 2 + window.pageYOffset,
                    w: fitWidth,
                };
            },
            index: getIndexDependOnDir(index),
            bgOpacity: 0.9,
            history: false,
        };

        createGalleryRef.current.then((createGallery) => {
            // IMPORTANT: Inside this function, we can use variables and functions only through ref.

            if (unmountedRef.current) {
                return;
            }

            galleryRef.current = createGallery(items, options);
            galleryRef.current.listen("beforeChange", () => {
                if (galleryRef.current && slickFeaturedRef.current) {
                    slickFeaturedRef.current.slickGoTo(galleryRef.current.getCurrentIndex(), true);
                }
            });
            galleryRef.current.listen("destroy", () => {
                galleryRef.current = null;
            });

            galleryRef.current.init();
        });
    };

    const handleFeaturedClick = (event: React.MouseEvent, index: number) => {
        if (!createGalleryRef.current || layout === "quickview") {
            return;
        }

        event.preventDefault();

        openPhotoswipe(index);
    };

    const handleThumbnailClick = (index: number) => {
        if (state.transition) {
            return;
        }

        setState((prev) => ({ ...prev, currentIndex: index }));

        if (slickFeaturedRef.current) {
            slickFeaturedRef.current.slickGoTo(getIndexDependOnDir(index));
        }
    };

    const handleFeaturedBeforeChange: ISlickProps["beforeChange"] = (oldIndex, newIndex) => {
        setState((prev) => ({
            ...prev,
            currentIndex: getIndexDependOnDir(newIndex),
            transition: true,
        }));
    };

    const handleFeaturedAfterChange: ISlickProps["afterChange"] = (index) => {
        setState((prev) => ({
            ...prev,
            currentIndex: getIndexDependOnDir(index),
            transition: false,
        }));
    };

    const handleZoomButtonClick = () => {
        openPhotoswipe(state.currentIndex);
    };

    // componentDidMount
    useEffect(() => {
        createGalleryRef.current = import("~/services/photoswipe").then((module) => module.default);
    }, []);

    // componentWillUnmount
    useEffect(() => {
        unmountedRef.current = false;

        return () => {
            if (galleryRef.current) {
                galleryRef.current.destroy();
            }

            unmountedRef.current = true;
        };
    }, []);

    useEffect(() => {
        // this is necessary to reset the transition state,
        // because when the direction changes, the afterChange event does not fire
        const timer = setTimeout(() => {
            setState((prev) => ({ ...prev, transition: false }));
        }, 0);

        return () => {
            clearTimeout(timer);
        };
    }, [direction]);

    useEffect(() => {
        getIndexDependOnDirRef.current = getIndexDependOnDir;
    }, [getIndexDependOnDir]);

    const rootClasses = classNames("product-gallery", `product-gallery--layout--${layout}`, className);

    return (
        <div className={rootClasses} data-layout={layout} {...rootProps}>
            {/* Botones fuera del contenedor de la imagen */}
            <div className="product-gallery__controls" style={{
                display: 'flex',
                justifyContent: 'space-between',
                alignItems: 'center',
                marginBottom: '10px',
                position: 'relative'
            }}>
                <button
                    type="button"
                    className="btn btn-sm custom-btn-back product-gallery__back d-flex align-items-center"
                    onClick={() => router.back()}
                    style={{ backgroundColor: "red", color: "white" }}
                >
                    <svg
                        className="mr-2"
                        xmlns="http://www.w3.org/2000/svg"
                        width="16"
                        height="16"
                        fill="currentColor"
                        viewBox="0 0 16 16"
                    >
                        <path
                            fillRule="evenodd"
                            d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"
                        />
                    </svg>
                    Volver
                </button>
                <button 
                    type="button" 
                    className="product-gallery__zoom" 
                    onClick={handleZoomButtonClick}
                    style={{
                        position: 'relative',
                        top: 'auto',
                        right: 'auto',
                        marginLeft: 'auto'
                    }}
                >
                    <ZoomIn24Svg />
                </button>
            </div>
            
            <div className="product-gallery__featured ">
                <AppSlick
                    ref={slickFeaturedRef}
                    {...slickSettingsFeatured}
                    beforeChange={handleFeaturedBeforeChange}
                    afterChange={handleFeaturedAfterChange}
                >
                    {images.map((image, index) => (
                        <div key={index} className="image image--type--product">
                            <AppLink
                                href={image}
                                anchor
                                className="image__body"
                                target="_blank"
                                rel="noreferrer"
                                onClick={(event: React.MouseEvent) => handleFeaturedClick(event, index)}
                            >
                                <AppImage
                                    className="image__tag product_gallery_image"
                                    src={image}
                                    ref={(element) => {
                                        imagesRefs.current[index] = element;
                                    }}
                                    data-width="700"
                                    data-height="700"
                                />
                            </AppLink>
                        </div>
                    ))}
                </AppSlick>
                {/* Barra con www.monticars.com debajo de la imagen principal */}
                <div className="product-gallery__banner" style={{
                    width: '100%',
                    height: '50px',
                    background: 'linear-gradient(to bottom, #8B0000 0%, #8B0000 50%, #000080 50%, #000080 100%)',
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    position: 'relative',
                    overflow: 'hidden'
                }}>
                    <div style={{
                        position: 'absolute',
                        top: 0,
                        left: 0,
                        right: 0,
                        bottom: 0,
                        background: `
                            radial-gradient(circle at 20% 30%, rgba(139, 0, 0, 0.3) 0%, transparent 50%),
                            radial-gradient(circle at 80% 70%, rgba(0, 0, 128, 0.3) 0%, transparent 50%)
                        `,
                        pointerEvents: 'none'
                    }} />
                    <span style={{
                        color: '#FFFFFF',
                        fontSize: '18px',
                        fontWeight: 'bold',
                        textShadow: '2px 2px 4px rgba(0, 0, 0, 0.5)',
                        position: 'relative',
                        zIndex: 1,
                        letterSpacing: '1px'
                    }}>
                        www.monticars.com
                    </span>
                </div>
            </div>
            <div className="product-gallery__thumbnails">
                <AppSlick {...slickSettingsThumbnails[layout]}>
                    {images.map((image, index) => (
                        <button
                            type="button"
                            key={index}
                            className={classNames("product-gallery__thumbnails-item", "image image--type--product", {
                                "product-gallery__thumbnails-item--active": index === state.currentIndex,
                            })}
                            onClick={() => handleThumbnailClick(index)}
                        >
                            <div className="image__body">
                                <AppImage className="image__tag product_gallery_image" src={image} />
                            </div>
                        </button>
                    ))}
                </AppSlick>
            </div>
        </div>
    );
}

export default React.memo(ProductGallery);
