import React, { useEffect, useState } from 'react'
import { isServer } from '$ustoreinternal/services/utils'
import Hashids from "hashids";
import features from '$features'
import Icon from '$core-components/Icon'
import { t } from '$themelocalization'

const withCustomProps = (WrappedComponent = {}) => {
  class ConnectedComponent extends React.Component {
    constructor(props) {
      super(props);
      const regex = new RegExp(/[!$%^&*()+|~=`{}\[\]:";'<>?,.\/]/, 'g');
      this.id = this.props.id.replace('root_', '').replace(regex, '')
      this.typingTimer = null
    }

    componentWillUnmount() {
      clearTimeout(this.typingTimer)
    }

    onDucChange = (value, errors = [], skipValidation = false) => {
      const newDucValue = value === 'default' ? undefined : value
      const schemaErrors = !value && this.props.uiSchema['ui:errorMessages']
          ? Object.values(this.props.uiSchema['ui:errorMessages']).map((err) => err)
          : []
      const errSchema = { [this.props.id]: { __errors: [...schemaErrors, ...errors] }}
      clearTimeout(this.typingTimer)
      this.typingTimer = setTimeout(() => {
        this.props.onChange(this.props.id, newDucValue, errSchema, skipValidation)
      }, 750)
    }

    render() {
      const hashids = new Hashids(this.id)
      const hashedID = hashids.encode(1, 2, 3)

      return (
          <div className={`a${hashedID}`}>
            <WrappedComponent
                {...this.props}
                onChange={this.onDucChange}
                id={this.id}
                disabled={this.props.readonly}
            />
          </div>
      )
    }
  }
  return ConnectedComponent
}

const widgets = !isServer() ? uStoreDucs.reduce((r, duc) => ({...r, [duc.name]: withCustomProps(duc.component)}), {})  : {}

const DynamicForm = ({ properties, excelPricingEnabled, onChange, onBlur, errors, formData }) => {
  const [internalFormData, setInternalFormData] = useState(formData || {})

  useEffect(() => {
    if (formData) {
      setInternalFormData(formData)
    }
  }, [formData])

  const handlePropertyChange = (id, value, errorsFromProperty, skipValidation = false) => {
    const updatedErrors = Object.keys(errors)
        .reduce((acc, propertyId) => ({
          ...acc,
          [propertyId]: errorsFromProperty[propertyId] &&
            errorsFromProperty[propertyId].__errors || errors[propertyId].errors
        }), {})
    setInternalFormData({
      ...internalFormData,
      [id]: value
    })
    onChange(id, value, updatedErrors, {}, skipValidation)
  }

  const handlePropertyBlur = (id, value) => {
    onBlur(id, value)
  }

  const checkIfPropertyDependersHaveDefaultValueSelected = (property, formData) =>
    property.depended !== null &&
    formData[property.parent] === property.condition.enum[0] ?
      checkIfPropertyDependersHaveDefaultValueSelected(property.depended, formData) :
      formData[property.parent] === property.condition.enum[0]


  if (!Object.keys(properties).length) return null

  return (
    <>
      {Object.values(properties)
        .map((property) => {
          if ((
            property.depended && checkIfPropertyDependersHaveDefaultValueSelected(property.depended, formData)) ||
            !property.depended
          ) {
            const WidgetComponent = widgets[property.uiSchema['ui:widget']]
            return (
                <div key={property.id} className={`duc-wrapper ${property.uiSchema['ui:options'].visible
                    ? ''
                    : 'hidden'}
                ${errors[property.id] && errors[property.id].errors.length && errors[property.id].show
                    ? 'errors'
                    : ''}
                `}
                >
                  <div className="duc-head">
                    <label htmlFor={property.id} className='duc-title'>
                      {property.title}
                      {property.required
                          ? <span className="required-field">*</span>
                          : null
                      }
                    </label>
                    {property.description &&
                        <span className='duc-description'>
                      <Icon name="info.svg" width="16px" height="16px" className="info-icon"/>
                      <div className='duc-description-text'>{property.description}</div>
                    </span>
                    }
                    {property.custom.info &&
                        <span className='info-icon'>(i)
                      <span className='tooltip-text' dangerouslySetInnerHTML={{__html: property.custom.info}}/>
                    </span>
                    }
                  </div>
                  <WidgetComponent
                      id={property.id}
                      readonly={property.uiSchema['ui:readonly']}
                      schema={property.propertySchema}
                      formContext={{ UStoreProvider }}
                      uiSchema={property.uiSchema}
                      options={property.uiSchema['ui:options']}
                      value={internalFormData[property.id]}
                      onChange={handlePropertyChange}
                      onBlur={handlePropertyBlur}
                      features={features}
                      required={property.required}
                      t={t}
                  />
                  {
                    errors[property.id] &&
                    errors[property.id].errors &&
                    errors[property.id].show
                        ? errors[property.id].errors.map((error) => {
                          return (
                              <div className={'duc-error'} key="err">
                                <div className="error-text">{error}</div>
                              </div>
                          )
                        })
                        : null
                  }
                </div>
            )
          }
        })
      }
    </>
  )
}

export default DynamicForm
