import React from "react";
import Joi from "joi";
import Input, { InputType } from "./Input";
import ToggleSlider from "./ToggleSlider";
import Select from "./Select";
import Option from "./option";
import { GeneralIdRef } from "../../utils/GeneralIdRef";
import SequencePicker from "../pickers/SequencePicker";
import GlossaryPicker from "../pickers/GlossaryPicker";
import CustomFieldsEditor, { CustomFieldEditorAdd, CustomFieldEditorDelete } from "./CustomFieldsEditor";
import { CustomField, numberParams, textParams } from "../../modules/manager/customfields/services/customFieldsService";
import FormTemplatePicker from "../pickers/FormTemplatePicker";
import { CustomFieldValue, CustomFieldValues, Glossary } from "../../modules/manager/glossary/services/glossaryService";
import TemplateEditor from "./TemplateEditor";
import DomainPicker from "../pickers/DomainPicker";
import UserPicker from "../pickers/UserPicker";
import Button, { ButtonType } from "./Button";
import Expando from "./expando";
import ErrorBlock from "./ErrorBlock";
import SsoProviderPicker from "../pickers/SsoProviderPicker";

export interface FormError {
    [key: string]: string;
}

export interface FormData {
    [key: string]: string | number | boolean | CustomFieldValue[] | GeneralIdRef | CustomField[] | bigint | Glossary | null | undefined;
}

export interface businessValidationError {
    path: string;
    message: string;
}

export interface businessValidationResult {
    details: businessValidationError[];
}

export interface propertyValue {
    name: string;
    value: string | boolean | number;
}

export interface joiSchema {
    [key: string]: object;
}

export interface FormState {
    loaded: boolean;
    data: FormData;
    customFields?: CustomField[];
    errors: FormError;
    redirect?: string;
}

export interface Match<P> {
    params: P;
    isExact: boolean;
    path: string;
    url: string;
}

export interface State {
    from: Location;
}

export interface LocationProps {
    hash: string;
    pathname: string;
    search: string;
    state: State;
}

export interface FormProps<P> {
    location: LocationProps;
    match: Match<P>;
    staticContext?: any;
}

class Form<P, FP extends FormProps<P>, FS extends FormState> extends React.Component<FP, FS> {
    schema: joiSchema = {};

    validate = (data: FormData) => {
        let options: Joi.ValidationOptions = {
            context: {},
            abortEarly: false,
        };

        const { customFields } = this.state;

        let schema = this.schema;
        if (customFields !== undefined) {
            for (const customfield of customFields) {
                const name = "customfield_" + customfield.id;
                switch (customfield.fieldType) {
                    case "Number":
                        if (customfield.parameters !== undefined) {
                            const parameters: numberParams = JSON.parse(customfield.parameters!);

                            options.context![name + "_minEntries"] = customfield.minEntries;
                            if (parameters.minValue) options.context![name + "_minValue"] = Number(parameters.minValue);
                            if (parameters.maxValue) options.context![name + "_maxValue"] = Number(parameters.maxValue);

                            let minCheck = options.context![name + "_minValue"]
                                ? Joi.number()
                                      .empty("")
                                      .min(options.context![name + "_minValue"])
                                : Joi.number().empty("");
                            let maxCheck = options.context![name + "_maxValue"]
                                ? Joi.number()
                                      .empty("")
                                      .max(options.context![name + "_maxValue"])
                                : Joi.number().empty("");

                            schema[name] = Joi.array()
                                .min(1)
                                .items(
                                    Joi.object({
                                        displayValue: Joi.string().allow(""),
                                        value: Joi.when("$" + name + "_minEntries", {
                                            is: 0,
                                            then: Joi.number().empty(""),
                                            otherwise: Joi.number().required(),
                                        })
                                            .when("$" + name + "_minValue", {
                                                is: Joi.number(),
                                                then: minCheck,
                                            })
                                            .when("$" + name + "_maxValue", {
                                                is: Joi.number(),
                                                then: maxCheck,
                                            })
                                            .label(customfield.name),
                                    })
                                );
                        } else {
                            schema[name] = Joi.optional().label(customfield.name);
                        }
                        break;
                    default:
                        schema[name] = Joi.optional().label(customfield.name);
                }
            }
        }

        const joiSchema = Joi.object(schema);
        const { error } = joiSchema.validate(data, options);
        let errors: FormError = {};
        if (error) {
            if (error.details === undefined) {
                errors[error.name] = error.message;
            } else {
                for (let item of error.details) {
                    errors[item.path[0]] = item.message;
                }
            }
        }

        return errors;
    };

    GetCustomFieldValues = (customField: CustomField) => {
        const name = "customfield_" + customField.id;

        const { data } = this.state;

        const codedValue = data[name];

        let values: CustomFieldValue[] = [];

        switch (customField.fieldType) {
            case "FormTemplate":
                if (codedValue !== undefined) {
                    const formTemplateValue = { value: JSON.stringify(codedValue as GeneralIdRef) };
                    values.push(formTemplateValue);
                }
                break;
            case "Sequence":
                if (codedValue !== undefined) {
                    values = codedValue as CustomFieldValue[];
                }
                break;
            case "Glossary":
                if (codedValue !== undefined) {
                    values = codedValue as CustomFieldValue[];
                }
                break;
            case "Domain":
                if (codedValue !== undefined) {
                    values = codedValue as CustomFieldValue[];
                }
                break;
            case "Text":
                const textParameters: textParams = JSON.parse(customField.parameters!);
                if (textParameters.multiLine) {
                    const textValue = {
                        value: codedValue === undefined ? customField.defaultValue : codedValue,
                        displayValue: codedValue === undefined ? customField.defaultValue : codedValue,
                    } as CustomFieldValue;
                    values.push(textValue);
                } else {
                    if (codedValue === undefined) {
                        const numberValue = {
                            value: customField.defaultValue,
                            displayValue: customField.defaultValue,
                        } as CustomFieldValue;
                        values.push(numberValue);
                    } else {
                        values = codedValue as CustomFieldValue[];
                    }
                }
                break;
            case "Number":
                if (codedValue === undefined) {
                    const numberValue = {
                        value: customField.defaultValue,
                        displayValue: customField.defaultValue,
                    } as CustomFieldValue;
                    values.push(numberValue);
                } else {
                    values = codedValue as CustomFieldValue[];
                }

                break;
            default:
                const textValue = { value: codedValue === undefined ? customField.defaultValue : String((codedValue as CustomFieldValue[])[0].displayValue) };
                values.push(textValue);
                break;
        }

        return values;
    };

    CustomFieldValues = () => {
        const { customFields } = this.state;

        let result: CustomFieldValues[] = [];

        if (customFields === undefined) {
            return result;
        }

        for (const customfield of customFields) {
            const values = this.GetCustomFieldValues(customfield);

            const id: GeneralIdRef = {
                id: customfield.id,
                guid: customfield.guid,
            };

            const newItem: CustomFieldValues = {
                id,
                values,
            };

            result.push(newItem);
        }

        return result;
    };

    setCustomFieldValues(data: object, customFieldValues: CustomFieldValues[], customFields: CustomField[]) {
        if (customFieldValues !== undefined) {
            for (const x of customFieldValues) {
                const customfieldName = "customfield_" + x.id.id;

                switch (this.getCustomFieldType(x, customFields).toLowerCase()) {
                    case "glossary":
                    case "domain":
                    case "number":
                    case "text":
                        (data as any)[customfieldName] = x.values.map((x) => {
                            return {
                                displayValue: x.displayValue,
                                value: x.value,
                            };
                        });
                        break;
                    case "formtemplate":
                    case "multilinetext":
                        (data as any)[customfieldName] = x.values[0].value;
                        break;
                    default:
                        (data as any)[customfieldName] = x.values;
                        break;
                }
            }
        }
    }

    getCustomFieldType = (field: CustomFieldValues, childCustomFieldDefinition: CustomField[]): string => {
        const fieldDefinition = childCustomFieldDefinition.filter((x) => x.id === field.id.id)[0];

        if (fieldDefinition.parameters) {
            const textParameters: textParams = JSON.parse(fieldDefinition.parameters!);
            if (textParameters.multiLine) return "multilinetext";
        }

        return fieldDefinition.fieldType;
    };

    handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();

        const submitEvent = e.nativeEvent as SubmitEvent;

        const submitter = submitEvent.submitter as any;

        const errors = this.validate(this.state.data);
        this.setState({ errors: errors });

        const disabled = Object.keys(errors).length > 0;

        if (disabled) return;

        this.doSubmit(submitter.name);
    };

    doSubmit = async (buttonName: string) => {};

    handleGeneralError = (ex: any) => {
        const errors: FormError = { ...this.state.errors };

        if (ex.response) {
            errors._general = ex.response.data.detail;
        } else {
            errors._general = ex.message;
        }

        this.setState({ errors });
    };

    handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const input = e.currentTarget;

        const data: FormData = { ...this.state.data };

        if ((input as any).type === InputType.checkbox) {
            data[input.name] = !data[input.name];
        } else data[input.name] = input.value;

        const errors = this.validate(data);

        this.setState({ data, errors });
    };

    handleTextAreaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
        const input = e.currentTarget;

        const data: FormData = { ...this.state.data };

        data[input.name] = input.value;

        const errors = this.validate(data);

        this.setState({ data, errors });
    };

    handleCustomFieldChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const input = e.currentTarget;

        const data: FormData = { ...this.state.data };

        switch ((input as any).type) {
            case InputType.checkbox:
                data[input.name] = !data[input.name];
                break;
            default:
                const customFieldValue: CustomFieldValue = {
                    displayValue: input.value,
                    value: input.value,
                };

                data[input.name] = [customFieldValue];
                break;
        }

        const errors = this.validate(data);

        this.setState({ data, errors });
    };

    handleTemplateEditorChange = (name: string, value: string) => {
        const data: FormData = { ...this.state.data };

        data[name] = value;

        const errors = this.validate(data);

        this.setState({ data, errors });
    };

    handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
        const input = e.currentTarget;

        const data: FormData = { ...this.state.data };
        data[input.name] = input.value;
        const errors = this.validate(data);

        this.setState({ data, errors });
    };

    handlePickerChange = (name: string, value: GeneralIdRef) => {
        const data: FormData = { ...this.state.data };
        data[name] = value;
        const errors = this.validate(data);

        this.setState({ data, errors });
    };

    handleDomainPickerChange = (name: string, values: CustomFieldValue[]) => {
        const data: FormData = { ...this.state.data };
        data[name] = values;
        const errors = this.validate(data);

        this.setState({ data, errors });
    };

    handleGlossaryPickerChange = (name: string, values: CustomFieldValue[]) => {
        const data: FormData = { ...this.state.data };
        data[name] = values;
        const errors = this.validate(data);

        this.setState({ data, errors });
    };

    handleTemplateFormPickerChange = (name: string, value: GeneralIdRef) => {
        const data: FormData = { ...this.state.data };
        data[name] = value;
        const errors = this.validate(data);

        this.setState({ data, errors });
    };

    handleUserPickerChange = (name: string, value: GeneralIdRef) => {
        const data: FormData = { ...this.state.data };
        data[name] = value;
        const errors = this.validate(data);

        this.setState({ data, errors });
    };

    handleSsoProviderPickerChange = (name: string, value: GeneralIdRef) => {
        const data: FormData = { ...this.state.data };
        data[name] = value;
        const errors = this.validate(data);

        this.setState({ data, errors });
    };

    handleToggleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const input = e.currentTarget;
        const { name, checked } = input;

        const data: FormData = { ...this.state.data };
        data[name] = checked;
        const errors = this.validate(data);

        this.setState({ data, errors });
    };

    renderButton(
        label: string,
        name?: string,
        onClick?: (keyValue: any) => {},
        testid?: string,
        enabled: boolean = true,
        buttonType: ButtonType = ButtonType.primary,
        overrideErrorChecking: boolean = false
    ) {
        const { errors } = this.state;

        let disabled = !enabled || Object.keys(errors).filter((x) => !x.startsWith("_")).length > 0;

        if (overrideErrorChecking) disabled = !enabled;

        return (
            <Button testid={testid} disabled={disabled} name={name ?? label} buttonType={buttonType} onClick={onClick}>
                {label}
            </Button>
        );
    }

    renderError(name: string) {
        const { errors } = this.state;

        return <ErrorBlock error={errors[name]} />;
    }

    renderInput(
        name: string,
        label: string,
        type: InputType = InputType.text,
        readOnly = false,
        defaultValue: string = "",
        placeHolder: string = "",
        maxLength: number = 0,
        visible: boolean = true,
        autoComplete: string | undefined = undefined
    ) {
        const { data, errors } = this.state;

        let value = data[name];

        let cleanValue: string | undefined;
        if (value === undefined) {
            cleanValue = defaultValue;
        } else if (typeof value === "string") {
            cleanValue = value as string;
        } else if (typeof value === "number") {
            cleanValue = String(value);
        } else if (typeof value === "boolean") {
            cleanValue = String(value);
        } else if (value as CustomFieldValue) {
            cleanValue = (value as CustomFieldValue).displayValue ?? (value as CustomFieldValue).value.toString();
        }

        if (readOnly) {
            return (
                <Input
                    includeLabel={true}
                    type={type}
                    name={name}
                    label={label}
                    value={cleanValue}
                    error={errors[name]}
                    maxLength={maxLength}
                    readOnly
                    placeHolder={placeHolder}
                    hidden={!visible}
                    autoComplete={autoComplete}
                />
            );
        } else {
            return (
                <Input
                    includeLabel={true}
                    type={type}
                    name={name}
                    label={label}
                    value={cleanValue}
                    error={errors[name]}
                    maxLength={maxLength}
                    onChange={this.handleChange}
                    placeHolder={placeHolder}
                    hidden={!visible}
                    autoComplete={autoComplete}
                />
            );
        }
    }

    renderInputWithChangeEvent(
        name: string,
        label: string,
        type: InputType = InputType.text,
        readOnly = false,
        handleChangeEvent: any,
        defaultValue: string = "",
        placeHolder: string = "",
        maxLength: number = 0
    ) {
        const { data, errors } = this.state;

        let value = data[name];

        let cleanValue: string | undefined;
        if (value === undefined) {
            cleanValue = defaultValue;
        } else if (typeof value === "string") {
            cleanValue = value as string;
        } else if (typeof value === "number") {
            cleanValue = String(value);
        } else if (typeof value === "boolean") {
            cleanValue = String(value);
        } else if (value as CustomFieldValue) {
            cleanValue = (value as CustomFieldValue).displayValue ?? (value as CustomFieldValue).value.toString();
        }

        if (readOnly) {
            return (
                <Input
                    includeLabel={true}
                    type={type}
                    name={name}
                    label={label}
                    value={cleanValue}
                    error={errors[name]}
                    maxLength={maxLength}
                    readOnly
                    placeHolder={placeHolder}
                />
            );
        } else {
            return (
                <Input
                    includeLabel={true}
                    type={type}
                    name={name}
                    label={label}
                    value={cleanValue}
                    error={errors[name]}
                    maxLength={maxLength}
                    onChange={handleChangeEvent}
                    placeHolder={placeHolder}
                />
            );
        }
    }

    renderInputNumber(name: string, label: string, readOnly = false, defaultValue: string = "", min?: number, max?: number, step: number = 1) {
        const { data, errors } = this.state;

        let value = data[name];

        let cleanValue: string | undefined;
        if (value === undefined) {
            cleanValue = defaultValue;
        } else if (typeof value === "string") {
            cleanValue = value as string;
        } else if (typeof value === "number") {
            cleanValue = String(value);
        } else if (typeof value === "boolean") {
            cleanValue = String(value);
        } else if (value as CustomFieldValue) {
            cleanValue = (value as CustomFieldValue).displayValue ?? (value as CustomFieldValue).value.toString();
        }

        if (readOnly) {
            return <Input includeLabel={true} type={InputType.number} name={name} label={label} value={cleanValue} error={errors[name]} readOnly />;
        } else {
            return (
                <Input
                    includeLabel={true}
                    type={InputType.number}
                    name={name}
                    label={label}
                    value={cleanValue}
                    error={errors[name]}
                    min={min}
                    max={max}
                    step={step}
                    onChange={this.handleChange}
                />
            );
        }
    }

    renderInputTextarea(includeLabel: boolean, name: string, label: string, readOnly = false, defaultValue: string = "") {
        const { data, errors } = this.state;

        let value = data[name];

        let cleanValue: string | undefined;
        if (value === undefined) {
            cleanValue = defaultValue;
        } else if (typeof value === "string") {
            cleanValue = value as string;
        }

        if (readOnly) {
            return (
                <Input
                    includeLabel={includeLabel}
                    type={InputType.textarea}
                    key={name}
                    name={name}
                    label={label}
                    value={cleanValue}
                    error={errors[name]}
                    readOnly
                />
            );
        } else {
            return (
                <Input
                    includeLabel={includeLabel}
                    type={InputType.textarea}
                    key={name}
                    name={name}
                    label={label}
                    value={cleanValue}
                    error={errors[name]}
                    onTextAreaChange={this.handleTextAreaChange}
                />
            );
        }
    }

    renderCustomFieldInput(includeLabel: boolean, name: string, label: string, type: InputType = InputType.text, readOnly = false, defaultValue: string = "") {
        const { data, errors } = this.state;

        let value = data[name];

        let cleanValue: string | undefined;
        if (value === undefined) {
            cleanValue = defaultValue;
        } else if (typeof value === "string") {
            cleanValue = value as string;
        } else if (typeof value === "number") {
            cleanValue = String(value);
        } else if (typeof value === "boolean") {
            cleanValue = String(value);
        } else if (value as CustomFieldValue) {
            const customFieldValue = value as CustomFieldValue[];
            cleanValue = customFieldValue[0].displayValue ?? customFieldValue[0].value?.toString();
        }

        if (readOnly) {
            return <Input includeLabel={includeLabel} type={type} name={name} label={label} value={cleanValue} error={errors[name]} readOnly />;
        } else {
            return (
                <Input
                    includeLabel={includeLabel}
                    type={type}
                    name={name}
                    label={label}
                    value={cleanValue}
                    error={errors[name]}
                    onChange={this.handleCustomFieldChange}
                />
            );
        }
    }

    renderCustomFieldNumber(
        includeLabel: boolean,
        name: string,
        label: string,
        readOnly = false,
        defaultValue: string = "",
        min?: number,
        max?: number,
        step: number = 1
    ) {
        const { data, errors } = this.state;

        let values: CustomFieldValue[] = data[name] as CustomFieldValue[];

        let value: CustomFieldValue | undefined = undefined;

        if (values) {
            if (values.length > 0) {
                value = values[0];
            }
        }

        let cleanValue: string | undefined;
        if (value === undefined) {
            cleanValue = defaultValue;
        } else if (typeof value === "string") {
            cleanValue = value as string;
        } else if (typeof value === "number") {
            cleanValue = String(value);
        } else if (value as CustomFieldValue) {
            cleanValue = (value as CustomFieldValue).displayValue ?? (value as CustomFieldValue).value?.toString();
        }

        if (readOnly) {
            return <Input includeLabel={includeLabel} type={InputType.number} name={name} label={label} value={cleanValue} error={errors[name]} readOnly />;
        } else {
            return (
                <Input
                    includeLabel={includeLabel}
                    type={InputType.number}
                    name={name}
                    label={label}
                    value={cleanValue}
                    error={errors[name]}
                    min={min}
                    max={max}
                    step={step}
                    onChange={this.handleCustomFieldChange}
                />
            );
        }
    }

    renderTemplateEditor(className: string, name: string, label: string, allowCustomFields: boolean) {
        const { data } = this.state;

        let value = data[name] as string;

        return (
            <div>
                <label htmlFor={name}>{label}</label>
                <TemplateEditor className={className} name={name} data={value} onChange={this.handleTemplateEditorChange} showFields={allowCustomFields} />
            </div>
        );
    }

    renderSelect(name: string, label: string, options: Option[]) {
        const { data, errors } = this.state;

        return <Select name={name} label={label} value={data[name]} options={options} error={errors[name]} onChange={this.handleSelectChange} />;
    }

    renderToggle(name: string, label: string) {
        const { data, errors } = this.state;
        return <ToggleSlider name={name} label={label} defaultChecked={Boolean(data[name])} error={errors[name]} onChange={this.handleToggleChange} />;
    }

    renderSequencePicker(includeLabel: boolean, name: string, label: string) {
        const { data, errors } = this.state;

        return (
            <SequencePicker includeLabel={includeLabel} name={name} label={label} value={data[name]} error={errors[name]} onChange={this.handlePickerChange} />
        );
    }

    renderGlossaryPicker(includeLabel: boolean, name: string, label: string, maxEntries?: number, refElementId?: GeneralIdRef) {
        const { data, errors } = this.state;

        const glossaryValues: CustomFieldValue[] | undefined = data[name] as any as CustomFieldValue[];

        return (
            <GlossaryPicker
                includeLabel={includeLabel}
                name={name}
                label={label}
                maxEntries={maxEntries}
                values={glossaryValues}
                error={errors[name]}
                rootItem={refElementId}
                onChange={this.handleGlossaryPickerChange}
            />
        );
    }

    renderDomainPicker(includeLabel: boolean, name: string, label: string, minEntries: number, maxEntries?: number) {
        const { data, errors } = this.state;

        const domainValues: CustomFieldValue[] | undefined = data[name] as any as CustomFieldValue[];

        return (
            <DomainPicker
                includeLabel={includeLabel}
                name={name}
                label={label}
                minEntries={minEntries}
                maxEntries={maxEntries}
                values={domainValues}
                error={errors[name]}
                onChange={this.handleDomainPickerChange}
            />
        );
    }

    renderTemplatePicker(includeLabel: boolean, name: string, label: string) {
        const { data, errors } = this.state;

        const templateValue: GeneralIdRef = data[name] as any as GeneralIdRef;

        return (
            <FormTemplatePicker
                includeLabel={includeLabel}
                name={name}
                label={label}
                value={templateValue}
                error={errors[name]}
                onChange={this.handleTemplateFormPickerChange}
            />
        );
    }

    renderUserPicker(name: string, label: string) {
        const { data, errors } = this.state;

        const glossaryValue: GeneralIdRef | undefined = data[name] as any as GeneralIdRef;

        return <UserPicker name={name} label={label} value={glossaryValue} error={errors[name]} onChange={this.handleUserPickerChange} />;
    }

    renderSsoProviderPicker(name: string, label: string) {
        const { data, errors } = this.state;

        const glossaryValue: GeneralIdRef | undefined = data[name] as any as GeneralIdRef;

        return <SsoProviderPicker name={name} label={label} value={glossaryValue} error={errors[name]} onChange={this.handleSsoProviderPickerChange} />;
    }

    renderCustomFieldsEditor(name: string, label: string, selected: CustomField[], onAdd: CustomFieldEditorAdd, onDelete: CustomFieldEditorDelete) {
        const { data, errors } = this.state;

        return (
            <CustomFieldsEditor name={name} label={label} value={data[name] as []} error={errors[name]} exclude={selected} onAdd={onAdd} onDelete={onDelete} />
        );
    }

    renderCustomFields(customFields: CustomField[] | undefined) {
        if (customFields === undefined) return <></>;

        let customFieldsBlock: JSX.Element[] = [];
        for (const customField of customFields) customFieldsBlock.push(this.renderCustomField(customField, true));

        return <>{customFieldsBlock.map((x) => x)}</>;
    }

    renderCustomField(customField: CustomField, includeLabel: boolean) {
        switch (customField.fieldType.toLowerCase()) {
            case "text":
                const textParameters: textParams = JSON.parse(customField.parameters!);
                if (textParameters.multiLine) {
                    return this.renderInputTextarea(includeLabel, "customfield_" + customField.id, customField.name, false, customField.defaultValue);
                } else {
                    return this.renderCustomFieldInput(
                        includeLabel,
                        "customfield_" + customField.id,
                        customField.name,
                        InputType.text,
                        false,
                        customField.defaultValue
                    );
                }
            case "sequence":
                return this.renderCustomFieldInput(includeLabel, "customfield_" + customField.id, customField.name, InputType.text, true);
            case "formtemplate":
                return this.renderTemplatePicker(includeLabel, "customfield_" + customField.id, customField.name);
            case "glossary":
                return this.renderGlossaryPicker(
                    includeLabel,
                    "customfield_" + customField.id,
                    customField.name,
                    customField.maxEntries,
                    customField.refElementId
                );
            case "number":
                const numberParameters: numberParams = JSON.parse(customField.parameters!);
                return this.renderCustomFieldNumber(
                    includeLabel,
                    "customfield_" + customField.id,
                    customField.name,
                    false,
                    customField.defaultValue,
                    numberParameters.minValue ? Number(numberParameters.minValue) : undefined,
                    numberParameters.maxValue ? Number(numberParameters.maxValue) : undefined,
                    numberParameters.step ? Number(numberParameters.step) : undefined
                );
            case "domain":
                return this.renderDomainPicker(includeLabel, "customfield_" + customField.id, customField.name, customField.minEntries, customField.maxEntries);
            default:
                return <>{customField.name + " " + customField.fieldType}</>;
        }
    }

    renderDropSection(name: string, title: JSX.Element, content: JSX.Element) {
        const { errors } = this.state;

        return (
            <Expando name={name} title={title} error={errors[name]}>
                {content}
            </Expando>
        );
    }
}

export default Form;
