import React, {Key, ReactElement} from "react";
import {
    INPUT_FIELD_SCHEMA,
    InputFieldOnBlurValidationType,
    InputFieldValidationFunObjectReturnType,
    InputFieldValidationFunType
} from "../schemes";
import {AdditionPropsType} from "../types";
import {
    DictDeepActionKeyWayType,
    InputField,
    isCustomComponent,
    UseIsErrorFieldAddErrorFieldType,
    UseIsErrorFieldRemoveErrorFieldType
} from "../dependencies";
import {INIT_FIELDS_NAME} from "../consts";

const getKeyWay = (schema: INPUT_FIELD_SCHEMA, additionProps: AdditionPropsType) => {
    if (schema.props.keyWay) {
        return schema.props.keyWay
    } else if (schema.props.name) {
        return [...additionProps.keyWay, schema.props.name]
    } else {
        // проверка на нахождение поле в array_fields
        const lastKeyWayItem = additionProps.keyWay[additionProps.keyWay.length - 1]
        if (typeof lastKeyWayItem === 'object') {
            return additionProps.keyWay
        }
    }
    return []
}

const getValidateFunResponse = (value: any, fun: InputFieldValidationFunType): InputFieldValidationFunObjectReturnType => {
    const res = fun(value)

    if (typeof res === 'object') {
        return res
    } else if (typeof res === 'string') {
        if (res === '')
            return {status: true, message: ''}
        else
            return {status: false, message: res}
    }

    return {status: res, message: ''}
}

const getValidateFun = (
    validationProps: InputFieldOnBlurValidationType,
    value: any,
    keyWay: DictDeepActionKeyWayType,
    schemeRequired: boolean,
    removeError: UseIsErrorFieldRemoveErrorFieldType,
    addError: UseIsErrorFieldAddErrorFieldType,
) => {
    return () => {
        let required = schemeRequired
        let fun: InputFieldValidationFunType = () => true

        if ('required' in validationProps && validationProps.required !== undefined) {
            required = validationProps.required
        }

        if ('fun' in validationProps && validationProps.fun !== undefined) {
            fun = validationProps.fun
        }

        const isEmptyValue = !value ||
            (Array.isArray(value) && value.length === 0) ||
            (typeof value === 'object' && Object.keys(value).length === 0)

        const funRes = getValidateFunResponse(value, fun)
        if (required ? !isEmptyValue && funRes.status : isEmptyValue || funRes.status) {
            removeError(keyWay)
        } else {
            addError(keyWay, funRes.message)
        }
    }
}

const getOnBlurValidation = (schema: INPUT_FIELD_SCHEMA, additionProps: AdditionPropsType, keyWay: DictDeepActionKeyWayType) => {
    const props = schema.props.onBlurValidation || schema.props.onChangeValidation
    if (props) {
        const value = additionProps.getValue(keyWay)
        return getValidateFun(props, value, keyWay, schema.props.required || false, additionProps.removeErrorField, additionProps.addErrorField)
    }
    return undefined
}

const getOnChangeValidation = (schema: INPUT_FIELD_SCHEMA, additionProps: AdditionPropsType, keyWay: DictDeepActionKeyWayType) => {
    let props = schema.props.onChangeValidation

    if (!props && schema.props.required === true) {
        props = {fun: (data) => true}
    }

    if (props) {
        const value = additionProps.getValue(keyWay)
        return getValidateFun(props, value, keyWay, schema.props.required || false, additionProps.removeOnChangeErrorField, additionProps.addOnChangeErrorField)
    }
    return undefined
}

const getOnChange = (schema: INPUT_FIELD_SCHEMA, keyWay: DictDeepActionKeyWayType, additionProps: AdditionPropsType) => {
    const serializeValue = schema.props.serializeValue
    let onChangeValidation = getOnChangeValidation(schema, additionProps, keyWay)
    return (data: any) => {
        onChangeValidation && onChangeValidation()
        serializeValue ? additionProps.setValue(serializeValue(data), keyWay) : additionProps.setValue(data, keyWay)
    }
}

const inputFieldComponent = (schema: INPUT_FIELD_SCHEMA, key: Key, additionProps: AdditionPropsType): ReactElement => {
    let onChange = undefined
    let value = undefined
    let isError = undefined
    let isErrorHintText = undefined

    let onBlur: ((e: any) => void) | undefined = undefined
    let keyWay: DictDeepActionKeyWayType = getKeyWay(schema, additionProps)

    if (keyWay) {
        const deserializeValue = schema.props.deserializeValue

        value = deserializeValue ? deserializeValue(additionProps.getValue(keyWay)) : additionProps.getValue(keyWay)
        onChange = getOnChange(schema, keyWay, additionProps)
        isError = additionProps.isErrorField(keyWay)
        isErrorHintText = additionProps.getErrorMessage(keyWay)
        onBlur = getOnBlurValidation(schema, additionProps, keyWay)

        // Поиск инициализированных полей
        const initFields: DictDeepActionKeyWayType = additionProps.getPrivateRefStoreValue(INIT_FIELDS_NAME) || []
        if (!initFields.find(item => JSON.stringify(item) === JSON.stringify(keyWay))) {
            additionProps.addPrivateRefStoreValue([...initFields, keyWay], INIT_FIELDS_NAME)
            onChange(value !== undefined ? value : schema.props.defaultValue)
        }
    }

    const comp = schema.props.ownerInputComponent ? schema.props.ownerInputComponent : <InputField/>

    const props = {
        ...(additionProps?.inputFieldAdditionProps ? additionProps?.inputFieldAdditionProps : {}),
        value: value,
        onChange: onChange,
        isError: isError,
        isErrorHintText: isErrorHintText,
        onBlur: onBlur,
        key: key,
        ...(additionProps.inputFieldClassName ? {className: additionProps.inputFieldClassName} : {}),
        ...(isCustomComponent(comp) ? additionProps.customCompAdditionProps : {}),
        ...schema.props,
    }
    return React.cloneElement(comp, props)
}


export default inputFieldComponent