import { Node, mergeAttributes } from '@tiptap/core'
import { ReactNodeViewRenderer, NodeViewWrapper, ReactNodeViewProps } from '@tiptap/react'
import { motion, AnimatePresence } from 'framer-motion'
import { useState, useRef, useEffect } from 'react'
import { Check, CircleUserRound } from 'lucide-react'
import { ScriptRoleEntity } from '@/app/service/domain/Entities';

interface CharacterTokenOptions {
  roles?: ScriptRoleEntity[];
}

export function CharacterToken(props: ReactNodeViewProps) {
  const [showRoleList, setShowRoleList] = useState(false);
  const [listPosition, setListPosition] = useState({ top: 0, left: 0 });
  const { name } = props.node.attrs as ScriptRoleEntity;
  const extension = props.extension as Node<CharacterTokenOptions>;
  const roles = extension.options.roles || [];
  
  const tokenRef = useRef<HTMLSpanElement>(null);
  const listRef = useRef<HTMLDivElement>(null);

  // 计算下拉列表的位置
  const updateListPosition = () => {
    if (!tokenRef.current || !listRef.current) return;

    const tokenRect = tokenRef.current.getBoundingClientRect();
    const listRect = listRef.current.getBoundingClientRect();
    const viewportHeight = window.innerHeight;
    const viewportWidth = window.innerWidth;

    // 计算理想的顶部位置（在token下方）
    let top = tokenRect.bottom + 8; // 8px 间距
    let left = tokenRect.left;

    // 检查是否超出底部
    if (top + listRect.height > viewportHeight) {
      // 如果超出底部，将列表显示在token上方
      top = tokenRect.top - listRect.height - 8;
    }

    // 检查是否超出右侧
    if (left + listRect.width > viewportWidth) {
      // 如果超出右侧，将列表右对齐
      left = viewportWidth - listRect.width - 8;
    }

    // 确保不会超出左侧
    left = Math.max(8, left);

    setListPosition({ top, left });
  };

  // 监听窗口大小变化
  useEffect(() => {
    if (showRoleList) {
      updateListPosition();
      window.addEventListener('resize', updateListPosition);
      window.addEventListener('scroll', updateListPosition);

      return () => {
        window.removeEventListener('resize', updateListPosition);
        window.removeEventListener('scroll', updateListPosition);
      };
    }
  }, [showRoleList]);

  const handleRoleSelect = (role: ScriptRoleEntity) => {
    const { editor } = props;
    const pos = props.getPos();
    
    if (typeof pos === 'number') {
      const { tr } = editor.state;
      tr.setNodeMarkup(pos, undefined, {
        ...props.node.attrs,
        id: role.id,
        name: role.name,
        image_url: role.image_url,
      });
      editor.view.dispatch(tr);
    }
    
    setShowRoleList(false);
  }

  return (
    <NodeViewWrapper
      as="span"
      ref={tokenRef}
      data-alt="character-token"
      contentEditable={false}
      className="relative inline text-blue-400 cursor-pointer hover:text-blue-300 transition-colors duration-200"
      onMouseLeave={() => setShowRoleList(false)}
      onMouseEnter={() => {
        setShowRoleList(true);
        // 延迟一帧执行位置更新，确保列表已渲染
        requestAnimationFrame(updateListPosition);
      }}
    >
      {name}

      <AnimatePresence>
        {showRoleList && (
          <motion.div
            data-alt="role-list"
            initial={{ opacity: 0, y: 4 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: 4 }}
            transition={{ duration: 0.2 }}
            ref={listRef}
            className="fixed w-64 rounded-lg backdrop-blur-md bg-white/10 border border-white/20 p-2 z-[51]"
            style={{
              top: listPosition.top,
              left: listPosition.left
            }}
          >
            <div className="space-y-1">
              {roles.map((role) => {
                const isSelected = role.name.toLowerCase() === name.toLowerCase();
                return (
                  <div
                    key={role.name}
                    data-alt="role-item"
                    className={`flex items-center gap-3 p-2 rounded-lg cursor-pointer transition-colors duration-200
                      ${isSelected ? 'bg-blue-500/20 text-blue-400' : 'hover:bg-white/5 text-gray-200'}`}
                    onClick={() => handleRoleSelect(role)}
                  >
                    <div className="relative">
                      <img
                        src={role.image_url}
                        alt={role.name}
                        className={`w-10 h-10 rounded-full border transition-all duration-200
                          ${isSelected ? 'border-blue-400 border-2' : 'border-white/20'}`}
                      />
                      {isSelected && (
                        <div className="absolute -top-1 -right-1 bg-blue-500 rounded-full p-0.5">
                          <Check className="w-3 h-3 text-white" />
                        </div>
                      )}
                    </div>
                    <span className="flex-1">{role.name}</span>
                  </div>
                );
              })}

              {/* 旁白 */}
              <div
                data-alt="role-item"
                className={`flex items-center gap-3 p-2 rounded-lg cursor-pointer transition-colors duration-200
                  ${name === 'Voiceover' ? 'bg-blue-500/20 text-blue-400' : 'hover:bg-white/5 text-gray-200'}`}
                onClick={() => handleRoleSelect({ name: 'Voiceover', image_url: '', id: 'voiceover' } as ScriptRoleEntity)}
              >
                <div className="relative">
                  <CircleUserRound
                    className={`w-10 h-10 rounded-full border transition-all duration-200`}
                  />
                  {name === 'Voiceover' && (
                    <div className="absolute -top-1 -right-1 bg-blue-500 rounded-full p-0.5">
                      <Check className="w-3 h-3 text-white" />
                    </div>
                  )}
                </div>
                <span className="flex-1">Voiceover</span>
              </div>
            </div>
          </motion.div>
        )}
      </AnimatePresence>
    </NodeViewWrapper>
  )
}

export const CharacterTokenExtension = Node.create<CharacterTokenOptions>({
  name: 'characterToken',
  group: 'inline',
  inline: true,
  atom: true,

  addOptions() {
    return {
      roles: [],
    }
  },

  addAttributes() {
    return {
      id: { default: null },
      name: { default: '' },
      gender: { default: '' },
      age: { default: '' },
      avatar: { default: '' },
    };
  },

  parseHTML() {
    return [{ tag: 'character-token' }];
  },

  renderHTML({ HTMLAttributes }) {
    return ['character-token', mergeAttributes(HTMLAttributes)];
  },

  addNodeView() {
    return ReactNodeViewRenderer(CharacterToken);
  },
});