import Validator from "./Validator";
import ConditionFactory, {ConditionConfig} from "../../Conditions/ConditionFactory";
import {addRequiredValidatorToFactory} from "./Implementations/Required";
import {addRegexValidatorValidatorToFactory} from "./Implementations/RegexValidator";

export default class ValidatorFactory {
    protected registeredConstructors: {[type:string]: (config:ValidatorConfig, params:Partial<Validator>) => Validator|null} = {};

    constructor(
        protected conditionFactory: ConditionFactory
    ) {}

    public createValidator(config: ValidatorConfig): Validator|null {
        if (typeof config.type !== "string" ) throw new Error("Type is not a string");
        if (!(typeof this.registeredConstructors[config.type] === "function")) return null;

        const validatorParam: Partial<Validator> = {};

        validatorParam.errorMessage = config.errorMessage;
        validatorParam.checkName = config.checkName;

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

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

        return validator;
    }

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

    public setDefaults(): this{
        addRequiredValidatorToFactory(this);
        addRegexValidatorValidatorToFactory(this);

        return this;
    }
}

export interface ValidatorConfig {
    type: string;
    errorMessage: string;
    checkName: string;
    conditions: ConditionConfig[];
    idPrefix?: string;
}