import { BehaviorSubject } from "rxjs";
export class FormController {
    constructor(schema) {
        this.values = new BehaviorSubject({});
        this.errors = new BehaviorSubject({});
        this._initialValues = {};
        this._values = {};
        this._errors = {};
        this._isValid = true;
        this._schema = schema;
    }
    processArrayError(obj, property, remainingProperties, message) {
        // Extract array name and index from the property string
        const [arrayName, indexStr] = property
            .match(/^([a-zA-Z0-9]+)\[(\d+)\]/)
            .slice(1);
        const index = parseInt(indexStr, 10);
        // Ensure the array exists and has an entry at the given index
        obj[arrayName] = obj[arrayName] || [];
        obj[arrayName][index] = obj[arrayName][index] || {};
        // Recursively set the error if there are remaining properties, else set the error message
        if (remainingProperties.length) {
            this.setNestedError(obj[arrayName][index], remainingProperties, message);
        }
        else {
            obj[arrayName][index] = message;
        }
    }
    processRegularError(obj, property, remainingProperties, message) {
        // Ensure the property exists
        obj[property] = obj[property] || {};
        // Recursively set the error if there are remaining properties, else set the error message
        if (remainingProperties.length) {
            this.setNestedError(obj[property], remainingProperties, message);
        }
        else {
            obj[property] = message;
        }
    }
    setNestedError(obj, properties, message) {
        const property = properties.shift();
        const isArrayError = property.includes('[');
        if (isArrayError) {
            this.processArrayError(obj, property, properties, message);
        }
        else {
            this.processRegularError(obj, property, properties, message);
        }
    }
    setError(obj, path, message) {
        // Convert path to properties array
        const properties = Array.isArray(path) ? path : path.split('.');
        this.setNestedError(obj, properties, message);
    }
    async validate(context) {
        this._isValid = true;
        this._errors = {};
        try {
            await this._schema.validate(this._values, { context, abortEarly: false });
        }
        catch (err) {
            this._isValid = false;
            err.inner.forEach((item) => {
                this.setError(this._errors, item.path, item.message);
            });
        }
        this.errors.next(this._errors);
        return this._isValid;
    }
    async validateAndSubmit(submitHandler, context) {
        const isValid = await this.validate(context || {});
        if (isValid) {
            submitHandler(this._values);
        }
    }
    setInitialValues(values) {
        this._initialValues = values;
        this._values = values;
        this.values.next(this._values);
    }
    setValues(values) {
        this._values = Object.assign(Object.assign({}, this._values), values);
        this.values.next(this._values);
    }
    resetValues() {
        this._values = this._initialValues;
        this.values.next(this._values);
    }
    getInitialValues() {
        return this._initialValues;
    }
    setFieldError(path, message) {
        this.setError(this._errors, path, message);
        this.errors.next(this._errors);
    }
    clearFieldError(path) {
        const properties = path.split('.');
        let obj = this._errors;
        for (let i = 0; i < properties.length - 1; i++) {
            if (!obj[properties[i]])
                return;
            obj = obj[properties[i]];
        }
        const lastProp = properties[properties.length - 1];
        if (obj[lastProp]) {
            delete obj[lastProp];
            this.errors.next(this._errors);
        }
    }
}
