import React from 'react'
import PropTypes from 'prop-types'
import {isValidFileType, validateInput} from 'common-fe/utils/validation'
import FormError, {reason} from 'common-fe/utils/form-error'
import inputNames from 'common-fe/constants/input-names'
import Button from 'react-uikit/button'
import {Flex, Grid} from 'react-uikit/layout'
import FileInput from 'react-uikit/input-file'
import Form from 'react-uikit/form'
import UploadTarget from './partials/upload-target'

import BEMModule from 'utils/bem'
import styles from './styles.scss'

const bem = new BEMModule(styles)

class FileUploadForm extends React.PureComponent {
    static formName = 'file-upload'

    static defaultState = {
        data: {
            [inputNames.FILES]: null,
            [inputNames.FILE_URL]: null,
        },
        error: {},
    }

    get initialState() {
        const {initialFileUrl = null} = this.props

        return {
            data: {
                ...FileUploadForm.defaultState.data,
                [inputNames.FILE_URL]: initialFileUrl,
            },
            error: {...FileUploadForm.defaultState.error},
        }
    }

    change = ({value}) => {
        this.props.onChange &&
            this.props.onChange({
                [inputNames.FILES]: value[inputNames.FILES],
                [inputNames.FILE_URL]: value[inputNames.FILE_URL],
            })
    }

    delete = () => {
        this.props.onChange &&
            this.props.onChange({...FileUploadForm.defaultState.data})
    }

    submit = (data) => {
        const {onSubmit} = this.props

        const files = data ? data.files : null

        onSubmit?.({files}).catch((err) => this.handleError(err))
    }

    handleError = (err) => {
        const {onError} = this.props
        if (!err.inlineErrors || !err.inlineErrors.length || !onError) {
            return
        }

        const error = new FormError(
            Object.keys(FileUploadForm.defaultState.data),
            err.inlineErrors
        )

        onError && onError(error)
    }

    validate = ({name, value: file, isRequired}) => {
        const {accept: acceptedTypes, maxSize, valid, onValid} = this.props
        let error = validateInput({name, file, isRequired})

        // TODO: validate multiples files
        if (file && !isValidFileType(file.type, acceptedTypes)) {
            error = reason.FILE_INVALID_ERR
        }

        if (file && file.size > maxSize) {
            error = reason.FILE_SIZE_EXCEEDED_ERR
        }

        onValid(valid)
        return error
    }

    render() {
        const {
            accept,
            data,
            error,
            iconName,
            maxSize,
            multiple,
            showPreview,
            onError,
        } = this.props

        const rootClasses = bem.classNames('c-file-upload')
        const wrapperClasses = bem.classNames('c-file-upload__wrapper')
        const buttonClasses = bem.classNames('c-file-upload__button')

        const Input = ({...formProps}) => (
            <FileInput
                accept={accept}
                iconName={iconName}
                maxSize={maxSize}
                multiple={multiple}
                previewUrl={data[inputNames.FILE_URL]}
                render={UploadTarget}
                showPreview={showPreview}
                {...formProps}
            />
        )

        return (
            <Form
                className={rootClasses}
                data={data}
                error={error}
                name={FileUploadForm.formName}
                validate={this.validate}
                onChange={this.change}
                onError={onError}
                onSubmit={this.submit}
            >
                <Flex
                    align="center"
                    className={wrapperClasses}
                    direction="column"
                >
                    <Form.Field render={Input} name={inputNames.FILES} />
                </Flex>

                <Form.SubmitTrigger
                    render={({submit}) => (
                        <Grid templateColumns="1fr 1fr">
                            <Button
                                className={buttonClasses}
                                variant="neutral"
                                text="Delete"
                                onClick={this.delete}
                            />
                            <Button
                                className={buttonClasses}
                                variant="primary"
                                text="Save"
                                onClick={submit}
                            />
                        </Grid>
                    )}
                />
            </Form>
        )
    }
}

FileUploadForm.propTypes = {
    accept: PropTypes.array,
    data: PropTypes.object,
    error: PropTypes.object,
    iconName: PropTypes.string,
    initialFileUrl: PropTypes.string,
    maxSize: PropTypes.number,
    multiple: PropTypes.bool,
    showPreview: PropTypes.bool,
    user: PropTypes.object,
    valid: PropTypes.bool,
    onChange: PropTypes.func,
    onError: PropTypes.func,
    onSubmit: PropTypes.func,
    onValid: PropTypes.func,
}

FileUploadForm.defaultProps = {
    data: {...FileUploadForm.defaultState.data},
    error: {...FileUploadForm.defaultState.error},
    validateOnUpdate: true,
}

export default FileUploadForm
