import { Component } from "cc";

const autoBindMap = new WeakMap<any, { [key: string]: { type?: any } }>();

/**
 * 自动绑定与变量同名的子节点。
 * 装饰器不传参数（组件）则绑定节点，传了组件则绑定节点上的组件。
 * 如果传了组件，则传入的组件一定要和变量类型一致，否则绑定会失败。
 * 记得在组件的onLoad函数调用initAutoBindings(this)
 */
export function auto(target: any, propertyKey: string): void;
export function auto<T extends Component>(componentType: { new(): T }): (target: any, propertyKey: string) => void;
export function auto<T extends Component>(componentTypeOrTarget?: { new(): T } | any, propertyKey?: string) {
    if (typeof componentTypeOrTarget === 'function') {
        return function (target: any, propertyKey: string) {
            if (!autoBindMap.has(target)) {
                autoBindMap.set(target, {});
            }
            autoBindMap.get(target)![propertyKey] = { type: componentTypeOrTarget };
        };
    } else {
        const target = componentTypeOrTarget;
        if (!autoBindMap.has(target)) {
            autoBindMap.set(target, {});
        }
        autoBindMap.get(target)![propertyKey!] = {};
    }
}

function buildNodeNameMap(node: any, nameMap: Map<string, any>) {
    nameMap.set(node.name, node);
    for (const child of node.children) {
        buildNodeNameMap(child, nameMap);
    }
}

/**
 * 在onLoad中调用这个函数然后才会自动绑定。initAutoBindings(this)。 
 */
export function initAutoBindings(instance: any) {
    const bindings = autoBindMap.get(Object.getPrototypeOf(instance));
    if (bindings) {
        const nameMap = new Map<string, any>();
        buildNodeNameMap(instance.node, nameMap);
        for (const propertyKey in bindings) {
            const binding = bindings[propertyKey];
            const node = nameMap.get(propertyKey);
            if (node) {
                if (binding.type) {
                    instance[propertyKey] = node.getComponent(binding.type);
                } else {
                    instance[propertyKey] = node;
                }
            } else {
                console.warn(`Node not found for propertyKey: ${propertyKey}`);
            }
        }
    }
}
