'use client';

import { useMounted } from '@/hooks';
import { useEffect, useCallback, useRef, useState, useMemo } from 'react';
import { createPortal } from 'react-dom';

type DrawerProps = {
  open?: boolean;
  inBody?: boolean;
  children?: React.ReactNode;
  position?: 'left' | 'right' | 'top' | 'bottom';
  width?: number;
  destroyOnClose?: boolean;
  zIndex?: number | string;
};

// 一个抽屉组件，支持打开关闭动画和自定义位置、宽度、z-index **无样式**
// 注意inBody为false时，需要设置父组件 position: relative;
export default function Drawer({
  open = false,
  inBody = false,
  children,
  position = 'right',
  width = 400,
  destroyOnClose = false,
  zIndex,
}: DrawerProps) {
  // shouldRender 控制是否渲染 DOM（用于 destroyOnClose）
  // 初始值应该根据 open 的初始值来设置，避免初始 open=true 时组件不渲染
  const [shouldRender, setShouldRender] = useState(open);
  const mounted = useMounted();
  const drawerRef = useRef<HTMLDivElement>(null);
  const previousState = useRef<{
    styles: React.CSSProperties;
    open: boolean;
  }>({
    styles: {},
    open: false,
  });

  // 计算隐藏时的 transform 值，需要在 useEffect 之前定义
  const hiddenTransform = useMemo(() => {
    switch (position) {
      case 'left':
        return 'translateX(-100%)';
      case 'right':
        return 'translateX(100%)';
      case 'top':
        return 'translateY(-100%)';
      case 'bottom':
        return 'translateY(100%)';
      default:
        return 'translateX(100%)';
    }
  }, [position]);

  // 当 open 变为 true 时，立即设置 shouldRender 为 true
  useEffect(() => {
    if (open) {
      setShouldRender(true);
    }
  }, [open]);

  // 处理打开/关闭动画，确保 DOM 已经挂载
  useEffect(() => {
    if (!shouldRender || !mounted || !drawerRef.current) return;

    // 判断是否是初始状态
    const isInitialState =
      previousState.current.open === false &&
      Object.keys(previousState.current.styles).length === 0;

    // 无论是初始状态还是状态变化，都需要触发动画
    if (open) {
      // 从隐藏状态变为显示状态，触发显示动画
      // 使用双重 requestAnimationFrame 确保浏览器已经渲染了初始的隐藏状态
      requestAnimationFrame(() => {
        requestAnimationFrame(() => {
          if (drawerRef.current) {
            drawerRef.current.style.transform = 'translateX(0) translateY(0)';
          }
        });
      });
    } else if (!isInitialState) {
      // 从打开状态变为关闭状态，触发隐藏动画（初始状态不需要）
      requestAnimationFrame(() => {
        if (drawerRef.current) {
          drawerRef.current.style.transform = hiddenTransform;
        }
      });
    }
  }, [open, shouldRender, mounted, hiddenTransform]);

  // 处理动画结束后的销毁
  const handleTransitionEnd = useCallback(() => {
    // 只有在关闭状态且设置了 destroyOnClose 时，才销毁 DOM
    if (!open && destroyOnClose) {
      setShouldRender(false);
    }
  }, [open, destroyOnClose, setShouldRender]);

  const positionStyles = useMemo(() => {
    switch (position) {
      case 'left':
        return {
          top: 0,
          left: 0,
          height: '100%',
          width: `${width}px`,
        };
      case 'right':
        return {
          top: 0,
          right: 0,
          height: '100%',
          width: `${width}px`,
        };
      case 'top':
        return {
          top: 0,
          left: 0,
          width: '100%',
          height: `${width}px`,
        };
      case 'bottom':
        return {
          bottom: 0,
          left: 0,
          width: '100%',
          height: `${width}px`,
        };
      default:
        return {};
    }
  }, [position, width]);

  // 根据位置计算样式
  const getPositionStyles = (): React.CSSProperties => {
    // 如果状态未改变，直接返回缓存的样式
    if (previousState.current.open === open) {
      return previousState.current.styles;
    }

    const positionType = inBody ? 'fixed' : 'absolute';

    const baseStyles: React.CSSProperties = {
      ...positionStyles,
      position: positionType,
      zIndex,
      boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
      transition: 'transform 0.3s ease-in-out',
      // 初始状态总是先设置为隐藏，然后通过 useEffect 中的动画来显示
      // 这样即使初始 open=true，也能看到从隐藏到显示的动画效果
      transform: hiddenTransform,
    };

    // 缓存当前状态
    // 注意：动画逻辑已经在 useEffect 中处理，这里只需要设置初始样式
    previousState.current = {
      styles: baseStyles,
      open,
    };
    return baseStyles;
  };

  if (!mounted || !shouldRender) return null;

  if (inBody) {
    return createPortal(
      <div
        ref={drawerRef}
        style={getPositionStyles()}
        onTransitionEnd={handleTransitionEnd}
        onClick={(e) => e.stopPropagation()}
      >
        {children}
      </div>,
      document.body
    );
  }

  return (
    <div
      ref={drawerRef}
      style={getPositionStyles()}
      onTransitionEnd={handleTransitionEnd}
      onClick={(e) => e.stopPropagation()}
    >
      {children}
    </div>
  );
}
