import "reflect-metadata";
import { assertInjectable } from "./Injectable";
import ClassName, { GetClassName } from "./ClassName";
import Logger from "../class/Logger";

/**
 * 一个简单的类容器
 */
@ClassName('Container')
export class Container {
    static _container = new Map();
    private static logger;

    static set<T>(k: Constructor<T>, v: T): void {
        if (!this._container.has(k)) {
            this._container.set(k, v);
        }
    }

    static get<T>(k: Constructor<T>): T {
        return this._container.get(k);
    }

    static factory<T>(target: ClassType<T>): T {
        assertInjectable(target);
        return this.get(target) || this.initParam(target);
    }

    static setLogger(logger: Logger): void {
        this.logger = logger;
    }

    private static initParam<T>(target: Constructor<T>): T {
        // 获取所有注入的服务
        const providers = Reflect.getMetadata('design:paramtypes', target);
        const args = providers ? providers.map((provider: Constructor) => {
            return this.factory(provider);
        }) : [];
        let _target = new target(...args);
        this.logger?.info(
            `[${ GetClassName(target) || target.name }] 实例化`
        );
        this.set(target, _target);
        return _target;
    }
}
