import { Component } from "cc";
import { Logger } from "./Logger";

interface AutoBindOptions {
    type?: any; // 组件类型（如 Label）
    tooltip?: string;
    [key: string]: any;
}

const AutoBindMap = new WeakMap<any, { [key: string]: AutoBindOptions }>();
/**
 * 自动绑定与变量同名的子节点。
 * 装饰器不传参数（组件）则绑定节点，传了组件则绑定节点上的组件。
 * 如果传了组件，则传入的组件一定要和变量类型一致，否则绑定会失败。
 * 记得在组件的onLoad函数调用initAutoBindings(this)
 事例:
"@autoBind不传" 绑定是节点
”@autoBind(Label)“ 绑定的是Label 
“@autoBind({type: Label,tooltip: "文本"})” 绑定的是Label 
 */
export function autoBind(target: any, propertyKey: string): void;
export function autoBind<T extends Component>(componentType: { new(): T }): (target: any, propertyKey: string) => void;
export function autoBind<T extends Component>(options: AutoBindOptions): (target: any, propertyKey: string) => void;
export function autoBind<T extends Component>(
    componentTypeOrTarget?: { new(): T } | AutoBindOptions | any,
    propertyKey?: string
) {
    if (propertyKey !== undefined) {
        //情况1：@autoBind 不传参
        const target = componentTypeOrTarget;
        if (!AutoBindMap.has(target)) {
            AutoBindMap.set(target, {});
        }
        AutoBindMap.get(target)![propertyKey] = {};
        return;
    }
    //情况2：@autoBind(Label) 或 @autoBind({type: Label})
    return function (target: any, propertyKey: string) {
        if (!AutoBindMap.has(target)) {
            AutoBindMap.set(target, {});
        }
        const options: AutoBindOptions = typeof componentTypeOrTarget === "function"
            ? { type: componentTypeOrTarget }
            : componentTypeOrTarget;
        AutoBindMap.get(target)![propertyKey] = options;
    };
}

/**
 * 获取变量的类型
 */
function getComponentType(instance: any, propertyKey: string, binding: AutoBindOptions): any {
    //1. 优先用 @autoBind 指定的类型
    if(binding.type) {
       return binding.type;
    }
    //2. 尝试从变量默认值推断（如 `= null! as Label`）
    const defaultValue = instance[propertyKey];
    if (defaultValue !== null && defaultValue !== undefined) {
        return defaultValue.constructor;
    }
    //3. 尝试从类型断言推断（如 `= null! as Label`）
    //注意：这种方式在运行时无法获取类型信息，需要用户确保正确使用
    // 这里我们无法直接获取类型断言信息，只能依赖用户正确设置默认值
    //4. 如果仍然没有，返回 null（绑定节点而非组件）
    return null;
}

/**
 * 在onLoad中调用这个函数然后才会自动绑定。initAutoBindings(this)。 
 */
export function initAutoBindings(instance: any) {
    const bindings = AutoBindMap.get(Object.getPrototypeOf(instance));
    if (!bindings) return;
    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) {
            //Logger.warn(`[AutoBind] 节点未找到: ${propertyKey}`);
            continue;
        }
        const componentType = getComponentType(instance, propertyKey, binding);
        if (componentType && !(node instanceof componentType)) {  // 关键修改：排除 Node 类型
            instance[propertyKey] = node.getComponent(componentType);
            //Logger.log(`[AutoBind] 绑定组件 ${propertyKey}:`, componentType.name);
        } else {
            instance[propertyKey] = node; // 直接绑定节点
           // Logger.log(`[AutoBind] 绑定节点 ${propertyKey}`);
        }
    }
}

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