import Component from "./Component";
import FormBuilder from "../FormBuilder";
import ConditionFactory, {ConditionConfig} from "../Conditions/ConditionFactory";
import Structure from "./Structure/Structure";

export default class ComponentFactory{
    protected registeredConstructors: {[type:string]: (config:ComponentConfig, params:Partial<Component>) => Component|null|undefined} = {};

    constructor(
        protected formBuilder: FormBuilder,
        protected conditionFactory: ConditionFactory
    ) {}

    public createComponent(config: ComponentConfig, parent:Structure|null = null): Component|null {
        if (typeof config.type !== "string" ) throw new Error("Type is not a string");
        if (!(typeof this.registeredConstructors[config.type] === "function")) {
            console.warn(`Component ${config.type} is not registered`);
            return null;
        }

        const componentParams: Partial<Component> = {};
        componentParams.parent = parent;
        componentParams.formBuilder = this.formBuilder;
        const idPrefix = config.idPrefix ?? parent?.idPrefix ?? "";
        componentParams.idPrefix = idPrefix;
        componentParams.id = config.id;


        const component = this.registeredConstructors[config.type](config, componentParams);
        if (component == null) {
            console.warn(`Component ${config.type} could not be created`);
            return null;
        }

        this.formBuilder.registry[(idPrefix) + config.id] = component;
        this.formBuilder.onClean.add(() => component.cleanHtml());
        this.formBuilder.onComponentsCreated.add(() => component.checkVisibility());

        config.conditions.forEach(c => {
            let condition = this.conditionFactory.createCondition(c);
            if (condition === null) return;
            condition.idPrefix = idPrefix;
            component.addConditions(condition);
        });

        return component;
    }

    public registerConstructor(type: string, constructor: (config:ComponentConfig, params:Partial<Component>) => Component|null|undefined): this {
        this.registeredConstructors[type] = constructor;
        return this;
    }
}

export interface ComponentConfig {
    type: string;
    id: string;
    conditions: ConditionConfig[];
    idPrefix?: string;
}