import { IBimComponent } from '../../types/component';
import { ThemeConfig } from '../../themes/types';
import { localeManager, t } from '../../services/locale';
import { themeManager } from '../../services/theme';
import { TreeOptions, TreeNodeConfig, TreeNodeCheckState } from './types';
import { BimTreeNode } from './tree-node';
import './index.css';

// 定义辅助事件发射器接口 (由于 BimTree 通常作为 Manager 的一部分或独立使用)
// 为了方便，这里我们假设它会被 TreeManager 管理，TreeManager 会处理事件发射
// 但 BimTree 本身也需要一个方式通知 Manager。
// 我们可以通过构造函数传入 event bus 适配器，或者直接使用 CustomEvent。
// 更好的方式：BimTree 提供 onEvent 回调。

export class BimTree implements IBimComponent {
    public element: HTMLElement;
    private contentElement: HTMLElement; // 树内容容器
    private searchInput: HTMLInputElement | null = null;
    private searchResults: HTMLElement | null = null;

    private options: TreeOptions;
    private nodeMap: Map<string, BimTreeNode> = new Map();
    private rootNodes: BimTreeNode[] = [];
    private selectedNode: BimTreeNode | null = null; // 当前选中的高亮节点

    // 订阅清理函数
    private unsubscribeLocale: (() => void) | null = null;
    private unsubscribeTheme: (() => void) | null = null;
    private clickOutsideHandler: ((e: MouseEvent) => void) | null = null;

    // 事件回调 (由 Manager 注入)
    public onNodeCheck?: (node: BimTreeNode) => void;
    public onNodeSelect?: (node: BimTreeNode) => void;
    public onNodeExpand?: (node: BimTreeNode) => void;

    constructor(options: TreeOptions) {
        this.options = {
            checkable: true,
            checkStrictly: true,
            indent: 24,
            defaultExpandAll: true,
            enableSearch: false,
            searchPlaceholder: 'tree.searchPlaceholder',
            ...options
        };
        
        // 主容器
        this.element = document.createElement('div');
        this.element.className = 'bim-tree';

        // 搜索区域
        if (this.options.enableSearch) {
            this.createSearchDOM();
        }

        // 内容容器
        this.contentElement = document.createElement('div');
        this.contentElement.className = 'bim-tree-content';
        this.element.appendChild(this.contentElement);

        // 初始化回调
        if (options.onNodeCheck) this.onNodeCheck = options.onNodeCheck;
        if (options.onNodeSelect) this.onNodeSelect = options.onNodeSelect;
        if (options.onNodeExpand) this.onNodeExpand = options.onNodeExpand;
    }

    private createSearchDOM() {
        const searchContainer = document.createElement('div');
        searchContainer.className = 'bim-tree-search';

        const wrapper = document.createElement('div');
        wrapper.className = 'bim-tree-search-wrapper';

        // 图标
        const icon = document.createElement('span');
        icon.className = 'bim-tree-search-icon';
        icon.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m21 21l-4.343-4.343m0 0A8 8 0 1 0 5.343 5.343a8 8 0 0 0 11.314 11.314"/></svg>`;
        wrapper.appendChild(icon);

        this.searchInput = document.createElement('input');
        this.searchInput.className = 'bim-tree-search-input';
        this.searchInput.type = 'text';
        this.searchInput.placeholder = t(this.options.searchPlaceholder || '搜索...');

        // 绑定输入事件
        this.searchInput.addEventListener('input', (e) => {
            const query = (e.target as HTMLInputElement).value;
            this.handleSearch(query);
        });

        wrapper.appendChild(this.searchInput);
        searchContainer.appendChild(wrapper);

        // 搜索结果容器
        this.searchResults = document.createElement('div');
        this.searchResults.className = 'bim-tree-search-results';

        searchContainer.appendChild(this.searchResults);
        this.element.appendChild(searchContainer);

        // 点击外部关闭搜索结果
        this.clickOutsideHandler = (e: MouseEvent) => {
            if (this.searchResults &&
                !this.searchResults.contains(e.target as Node) &&
                !this.searchInput?.contains(e.target as Node)) {
                this.searchResults.classList.remove('is-visible');
            }
        };
        document.addEventListener('click', this.clickOutsideHandler);
    }

    public init(): void {
        this.render();

        // 订阅系统事件
        this.unsubscribeLocale = localeManager.subscribe(() => this.setLocales());
        this.unsubscribeTheme = themeManager.subscribe((theme) => this.setTheme(theme));

        // 初始化主题
        this.setTheme(themeManager.getTheme());
    }

    /**
     * 处理搜索逻辑
     */
    private handleSearch(query: string) {
        if (!this.searchResults) return;

        if (!query.trim()) {
            this.searchResults.classList.remove('is-visible');
            this.searchResults.innerHTML = '';
            return;
        }

        const results: { node: BimTreeNode, label: string, path: string }[] = [];
        const lowerQuery = query.toLowerCase();

        this.nodeMap.forEach(node => {
            // 直接使用 config.label，不进行翻译
            const label = node.config.label;
            if (label.toLowerCase().includes(lowerQuery)) {
                results.push({
                    node,
                    label,
                    path: this.getNodePath(node)
                });
            }
        });

        this.renderSearchResults(results);
    }

    /**
     * 获取节点路径（面包屑）
     */
    private getNodePath(node: BimTreeNode): string {
        const path: string[] = [];
        let current: BimTreeNode | null = node.parent; // 从父级开始
        while (current) {
            // 直接使用 label
            path.unshift(current.config.label);
            current = current.parent;
        }
        return path.join(' > ');
    }

    /**
     * 渲染搜索结果列表
     */
    private renderSearchResults(results: { node: BimTreeNode, label: string, path: string }[]) {
        if (!this.searchResults) return;

        this.searchResults.innerHTML = '';
        if (results.length === 0) {
            const noData = document.createElement('div');
            noData.className = 'bim-tree-search-item';
            noData.style.cursor = 'default';
            noData.style.color = '#999';
            noData.textContent = 'No results';
            this.searchResults.appendChild(noData);
        } else {
            results.forEach(res => {
                const item = document.createElement('div');
                item.className = 'bim-tree-search-item';

                const title = document.createElement('span');
                title.className = 'bim-tree-search-item-title';
                title.textContent = res.label;

                const path = document.createElement('span');
                path.className = 'bim-tree-search-item-path';
                path.textContent = res.path;

                item.appendChild(title);
                if (res.path) item.appendChild(path);

                item.addEventListener('click', () => {
                    this.revealNode(res.node);
                });

                this.searchResults!.appendChild(item);
            });
        }
        this.searchResults.classList.add('is-visible');
    }

    /**
     * 定位到指定节点
     */
    public revealNode(node: BimTreeNode) {
        // 1. 关闭搜索下拉
        if (this.searchResults) {
            this.searchResults.classList.remove('is-visible');
            if (this.searchInput) this.searchInput.value = ''; // 可选：清空搜索框
        }

        // 2. 递归展开父节点
        let current = node.parent;
        while (current) {
            current.toggleExpand(true); // 强制展开
            current = current.parent;
        }

        // 3. 选中节点 (Select)
        this.handleNodeSelect(node);

        // 4. 滚动到可视区域
        setTimeout(() => {
            node.element.scrollIntoView({ behavior: 'smooth', block: 'center' });
        }, 100);
    }

    /**
     * 设置主题
     */
    public setTheme(theme: ThemeConfig): void {
        const style = this.element.style;
        style.setProperty('--bim-ui_bg_color', theme.panelBackground);
        style.setProperty('--bim-ui_text_primary', theme.textPrimary);
        style.setProperty('--bim-ui_text_secondary', theme.textSecondary || '#999');
        style.setProperty('--bim-ui_border_color', theme.border);
        style.setProperty('--bim-ui_bg_hover', theme.componentHover);
        style.setProperty('--bim-primary_color', theme.primary);
        // style.setProperty('--bim-ui_text_disabled', theme.textDisabled); // 如果 ThemeConfig 有这个字段
    }

    /**
     * 响应语言变更
     */
    public setLocales(): void {
        this.nodeMap.forEach(node => node.updateLabel());
        if (this.searchInput) {
            this.searchInput.placeholder = t(this.options.searchPlaceholder || 'tree.searchPlaceholder');
        }
    }

    public destroy(): void {
        if (this.unsubscribeLocale) {
            this.unsubscribeLocale();
            this.unsubscribeLocale = null;
        }
        if (this.unsubscribeTheme) {
            this.unsubscribeTheme();
            this.unsubscribeTheme = null;
        }
        if (this.clickOutsideHandler) {
            document.removeEventListener('click', this.clickOutsideHandler);
            this.clickOutsideHandler = null;
        }
        this.rootNodes.forEach(node => node.destroy());
        this.rootNodes = [];
        this.nodeMap.clear();
        this.element.remove();
        this.selectedNode = null;
    }

    /**
     * 核心渲染逻辑
     */
    private render(): void {
        this.contentElement.innerHTML = ''; // 清空内容区，而不是整个 element
        this.nodeMap.clear();
        this.rootNodes = [];

        this.options.data.forEach(config => {
            this.createNodeRecursively(config, null);
        });

        // 移除旧的 expandAll 调用，因为 expanded 状态已在 createNodeRecursively 中处理
    }

    /**
     * 递归创建节点
     */
    private createNodeRecursively(config: TreeNodeConfig, parent: BimTreeNode | null) {
        // 处理展开状态优先级: config.expanded > defaultExpandAll
        if (config.expanded === undefined) {
            config.expanded = this.options.defaultExpandAll;
        }

        const node = new BimTreeNode(config, this.options, {
            onExpand: (n) => { if (this.onNodeExpand) this.onNodeExpand(n); },
            onCheck: (n) => this.handleNodeCheck(n),
            onClick: (n) => this.handleNodeSelect(n)
        });

        this.nodeMap.set(config.id, node);

        if (parent) {
            parent.appendChild(node);
        } else {
            this.rootNodes.push(node);
            this.contentElement.appendChild(node.element); // 挂载到 contentElement
        }

        if (config.children && config.children.length > 0) {
            config.children.forEach(childConfig => {
                this.createNodeRecursively(childConfig, node);
            });
        }

        // 如果是初始化渲染，需要处理 checkStrictly 的向上联动（因为数据里可能只给了子节点 checked，父节点没给）
        // 这里做一个简单的后处理：如果 checkStrictly 开启，且当前节点 checked，则触发一次联动
        // 注意：这可能会导致性能问题，���化做法是在所有节点创建完后统一计算一次状态
    }

    /**
     * 处理节点选择 (高亮)
     */
    private handleNodeSelect(node: BimTreeNode) {
        // 如果之前有选中的，先取消选中
        if (this.selectedNode && this.selectedNode !== node) {
            this.selectedNode.setSelected(false);
        }

        // 设置当前为选中
        node.setSelected(true);
        this.selectedNode = node;

        // 触发外部回调
        if (this.onNodeSelect) this.onNodeSelect(node);
    }

    /**
     * 处理节点勾选逻辑 (核心算法)
     */
    private handleNodeCheck(node: BimTreeNode) {
        const isChecked = node.checkState === TreeNodeCheckState.Checked;

        // 1. 触发外部回调 (Event)
        if (this.onNodeCheck) this.onNodeCheck(node);

        // 2. 如果不联动，直接返回
        if (this.options.checkStrictly === false) return;

        // 3. 联动逻辑
        // 3.1 向下级联 (Cascade Down): 父变子全变
        const updateChildren = (n: BimTreeNode, state: TreeNodeCheckState) => {
            n.children.forEach(child => {
                if (child.config.disabled) return; // 跳过禁用节点
                child.setChecked(state, false); // 不再触发事件，只更新状态 UI
                updateChildren(child, state);
            });
        };

        // 当前节点是 Checked 或 Unchecked，子节点跟随
        if (isChecked) {
            updateChildren(node, TreeNodeCheckState.Checked);
        } else {
            updateChildren(node, TreeNodeCheckState.Unchecked);
        }

        // 3.2 向上冒泡 (Bubble Up): 子变父更新
        let current = node.parent;
        while (current) {
            if (current.config.disabled) {
                current = current.parent;
                continue;
            }

            const children = current.children;
            const allChecked = children.every(c => c.checkState === TreeNodeCheckState.Checked);
            const allUnchecked = children.every(c => c.checkState === TreeNodeCheckState.Unchecked);

            if (allChecked) {
                current.setChecked(TreeNodeCheckState.Checked, false);
            } else if (allUnchecked) {
                current.setChecked(TreeNodeCheckState.Unchecked, false);
            } else {
                current.setChecked(TreeNodeCheckState.Indeterminate, false);
            }

            current = current.parent;
        }
    }

    // ================== Public APIs ==================

    public getNode(id: string): BimTreeNode | undefined {
        return this.nodeMap.get(id);
    }

    public checkNode(id: string, checked: boolean) {
        const node = this.nodeMap.get(id);
        if (node) {
            node.setChecked(checked ? TreeNodeCheckState.Checked : TreeNodeCheckState.Unchecked, true);
            // 手动调用联动处理，因为 setChecked 的 fireEvent 只触发回调，不包含内部逻辑调用?
            // 不，我们在 createNodeRecursively 里绑定的 onCheck 就是 handleNodeCheck
            // 所以只要 fireEvent=true，就会触发 handleNodeCheck，进而触发联动。
        }
    }

    public expandAll(expanded: boolean) {
        this.nodeMap.forEach(node => node.toggleExpand(expanded));
    }

    public getCheckedNodes(includeHalfChecked: boolean = false): TreeNodeConfig[] {
        const result: TreeNodeConfig[] = [];
        this.nodeMap.forEach(node => {
            if (node.checkState === TreeNodeCheckState.Checked) {
                result.push(node.config);
            } else if (includeHalfChecked && node.checkState === TreeNodeCheckState.Indeterminate) {
                result.push(node.config);
            }
        });
        return result;
    }
}
