"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,
    contentClassName,
    clickOutsideClose,
    onClose,
    header,
    body,
    footer
}: {
    isOpen: boolean;
    contentClassName?: string;
    clickOutsideClose?: boolean;
    onClose: (e: boolean) => void;
    header?: React.ReactNode;
    body: React.ReactNode;
    footer?: React.ReactNode;
}) {
    // show - 显示
    // outing - 隐藏动画中
    // hidden - 隐藏
    const [rootVisible, setRootVisible] = useState<'show' | 'outing' | 'hidden'>('hidden');
    
    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 w-full bg-white transition-transform duration-300 ease-out";
    let applyClassName = "bottom-0 left-0 h-17/20";
    if(contentClassName) {
        applyClassName = contentClassName;
    }

    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.animationName === "fade-out") {
            setRootVisible('hidden');
        } 
        
    }
    // 初始化时是隐藏状态
    // fade-in的时候display block + fade-in
    // fade-out的时候需要先加fade-out 类名，动画效果结束之后才能display none 
    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={{
                        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>
    ); 
}