// Lib
import React, {Component} from 'react';
import {withNamespaces} from 'react-i18next';
import FormUnique from '../FormUnique';
import {ID} from "@formanta/js";
import {fileSize2Human} from "@formanta/js";

import {withTheme, injectSheet} from '../../lib/theme';
import {ButtonSmall} from "../Form";
import FilePreview from "./FilePreview";
import {storeUpload} from "../../feature/Media/Stores/Upload";

const styling = theme => ({
    wrapper: {
        margin: '0'
    },
    dropArea: {
        background: theme.drop.area,
        minHeight: '60px',
        transition: '0.2s linear background',
        '&.dropping': {
            background: theme.drop.area_targeted,
        }
    },
    controlText: {
        display: 'flex',
        padding: theme.gutter.base * 2 + 'px',
        margin: 0,
        alignItem: 'center'
    },
    duplicateFiles: {
        padding: theme.gutter.base * 2 + 'px',
    },
    filePreviews: {
        display: 'flex',
        flexWrap: 'wrap'
    },
    totalSize: {
        fontSize: '0.875rem',
        padding: theme.gutter.base + 'px 0 0 0',
    }
});

const DuplicateFiles = withNamespaces('file-upload')(withTheme(injectSheet(styling)((props) => (
    props.duplicateFiles && 0 < props.duplicateFiles.length ?
        <div className={props.classes.duplicateFiles} style={{border: '1px solid ' + props.theme.errorColor}}>
            <p>{props.t('duplicate-files')}</p>
            <ul>
                {props.duplicateFiles.map((elem, i) => <li key={i}>{elem.name}</li>)}
            </ul>
        </div> : null
))));

class Uploader extends Component {

    state = {
        dropping: false,
        files: {},
        fileNames: [],
        totalSize: 0,
        duplicateFiles: false,
    };

    id = '';

    evts = {};


    componentWillMount() {
        this.id = FormUnique();
    }

    componentWillUnmount() {
        this.evts = {};
    }

    componentDidMount() {
    }

    preventDefaults = (e) => {
        e.preventDefault();
        e.stopPropagation()
    };

    handleDragHighlight = (evt) => {
        this.preventDefaults(evt);
        evt.dataTransfer.dropEffect = 'copy';
        this.setState({
            dropping: true
        });
    };

    handleDragUnhighlight = (evt) => {
        this.preventDefaults(evt);
        this.setState({
            dropping: false
        });
    };

    handleDrop = (evt) => {
        this.handleDragUnhighlight(evt);

        let dt = evt.dataTransfer;
        let files = dt.files;

        this.handleFiles(files)
    };

    handleFileInput = (evt) => {
        this.handleFiles(evt.target.files);
    };

    handleFiles = (files) => {
        let current_files = {...this.state.files};
        let current_file_names = [...this.state.fileNames];
        let totalSize = this.state.totalSize;
        let duplicate_files = [];

        [...files].forEach((file) => {
            if(-1 === this.state.fileNames.indexOf(file.name)) {
                let id = ID();
                current_files[id] = {
                    progress: 'init',
                    id,
                    file
                };

                current_file_names.push(file.name);
                totalSize += file.size;
            } else {
                console.error('Duplicate file added with name: ' + file.name);
                duplicate_files.push(file);
            }
        });

        this.setState({
            files: current_files,
            fileNames: current_file_names,
            duplicateFiles: duplicate_files,
            totalSize,
        });
    };

    undropFile = (id) => {
        let current_files = {...this.state.files};
        let current_file_names = [...this.state.fileNames];
        let totalSize = this.state.totalSize;

        current_file_names.splice(current_file_names.indexOf(current_files[id].file.name), 1);

        totalSize -= current_files[id].file.size;
        delete current_files[id];

        this.setState({
            files: current_files,
            fileNames: current_file_names,
            totalSize,
        });
    };

    clearAll = () => {
        this.setState({
            files: {},
            fileNames: [],
            totalSize: 0,
        });
    };

    clearFinished = () => {
        let current_files = {...this.state.files};
        let current_file_names = [...this.state.fileNames];
        let totalSize = this.state.totalSize;

        for(let id in current_files) {
            if(current_files.hasOwnProperty(id)) {
                if('success' === current_files[id].progress) {
                    totalSize -= current_files[id].file.size;
                    current_file_names.splice(current_file_names.indexOf(current_files[id].file.name), 1);
                    delete current_files[id];
                }
            }
        }

        this.setState({
            files: current_files,
            fileNames: current_file_names,
            totalSize: totalSize,
        });
    };

    uploadFiles = () => {
        const files = {...this.state.files};
        const {target, uploadFiles} = this.props;

        const evtid = ID();
        this.evts[evtid] = true;
        const updateProg = (id, progress) => {
            if(this.evts[evtid]) {
                this.updateProgress(id, progress);
            }
        };

        uploadFiles(files, target, updateProg);
    };

    updateProgress = (id, progress) => {
        let current_files = {...this.state.files};

        if(current_files[id]) {
            current_files[id].progress = progress;
        }

        this.setState({
            files: current_files,
        });
    };

    render() {
        const {t, classes, theme, style} = this.props;

        return (
            <div className={classes.wrapper} style={style}>
                <div className={classes.dropArea + ' ' + (this.state.dropping ? 'dropping' : '')}
                     onDragEnter={this.handleDragHighlight}
                     onDragOver={this.handleDragHighlight}
                     onDragLeave={this.handleDragUnhighlight}
                     onDrop={this.handleDrop}>
                    <input type="file" id={'fileInp' + this.id} multiple size="50" onChange={this.handleFileInput} style={{display: 'none'}}/>

                    <p className={classes.controlText}>
                        <label htmlFor={'fileInp' + this.id} style={{margin: '0 ' + theme.gutter.base + 'px 0 auto', borderBottom: '1px solid ' + theme.textColorLight, cursor: 'pointer'}}>{t('upload-new--select')}</label>
                        <span>{t('upload-new--or')}</span>
                        <span style={{margin: '0 auto 0 ' + theme.gutter.base + 'px',}}>{t('upload-new--dragndrop')}</span>
                    </p>

                    <DuplicateFiles duplicateFiles={this.state.duplicateFiles}/>

                    {this.state.files && 0 < this.state.fileNames.length ?
                        <div className={classes.filePreviews}>
                            {Object.keys(this.state.files).map((id) => {
                                return <FilePreview file={this.state.files[id].file}
                                                    progress={this.state.files[id].progress}
                                                    key={id}
                                                    id={id}
                                                    delete={this.undropFile}/>;
                            })}
                        </div> : null}

                    <DuplicateFiles duplicateFiles={this.state.duplicateFiles}/>

                    {this.state.files && 0 < this.state.fileNames.length ?
                        <p className={classes.totalSize}>{t('total.qty')} {this.state.fileNames.length}, {t('total.size')} {fileSize2Human(this.state.totalSize)}</p> : null}
                </div>

                {this.state.files && 0 < this.state.fileNames.length ?
                    <ButtonSmall onClick={this.uploadFiles}>{t('upload-to-dir')}</ButtonSmall>
                    : null}
                {this.state.files && 0 < this.state.fileNames.length ?
                    <ButtonSmall onClick={this.clearAll} style={{marginLeft: '-1px'}}>{t('clear-all')}</ButtonSmall>
                    : null}
                {this.state.files && 0 < this.state.fileNames.length ?
                    <ButtonSmall onClick={this.clearFinished} style={{marginLeft: '-1px'}}>{t('clear-finished')}</ButtonSmall>
                    : null}
            </div>
        );
    };
}

export default withNamespaces('file-upload')(storeUpload(withTheme(injectSheet(styling)(Uploader))));