import React from 'react';
import PropTypes from 'prop-types';
import Select, { createFilter } from 'react-select';
import { Controller } from 'react-hook-form';
import { createNamespace } from '../../tools/namingTools';
import { SMALL } from '../../constants/sizes';
import { LIGHT, DARK } from '../../constants/themeColor';
import FormLabel from '../form-label/FormLabel';
import './styles/Select.scss';

const n = createNamespace('Select');

const SpecificSelect = ({
    name,
    value,
    label,
    size,
    theme,
    type,
    width,
    defaultValue,
    options,
    placeholder,
    hiddenLabel,
    onChange,
    isSearchable,
    withBackground,
    classNamePrefix,
    inline,
    hookFormControl,
    validationRules,
    error,
    required,
    i18n
}) => {
    const prefix = classNamePrefix || 'select';
    const customStyles = {
        control: () => ({
            width: width || '100%'
        })
    };
    const valueShape = options && options.find(o => o.value === value);
    const inlineClass = 'inline';
    const labelTextModifier = [
        hiddenLabel ? 'hidden' : null,
        inline && inlineClass
    ];
    const groupModifiers = [
        size,
        theme,
        type,
        error && 'error',
        !withBackground && 'transparent'
    ];

    const inputProps = {
        id: name,
        name,
        value: valueShape,
        options,
        styles: customStyles,
        placeholder,
        isSearchable: isSearchable || false,
        menuPlacement: 'auto',
        className: `${prefix}__container`,
        onChange,
        classNamePrefix: prefix
    };

    if (isSearchable) {
        inputProps.filterOption = createFilter({
            ignoreCase: true,
            ignoreAccents: true,
            trim: true,
            matchFrom: 'start'
        });
    }

    let input;
    if (hookFormControl) {
        input = (
            <Controller
                control={hookFormControl}
                name={name}
                value={valueShape}
                defaultValue={defaultValue || ''}
                render={({ onChange: innerOnChange, onBlur: innerOnBlur, value: innerValue, name: innerName }) => (
                    <Select
                        {...inputProps}
                        onChange={v => {
                            if (onChange) {
                                onChange(v);
                            }
                            innerOnChange(v);
                        }}
                        onBlur={innerOnBlur}
                        value={innerValue}
                        name={innerName}
                    />
                )}
                rules={validationRules}
            />
        );
    } else {
        input = <Select {...inputProps} />;
    }

    return (
        <div {...n('group', groupModifiers).withTestId().props}>
            <FormLabel
                labelText={label}
                required={required}
                labelProps={n('label', inline && inlineClass).withE2EId().withTestId().props}
                textProps={n('text', labelTextModifier).props}
                htmlFor={name}
                i18n={i18n}
            >
                {input}
            </FormLabel>
            {error && (
                <span {...n('error').props} aria-live="assertive">
                    {error}
                </span>
            )}
        </div>
    );
};

const selectOptionShape = {
    label: PropTypes.string,
    value: PropTypes.string
};

SpecificSelect.propTypes = {
    name: PropTypes.string,
    label: PropTypes.string,
    value: PropTypes.string,
    type: PropTypes.oneOf(['button']),
    theme: PropTypes.oneOf([LIGHT.value, DARK.value]),
    size: PropTypes.oneOf([SMALL.value, 'auto']),
    width: PropTypes.number,
    defaultValue: PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.shape(selectOptionShape)
    ]),
    classNamePrefix: PropTypes.string,
    options: PropTypes.arrayOf(PropTypes.shape(selectOptionShape)),
    placeholder: PropTypes.string,
    hiddenLabel: PropTypes.bool,
    isSearchable: PropTypes.bool,
    withBackground: PropTypes.bool,
    inline: PropTypes.bool,
    error: PropTypes.string,
    hookFormControl: PropTypes.object,
    validationRules: PropTypes.object,
    onChange: PropTypes.func,
    required: PropTypes.bool,
    i18n: PropTypes.shape({
        fieldRequired: PropTypes.string
    })
};

SpecificSelect.defaultProps = {
    name: null,
    label: null,
    value: undefined,
    type: null,
    theme: null,
    size: null,
    width: null,
    defaultValue: null,
    classNamePrefix: null,
    options: [],
    placeholder: null,
    hiddenLabel: false,
    isSearchable: false,
    withBackground: true,
    inline: false,
    error: null,
    hookFormControl: null,
    validationRules: null,
    onChange: () => null,
    required: false,
    i18n: null
};

export default SpecificSelect;
