import { __awaiter, __decorate } from "tslib";
import { Connect } from '@genesislcap/foundation-comms';
import { attr, customElement, observable } from '@microsoft/fast-element';
import { FoundationElement } from '@microsoft/fast-foundation';
import { foundationFormStyles as styles } from './form.styles';
import { foundationFormTemplate as template } from './form.template';
import { createLogger } from '@genesislcap/foundation-utils';
import { isControl, isStringControl, mapStateToControlProps, rankWith, } from '@jsonforms/core';
import { BooleanControlEntry } from './jsonforms/renderers/BooleanControlRenderer';
import { ConnectedMultiselectControlRendererEntry } from './jsonforms/renderers/ConnectedMultiselectControlRenderer';
import { ConnectedSelectControlRendererEntry } from './jsonforms/renderers/ConnectedSelectControlRenderer';
import { DateControlRendererEntry } from './jsonforms/renderers/DateControlRenderer';
import { EnumControlRendererEntry } from './jsonforms/renderers/EnumControlRenderer';
import { InvisibleControlEntry } from './jsonforms/renderers/InvisibleControlRenderer';
import { LayoutRendererEntry } from './jsonforms/renderers/LayoutRenderer';
import { LayoutVertical2ColumnsEntry } from './jsonforms/renderers/LayoutVertical2ColumnsRenderer';
import { NumberControlRendererEntry } from './jsonforms/renderers/NumberControlRenderer';
import { StringControlRendererTemplate } from './jsonforms/renderers/StringControlRenderer';
export const logger = createLogger('foundation-form');
const stringEntry = {
    renderer: StringControlRendererTemplate,
    tester: rankWith(2, isStringControl),
    mapper: mapStateToControlProps,
};
const fallbackEntry = {
    renderer: StringControlRendererTemplate,
    tester: rankWith(1, isControl),
    mapper: mapStateToControlProps,
};
const renderers = [
    fallbackEntry,
    stringEntry,
    BooleanControlEntry,
    LayoutVertical2ColumnsEntry,
    LayoutRendererEntry,
    NumberControlRendererEntry,
    ConnectedMultiselectControlRendererEntry,
    EnumControlRendererEntry,
    ConnectedSelectControlRendererEntry,
    DateControlRendererEntry,
    InvisibleControlEntry,
];
/**
 * Foundation form component for automatically generated forms based on json schema
 * obtained from the api, supplied initial data or supplied JSON schema.
 * Allowing customisable form elements using UI schema and set of custom renderers
 * @beta
 */
let Form = class Form extends FoundationElement {
    constructor() {
        super(...arguments);
        /**
         * Allows to provide set of renderers used by the form. If not provided it will default to text-field inputs
         * @public
         */
        this.renderers = renderers;
        this.errors = [];
        /**
         * Initial data for the form
         * @public
         */
        this.data = {};
    }
    resourceNameChanged() {
        var _a, _b;
        return __awaiter(this, void 0, void 0, function* () {
            if (this.resourceName) {
                const jsonSchemaResponse = yield this.connect.getJSONSchema(this.resourceName);
                this.jsonSchema = (_b = (_a = jsonSchemaResponse === null || jsonSchemaResponse === void 0 ? void 0 : jsonSchemaResponse.INBOUND) === null || _a === void 0 ? void 0 : _a.properties) === null || _b === void 0 ? void 0 : _b.DETAILS;
            }
            this.removeDataProperties();
        });
    }
    removeDataProperties() {
        if (!this.jsonSchema || !this.data) {
            return;
        }
        // removes data provided to the form that isn't part of the schema
        const properties = Object.keys(this.jsonSchema.properties);
        Object.keys(this.data).forEach((key) => {
            if (!properties.includes(key)) {
                delete this.data[key];
                logger.debug('Removing key ', key, 'from provided data because it is not part of the payload');
            }
        });
    }
    /**
     * @internal
     */
    _submit() {
        return __awaiter(this, void 0, void 0, function* () {
            const payload = Object.assign({}, this.data);
            this.submissionErrors = '';
            this.submitted = true;
            logger.debug({ payload, errors: this.errors });
            this.$emit('submit', { payload, errors: this.errors });
            if (Object.entries(payload).length !== 0 && !this.errors.length && this.resourceName) {
                this.submitting = true;
                const formSubmitReq = yield this.connect.commitEvent(this.resourceName, { DETAILS: payload });
                this.submitting = false;
                if (formSubmitReq.ERROR) {
                    this.$emit('submit-failure', { payload, errors: formSubmitReq.ERROR });
                    this.submissionErrors = formSubmitReq.ERROR.map((x) => x.CODE + ': ' + x.TEXT).toString();
                }
                else {
                    this.$emit('submit-success', { payload });
                }
            }
        });
    }
    /**
     * @internal
     */
    onChange(event) {
        logger.debug({ event });
        if (event.detail) {
            this.data = event.detail.data;
            this.errors = event.detail.errors;
        }
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.submitted = false;
        this.submissionErrors = '';
        this.jsonSchema = undefined;
        this.resourceName = undefined;
        this.data = {};
    }
};
__decorate([
    attr
], Form.prototype, "resourceName", void 0);
__decorate([
    observable
], Form.prototype, "uischema", void 0);
__decorate([
    observable
], Form.prototype, "renderers", void 0);
__decorate([
    observable
], Form.prototype, "jsonSchema", void 0);
__decorate([
    Connect
], Form.prototype, "connect", void 0);
__decorate([
    observable
], Form.prototype, "data", void 0);
__decorate([
    observable
], Form.prototype, "submitting", void 0);
__decorate([
    observable
], Form.prototype, "submitted", void 0);
__decorate([
    observable
], Form.prototype, "submissionErrors", void 0);
__decorate([
    attr({ mode: 'boolean' })
], Form.prototype, "readonly", void 0);
Form = __decorate([
    customElement({
        name: 'foundation-form',
        template,
        styles,
    })
], Form);
export { Form };
//# sourceMappingURL=form.js.map