import { Link, useLocation } from "react-router-dom";
import { Swiper, SwiperSlide } from "swiper/react";
import { Autoplay, EffectFade } from "swiper/modules";
import type { Swiper as SwiperType } from "swiper";
import "swiper/css";
import "swiper/css/effect-fade";
import styles from "./Banner.module.css";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useStore } from "@/store";
import type { BannerConfig, NavItem, NavChild } from "@/type";
import ScrollReveal from "@/components/ScrollReveal";

const FALLBACK_GRADIENT = "linear-gradient(135deg, #1a2a4a 0%, #2d4a7c 100%)";

const VIDEO_EXT = ["mp4", "webm", "ogg"];

function mediaExtension(url: string) {
    const path = url.split("?")[0] ?? "";
    return path.split(".").pop()?.toLowerCase() ?? "";
}

function isVideoUrl(url: string) {
    return VIDEO_EXT.includes(mediaExtension(url));
}

function BannerSlideVideo({
    src,
    active,
    onEnded,
    className,
}: {
    src: string;
    active: boolean;
    onEnded: () => void;
    className: string;
}) {
    const ref = useRef<HTMLVideoElement>(null);
    useEffect(() => {
        const v = ref.current;
        if (!v) return;
        if (active) {
            v.currentTime = 0;
            void v.play().catch(() => { });
        } else {
            v.pause();
        }
    }, [active, src]);
    return (
        <video ref={ref} src={src} className={className} muted playsInline onEnded={onEnded} />
    );
}

export type { BannerConfig } from "@/type";

type Props = {
    title: string;
    subtitle?: string;
    desc?: string;
    content?: string;
    largedesc?: string;
    titleSize?: "large" | "medium" | string;
    backgroundImage: string | string[];
    icon?: string;
};

export default function Banner({
    title,
    subtitle,
    desc,
    content,
    largedesc,
    titleSize = "large",
    backgroundImage,
    icon
}: Props) {
    const appConfig = useStore((s) => s.appConfig);
    const navItems = appConfig?.navItems ?? [];

    const location = useLocation();
    const images = Array.isArray(backgroundImage) ? backgroundImage : [backgroundImage];
    const isCarousel = images.length > 1;
    const descText = desc ?? content;


    const notShowBreadcrumbPaths = ["/"];
    const breadcrumbItems = useMemo(() => {
        const segments = location.pathname.split("/").filter((s) => s !== "");
        if (segments.length === 0) {
            return [{ label: "首页", to: "/" }];
        }
        const paths: string[] = [];
        for (let i = 0; i < segments.length; i++) {
            paths.push((paths[i - 1] ?? "") + "/" + segments[i]);
        }
        const getLabelByPath = (path: string): string => {
            if (path === "/") return navItems.find((n: NavItem) => n.path === "/")?.label ?? "首页";
            const top = navItems.find((n: NavItem) => n.path === path);
            if (top) return top.label;
            for (const item of navItems) {
                const child = item.children?.find((c: NavChild) => c.path === path);
                if (child) return child.label;
            }
            const last = path.split("/").pop() ?? path;
            return title;
        };
        const items = paths.map((path) => ({
            label: getLabelByPath(path),
            to: path,
        }));
        items.unshift({
            label: navItems.find((n: NavItem) => n.path === "/")?.label ?? "首页",
            to: "/",
        });
        return items;
    }, [location.pathname, navItems]);

    const heroContent = (
        <div className={styles.heroContent} style={{ gap: "1.875rem" }}>
            <ScrollReveal preset="slideUp">
                {icon ? <img src={icon} alt="" className={styles.heroIcon} />
                    :
                    <h1 className={`${styles.heroTitle} ${titleSize === "medium" ? styles.heroTitleMedium : ""}`}>{title}</h1>
                }
            </ScrollReveal>
            {subtitle && <ScrollReveal preset="slideUp" delay={0.2}>
                <h2 className={styles.heroSubtitle}>{subtitle}</h2>
            </ScrollReveal>}
            {descText && <ScrollReveal preset="slideUp" delay={0.2}>
                <p className={styles.heroDesc}>{descText}</p>
            </ScrollReveal>}
            {largedesc && <ScrollReveal preset="slideUp" delay={0.2}>
                <p className={styles.heroLargeDesc}>{largedesc}</p>
            </ScrollReveal>}
            <ScrollReveal preset="fadeIn" delay={0.2}>
                <div className={styles.breadcrumb}>
                    {!notShowBreadcrumbPaths.includes(location.pathname) &&
                        (breadcrumbItems ?? []).map((item, i) => (
                            <span key={i}>
                                {i > 0 && <span>{" > "}</span>}
                                {item.to ? <Link to={item.to}>{item.label}</Link> : <span>{item.label}</span>}
                            </span>
                        ))}
                </div>
            </ScrollReveal>
        </div>
    );

    const swiperRef = useRef<SwiperType | null>(null);
    const [carouselRealIndex, setCarouselRealIndex] = useState(0);

    const syncAutoplayForMedia = useCallback((swiper: SwiperType, urls: string[]) => {
        const idx = swiper.realIndex;
        const url = urls[idx];
        if (url && isVideoUrl(url)) {
            swiper.autoplay?.stop();
        } else {
            swiper.autoplay?.start();
        }
    }, []);

    const handleVideoEnded = useCallback(() => {
        swiperRef.current?.slideNext();
    }, []);

    return (
        <section
            className={styles.hero}
            style={
                isCarousel
                    ? undefined
                    : { backgroundImage: `url(${images[0]}), ${FALLBACK_GRADIENT}` }
            }
        >
            {isCarousel && (
                <Swiper
                    className={styles.bgSwiper}
                    modules={[Autoplay, EffectFade]}
                    effect="slide"
                    autoplay={{ delay: 5000, disableOnInteraction: true }}
                    allowTouchMove={false}
                    slidesPerView={1}
                    loop={true}
                    onSwiper={(swiper: SwiperType) => {
                        swiperRef.current = swiper;
                        setCarouselRealIndex(swiper.realIndex);
                        syncAutoplayForMedia(swiper, images);
                    }}
                    onSlideChange={(swiper: SwiperType) => {
                        setCarouselRealIndex(swiper.realIndex);
                        syncAutoplayForMedia(swiper, images);
                    }}
                >
                    {images.map((img, i) => (
                        <SwiperSlide key={i}>
                            {isVideoUrl(img) ? (
                                <BannerSlideVideo
                                    src={img}
                                    active={carouselRealIndex === i}
                                    onEnded={handleVideoEnded}
                                    className={styles.bgVideo}
                                />
                            ) : (
                                <div
                                    className={styles.bgSlide}
                                    style={{
                                        backgroundImage: `url(${img}), ${FALLBACK_GRADIENT}`,
                                    }}
                                />
                            )}
                        </SwiperSlide>
                    ))}
                </Swiper>
            )}
            {!isCarousel && isVideoUrl(images[0]) && (
                <video
                    src={images[0]}
                    className={styles.bgVideo}
                    autoPlay
                    muted
                    loop
                    playsInline
                />
            )}
            <div className={styles.heroOverlay} />
            {heroContent}
        </section>
    );
}
