"use client";

import clsx from "clsx";
import { useState, useLayoutEffect, useRef } from "react";
import Portal from "@/components/common/portal/Portal";

/**
 * 为了弹窗里的表单校验开发整个组件：
 * 当弹窗关闭，校验弹窗里的表单时要保证弹窗里的表单元素还存在文档流中，所以这个组件采用display block/none 来控制弹窗的显示和隐藏 
 */
export default function CommonModal({ 
    isOpen,
    destroyOnClose = false,
    contentClassName,
    contentStyle = {},
    clickOutsideClose,
    onClose,
    animationEndCallback = () => {},
    header,
    body,
    footer
}: {
    isOpen: boolean;
    destroyOnClose?: boolean;
    contentClassName?: string;
    contentStyle?: React.CSSProperties;
    clickOutsideClose?: boolean;
    onClose: (e: boolean) => void;
    animationEndCallback?: (flag: string) => void; 
    header?: React.ReactNode;
    body: React.ReactNode;
    footer?: React.ReactNode;
}) {
    // show - 显示
    // outing - 隐藏动画中
    // hidden - 隐藏
    const [rootVisible, setRootVisible] = useState<'show' | 'outing' | 'hidden'>('hidden');
    const [mounted, setMounted] = useState(false);
    
    const cssInit = useRef(false);
    const rootRef = useRef<HTMLDivElement>(null);
    const footerRef = useRef<HTMLDivElement>(null);
    const headerRef = useRef<HTMLDivElement>(null);
 
    const [rootPddingBottom, setRootPddingBottom] = useState(0);
    const [rootPddingTop, setRootPddingTop] = useState(0);

    const baseClassNname = "absolute box-border transition-transform duration-300 ease-out";
    let applyClassName = "bottom-0 left-0 h-17/20 w-full bg-white rounded-t-xl";
    if(contentClassName) {
        applyClassName = contentClassName;
    }

    useLayoutEffect(() => {
        const original = document.documentElement.style.overflow;
        if(isOpen){
            // destroy模式重新创建DOM
            if(destroyOnClose){
                // eslint-disable-next-line react-hooks/set-state-in-effect
                setMounted(true);
            }
            document.documentElement.style.overflow = "hidden";
            requestAnimationFrame(()=>{
                setRootVisible("show");
            });
        }else{
            document.documentElement.style.overflow = "";
            if(destroyOnClose){
                // 先播放关闭动画
                if(mounted){
                    // eslint-disable-next-line react-hooks/set-state-in-effect
                    setRootVisible("outing");
                }
            }else{
                // 保留DOM
                if(cssInit.current){
                    // eslint-disable-next-line react-hooks/set-state-in-effect
                    setRootVisible("outing");
                }
            }

        }
        return ()=>{ document.documentElement.style.overflow = original; };
    },[isOpen, destroyOnClose, mounted]);

    // useLayoutEffect(() => {
    //     const original = document.documentElement.style.overflow;
    //     if(isOpen) {
    //         document.documentElement.style.overflow = "hidden";
    //     } else {
    //         document.documentElement.style.overflow = "";
    //     }
    //     // intent: 为了实现关闭时也有动画效果，告诉eslint忽略这个错误
    //     if(isOpen) {
    //         // eslint-disable-next-line react-hooks/set-state-in-effect
    //         setRootVisible('show');
    //     } else {
    //         if(cssInit.current) {
    //             // eslint-disable-next-line react-hooks/set-state-in-effect
    //             setRootVisible('outing');
    //         }
            
    //     }

    //     return () => { document.documentElement.style.overflow = original; };
    // },[isOpen]);
    // 当弹窗完全显示后计算 footer 高度
    useLayoutEffect(() => {
        if (rootVisible === 'show' && !cssInit.current && footerRef.current && headerRef.current) {
            const footerHeight = footerRef.current.getBoundingClientRect().height;
            const headerHeight = headerRef.current.getBoundingClientRect().height;
            setRootPddingBottom(footerHeight);
            setRootPddingTop(headerHeight);
            cssInit.current = true;
        }
    }, [rootVisible]);
    const rootClick = (e: React.MouseEvent) => {
        e.stopPropagation();
        if(clickOutsideClose) {
            onClose(false);
        }  
    }
    // 如果是关闭，动画结束之后才隐藏
    const handlerAnimationEnd = (e: React.AnimationEvent<HTMLDivElement>) => {
        // 如果子元素上也有自己的动画效果，也会触发父元素的动画事件
        if (e.target !== e.currentTarget) return;
        if(e.animationName === "fade-out") {
            setRootVisible('hidden');
            if(destroyOnClose){
                setMounted(false);
                cssInit.current=false;
            }
            animationEndCallback('close');
        } else {
            animationEndCallback('show');
        }
    }
    // 初始化时是隐藏状态
    // fade-in的时候display block + fade-in
    // fade-out的时候需要先加fade-out 类名，动画效果结束之后才能display none 
    if(destroyOnClose && !mounted){
        return null;
    }
    return (
        <Portal>
            <div 
                ref={rootRef} 
                className={clsx("w-full h-full backdrop-blur-md backdrop-saturate-150 bg-black/30 fixed inset-0 z-50 transition-all ease-in-out",{
                    "block fade-in": rootVisible === "show",
                    "hidden": rootVisible === "hidden",
                    "fade-out": rootVisible === "outing"
                })}
                onAnimationEnd={handlerAnimationEnd}
                onClick={rootClick}
            >
                <div 
                    className={clsx(baseClassNname,applyClassName,
                        {
                            "slide-bottom-in": rootVisible === "show",
                            "slide-bottom-out": rootVisible === "outing",
                        }
                    )}
                    style={{
                        ...contentStyle,
                        paddingTop: rootPddingTop,
                        paddingBottom: rootPddingBottom
                    }}
                >
                    <div ref={headerRef} className="w-full box-border absolute left-0 top-0">
                        {header && header}
                    </div>
                    
                    <div className="w-full box-border h-full overflow-y-auto relative">
                        
                        {body}
                        
                    </div>

                    <div ref={footerRef} className={clsx("w-full box-border absolute bottom-0 left-0",{
                        "border-t border-gray-200": footer !==null && footer !== undefined
                    })}>
                        {footer && footer}
                    </div>
                </div>
                
            </div>
        </Portal>
    ); 
}