import { IBimComponent } from '../../types/component';
import { ThemeConfig } from '../../themes/types';
import { IRightKeyContent, RightKeyOptions } from './types';
import './index.css';

/**
 * 右键浮层容器组件 (RightKey)
 * 这是一个纯粹的定位容器，负责在屏幕指定位置显示内容。
 * 它不关心具体内容是什么，只处理定位、边界检测和关闭逻辑。
 */
export class BimRightKey implements IBimComponent {
    private element: HTMLElement;
    private content: IRightKeyContent | null = null;
    private isVisible: boolean = false;
    private onCloseCallback?: () => void;
    private options?: RightKeyOptions;
    
    private mouseDownTime: number = 0;
    private readonly CLICK_THRESHOLD: number = 200; // ms

    constructor(options?: RightKeyOptions) {
        this.options = options;
        this.element = document.createElement('div');
        this.element.className = `bim-right-key ${options?.className || ''}`;
        
        // 设置层级，默认很高以覆盖其他 UI
        if (options?.zIndex) {
            this.element.style.zIndex = options.zIndex.toString();
        }
        
        // 挂载到 body 以便进行固定定位
        document.body.appendChild(this.element);
    }

    public init(): void {
        // 绑定全局点击事件，用于实现"点击外部关闭"
        document.addEventListener('mousedown', this.handleGlobalClick);
        
        // 阻止在容器自身上触发系统默认右键菜单
        this.element.addEventListener('contextmenu', (e) => {
            e.preventDefault();
            e.stopPropagation();
        });

        // 绑定容器交互事件
        if (this.options?.container) {
            this.options.container.addEventListener('mousedown', this.handleContainerMouseDown);
            this.options.container.addEventListener('mouseup', this.handleContainerMouseUp);
            this.options.container.addEventListener('contextmenu', this.handleContainerContextMenu);
        }
    }

    public setTheme(_theme: ThemeConfig): void {
        // 容器本身通常是透明的，主题样式主要由内容组件处理
        // 如果容器需要背景色，可以在这里设置
        // 使用 _theme 前缀避免 TS 未使用变量报错
    }

    public setLocales(): void {
        // 容器不包含文本，无需处理国际化
        // 内容组件的国际化由内容组件自身处理
    }

    public destroy(): void {
        document.removeEventListener('mousedown', this.handleGlobalClick);
        
        if (this.options?.container) {
            this.options.container.removeEventListener('mousedown', this.handleContainerMouseDown);
            this.options.container.removeEventListener('mouseup', this.handleContainerMouseUp);
            this.options.container.removeEventListener('contextmenu', this.handleContainerContextMenu);
        }

        this.unmountContent();
        this.element.remove();
    }

    private handleContainerMouseDown = (e: MouseEvent): void => {
        // 记录右键按下时间 (button 2 是右键)
        if (e.button === 2) {
            this.mouseDownTime = Date.now();
        }
    };

    private handleContainerMouseUp = (e: MouseEvent): void => {
        // 只处理右键 (button 2)
        if (e.button !== 2) return;

        // 检查点击时长，如果是长按或拖拽（时间过长），则不触发回调
        const pressDuration = Date.now() - this.mouseDownTime;
        if (pressDuration > this.CLICK_THRESHOLD) {
            return;
        }

        // 触发有效右键回调
        if (this.options?.onContext) {
            this.options.onContext(e);
        }
    };

    private handleContainerContextMenu = (e: MouseEvent): void => {
        // 阻止浏览器默认的右键菜单
        // 真正的菜单触发逻辑已移至 mouseup，这里只负责拦截默认行为
        e.preventDefault();
    };

    /**
     * 设置关闭时的回调函数
     * 通常用于通知 Manager 状态变更
     */
    public setOnClose(callback: () => void): void {
        this.onCloseCallback = callback;
    }

    /**
     * 挂载内容组件
     * @param content 实现了 IRightKeyContent 接口的组件实例
     */
    public mount(content: IRightKeyContent): void {
        // 先卸载旧内容，防止内存泄漏
        this.unmountContent();
        
        this.content = content;
        this.element.appendChild(content.getElement());
    }

    /**
     * 卸载当前内容
     */
    public unmountContent(): void {
        if (this.content) {
            this.content.destroy(); // 重要：调用组件销毁方法清理���源
            this.element.innerHTML = '';
            this.content = null;
        }
    }

    /**
     * 在指定位置显示容器
     * 包含智能边界检测逻辑，防止溢出屏幕
     * @param x 目标 X 坐标 (通常是鼠标点击位置)
     * @param y 目标 Y 坐标
     */
    public show(x: number, y: number): void {
        this.element.classList.add('visible');
        this.isVisible = true;

        // 1. 先定位到目标位置，以便测量尺寸
        this.element.style.left = `${x}px`;
        this.element.style.top = `${y}px`;

        // 2. 获取容器尺寸和视口尺寸
        const rect = this.element.getBoundingClientRect();
        const viewportWidth = window.innerWidth;
        const viewportHeight = window.innerHeight;

        let newX = x;
        let newY = y;

        // 3. 水平方向边界检测：如果溢出右边界，则向左对齐
        if (x + rect.width > viewportWidth) {
            newX = x - rect.width;
        }
        
        // 4. 垂直方向边界检测：如果溢出下边界，则向上对齐
        if (y + rect.height > viewportHeight) {
            newY = y - rect.height;
        }

        // 5. 应用修正后的坐标
        this.element.style.left = `${newX}px`;
        this.element.style.top = `${newY}px`;
    }

    /**
     * 隐藏容器
     */
    public hide(): void {
        this.element.classList.remove('visible');
        this.isVisible = false;
        
        // 为了状态重置，通常隐藏时也卸载内容
        this.unmountContent(); 
        
        if (this.onCloseCallback) {
            this.onCloseCallback();
        }
    }

    /**
     * 处理全局点击事件
     * 用于检测是否点击了容器外部
     */
    private handleGlobalClick = (e: MouseEvent): void => {
        if (!this.isVisible) return;
        
        // 如果点击的是容器内部，不做处理
        if (this.element.contains(e.target as Node)) {
            return;
        }

        // 点击外部，关闭容器
        this.hide();
    };
}
