import React, { FC, ChangeEvent, useState, useRef } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faUpload } from '@fortawesome/free-solid-svg-icons'
import { BlockBlobClient, AnonymousCredential } from '@azure/storage-blob'

import { useTheme } from '../../hooks'
import { setFieldValue } from '../../actions/forms'
import { showNotification } from '../../actions/notifications'
import { getFieldValue } from '../../selectors/forms'
import { apiFetch } from '../../api/fetch'
import { MEDIA_DEFAULT_MAX_SIZE } from '../../constants'
import { AppState, AppThunkDispatch, SasResponse, NotificationType } from '../../types'

import Progress from '../../components/progress'
import FieldLabel from '../../components/controls/field-label'
import AvatarEditor from '../../components/avatar-editor'

interface Props {
    name: string
    label: string
    width: number
    height: number
    help?: string
    previewWidth?: number
    maxSize?: number
}

const FileField: FC<Props> = props => {
    const theme = useTheme()
    const value = useSelector<AppState, string>(state => getFieldValue<string>(state, props.name, ''))
    const dispatch = useDispatch<AppThunkDispatch>()

    const [progress, setProgress] = useState(0)
    const [file, setFile] = useState<File | undefined>()
    const [uploading, setUploading] = useState(false)
    const [uploaded, setUploaded] = useState(false)

    const {
        name,
        label,
        width,
        height,
        help,
        previewWidth = 128,
        maxSize = MEDIA_DEFAULT_MAX_SIZE,
    } = props

    const handleChange = async (event: ChangeEvent<HTMLInputElement>) => {
        if (event.target.files && event.target.files[0]) {
            if (event.target.files[0].size > maxSize) {
                const maxSizeString = Math.round(maxSize / 1024 / 1024)
                dispatch(showNotification(NotificationType.Error, `Files must be less than ${maxSizeString} MBs`))
                return
            }

            setFile(event.target.files[0])
        }
    }

    const handleUpload = async () => {
        if (!file) return
        setUploading(true)

        const ext = file.name.substring(file.name.lastIndexOf('.'))
        const { sas, blobUrl, id } = await apiFetch<SasResponse>({ path: '/v1/sas' })
        const filename = `${id}${ext}`
        const url = `${blobUrl}/${filename}`

        try {
            const blockBlobClient = new BlockBlobClient(`${url}?${sas}`, new AnonymousCredential())
            await blockBlobClient.uploadBrowserData(file, {
                onProgress: p => {
                    setProgress((p.loadedBytes / file.size) * 100)
                }
            })

            await apiFetch({
                path: '/v1/media',
                method: 'post',
                body: {
                    name: filename,
                    size: file.size,
                    type: file.type,
                    originalName: file.name,
                }
            })

            dispatch(setFieldValue(name, url))
            setUploaded(true)
        } catch (err) {
            console.error(err)
            dispatch(showNotification(NotificationType.Error, `Upload error: ${err}`))
        }

        setUploading(false)
    }

    const handleDelete = async () => {
        if (uploaded) {
            await apiFetch({
                path: `/v1/media?name=${value}`,
                method: 'delete',
            })
        }

        dispatch(setFieldValue(name, ''))
    }

    if (file) {
        return (
            <div className="field">
                <FieldLabel>{label} (<span style={{ color: theme.red }}>Unsaved</span>)</FieldLabel>
                <AvatarEditor
                    file={file}
                    width={width}
                    height={height} />
            </div>
        )
    }

    if (uploading) {
        return (
            <div className="field">
                <FieldLabel>{label}</FieldLabel>
                <Progress value={progress} />
            </div>
        )
    }

    return (
        <div className="field">
            <FieldLabel>{label}</FieldLabel>
            {value &&
                <div style={{ padding: '1rem 0px' }}>
                    <img src={value} style={{ width: previewWidth }} />
                    <div style={{ color: theme.secondary, fontSize: '0.8rem' }}>
                        <a style={{ color: theme.red }} onClick={() => handleDelete()}>Delete</a>
                    </div>
                </div>
            }
            {!value &&
                <div>
                    <label className="file-input" style={{ backgroundColor: theme.primary, color: theme.primaryAlternate }}>
                        <input type="file" name={name} onChange={handleChange} />
                        <span className="button-icon">
                            <FontAwesomeIcon icon={faUpload} />
                        </span>
                        <span>Choose a file...</span>
                    </label>
                    <p className="help" style={{ color: theme.text }}>{help}</p>
                </div>
            }
        </div>
    )
}

export default FileField
