// redux dependencies
import { connect } from 'react-redux'
import createReducer from 'lib/reducer';
import backendRequest, { download } from 'lib/backend';


// react component dependencies
import React, { Component } from 'react'
import Dropzone from 'react-dropzone';
import { upload } from 'lib/backend';
import { defineMessages, injectIntl, FormattedDate } from 'react-intl';

import { Modal } from 'lib/components';
import messages from './messages';


export const attachmentKey = (objType = "objType", objId = "objId") => {
	return [objType, objId].join(":");
};


/* REDUX */
const initialState = {};
const emptyList = {
	status: null,
	data: []
};

let _reducer = createReducer(initialState);

function registerComponent(unitId, objectType, objectId) {
	return {
		type: '@@attachments/REGISTER',
		payload: attachmentKey(objectType, objectId),
		meta: {
			unitId,
			objectType,
			objectId
		}
	}
}


function unregisterComponent(unitId, objectType, objectId) {
	return {
		type: '@@attachments/UNREGISTER',
		payload: attachmentKey(objectType, objectId),
		meta: {
			unitId,
			objectType,
			objectId
		}
	}
}


function fetchAttachments(unitId, objectType, objectId) {
	return {
		type: '@@attachments/FETCH',
		payload: backendRequest(`/api/${unitId}/attachments/${objectType}/${objectId}`),
		meta: {
			key: attachmentKey(objectType, objectId),
			unitId,
			objectType,
			objectId
		}
	}
}


function deleteAttachment(unitId, objectType, objectId, attachmentId) {
	return {
		type: '@@attachments/FETCH',
		payload: backendRequest(`/api/${unitId}/attachments/${objectType}/${objectId}/${attachmentId}`, "DELETE"),
		meta: {
			unitId,
			objectType,
			objectId,
			attachmentId
		}
	}
}

//@PutMapping("/{unitId}/attachments/{objectType}/{objectId}/{attachmentId}")
function renameAttachment(unitId, objectType, objectId, attachmentId, name) {
	return {
		type: '@@attachment/RENAME',
		payload: backendRequest(`/api/${unitId}/attachments/${objectType}/${objectId}/${attachmentId}`, "PUT", {
			body: name
		}),
		meta: {
			unitId,
			objectType,
			objectId,
			attachmentId,
			name
		}
	}
}

_reducer.handleAction("@@attachments/REGISTER", (state, action) => state.updateIn([action.payload, "count"], val => isNaN(val) ? 1 : val + 1 ));
_reducer.handleAction("@@attachments/UNREGISTER", (state, action) => {
	let count = state.getIn([action.payload, "count"], 0);
	if (count < 2) {
		state = state.remove(action.payload);
	} else {
		state = state.updateIn([action.payload, "count"], val => val - 1);
	}
	return state;
} );



_reducer.handleAction("@@attachments/FETCH_PENDING", (state, action) => state.setIn([action.meta.key, "list", "status"], "pending") );
_reducer.handleAction("@@attachments/FETCH_FULFILLED", (state, action) => state.setIn([action.meta.key, "list", "status"], "success").setIn([action.meta.key, "list", "data"], action.payload.body) );
_reducer.handleAction("@@attachments/FETCH_REJECTED", (state, action) => state.setIn([action.meta.key, "list", "status"], "failure").deleteIn([action.meta.key, "list", "data"]) );



//export reducer
export const reducer = _reducer.export();


/* ******************************************* */
/* UI Components                               */
/* ******************************************* */

require("./attachment.scss")


class AttachmentNameForm extends Component {

	constructor(props) {
		super(props);

		this.initData = this.initData.bind(this);

		this.state = { name: "" };
	}	


	initData(props) {
		this.setState({ name: props.name });
	}

	componentWillMount() {
		this.initData(this.props);
	}

	componentWillReceiveProps(props) {
		if (props.name != this.props.name) {
			this.initData(props);
		}		
	}


	render() {
		return (
			<div>
				<div>
					<input type="text" onChange={ (e) => this.setState({ name: e.target.value }) } value={ this.state.name } />
				</div>
				<div>
					<button type="button" onClick={ () => typeof this.props.onSubmit === "function" && this.props.onSubmit(this.props.item, this.state.name) }>Ok</button>
					<button type="button" onClick={ () => typeof this.props.onCancel === "function" && this.props.onCancel() }>Cancel</button>
				</div>
			</div>
		);
	}

}



class Attachments extends Component {

	constructor(props) {
		super(props);

		this.onDrop = this.onDrop.bind(this);
		this.renderRow = this.renderRow.bind(this);
		this.deleteRow = this.deleteRow.bind(this);
		this.renameRow = this.renameRow.bind(this);

		this.state = { modal: null };
	}


    async onDrop(acceptedFiles, rejectedFiles) {
    	const { unitId, objectType, objectId, disabled } = this.props;

    	if (disabled) {
    		//TODO warn the user
    		return;
    	}

		for (let i = 0; i < acceptedFiles.length; i++) {
			await upload(`/api/${unitId}/attachments/${objectType}/${objectId}`, acceptedFiles[i]);
			//await this.props.uploadAttachment(unitId, objectType, objectId, acceptedFiles[i]);
	    }

    	await this.props.fetchData();
    }


    async deleteRow(id) {
    	await this.props.deleteAttachment(id);
    	await this.props.fetchData();
    }


    async renameRow(item, name) {
    	try {
    		await this.props.renameAttachment(item.id, name);
    		this.setState({ modal: null, item: null });
    	} catch (e) {
    		console.error(e);
    	}
    	await this.props.fetchData();
    }

	componentWillReceiveProps(props) {
		//clearInfoMessages(this);
		if (props.objectId != this.props.objectId) {
			this.props.fetchData();
		}
	}


	//TODO ensure data
	componentWillMount() {
		this.props.registerComponent();

		//refresh list?
		const { status } = this.props;
		if (status !== "pending" && this.props.objectId) {
			this.props.fetchData();
		}
	}
	

	componentWillUnmount() {
		this.props.unregisterComponent();
	}
	

	renderRow(item, idx) {
		const { unitId, objectType, objectId, disabled } = this.props;
		return (
			<div key={idx} className="list-row bottom-border">
				<div className="row-content">
					<div className="float-left left p10-5">
						<div className="main">
							{ item.name }
						</div>
						<div className="secondary">
							{ item.mimeType }
						</div>
					</div>
				</div>
				<div className="row-menu">
					<button 
						className="icon" 
						type="button" 
						onClick={ (e) => this.setState({ modal: item.name, item: item }) }>
						
					</button>
					<button 
						className="icon" 
						type="button" 
						onClick={ (e) => download('/api/' + unitId + '/attachments/' + objectType + '/' + objectId + '/' + item.id) }>
						
					</button>  
					<button 
						className="icon" 
						type="button" 
						onClick={ (e) => this.deleteRow(item.id) }>
						
					</button>
				</div>
			</div>
		);
	}

	render() {
		let { 
			intl, 
			status, 
			error, 
			data,
			showList = true, 
			showDropzone = true,
			editable = true,
			disabled,
			unitId, 
			objectType, 
			objectId, 
			icon = ""
		} = this.props;

		
		return (
			<div className={`attachments ${this.props.className||""} ${ disabled ? "disabled" : ""}`}>
				<h3>
					<i className="icon">{ icon }</i> { intl.formatMessage(messages.title) }
				</h3>

				<Dropzone onDrop={this.onDrop} className="dropzone" disabled={ disabled }>
					<i className="icon"></i>{ intl.formatMessage(messages.hint) }
				</Dropzone>

				{ showList ? (
				<div className="row-margin-10">
					<div className="row">
						{ data && data.length ? data.map(this.renderRow) : null }
					</div>
				</div>
				) : null }

				<Modal show={ !!this.state.modal } onClose={ () => this.setState({ modal: null, item:null }) }>
					<AttachmentNameForm 
						name={ this.state.modal } 
						item={ this.state.item }
						onCancel={ () => this.setState({ modal: null, item: null }) }
						onSubmit={ this.renameRow }
						/>
				</Modal>
			</div>
			);
	}
}


const mapStateToProps = (state, props) => {
	let s = state.getIn(["attachment", attachmentKey(props.objectType, props.objectId), "list"]);
	if (!s) {
		return emptyList;
	}
	return s.toJS();
}



function mapDispatchToProps(dispatch, props) {
	return {
    	registerComponent: () => dispatch(registerComponent(props.unitId, props.objectType, props.objectId)),
    	unregisterComponent: () => dispatch(unregisterComponent(props.unitId, props.objectType, props.objectId)),
    	fetchData: () => dispatch(fetchAttachments(props.unitId, props.objectType, props.objectId)),
    	deleteAttachment: (attachmentId) => dispatch(deleteAttachment(props.unitId, props.objectType, props.objectId, attachmentId)),
    	renameAttachment: (attachmentId, name) => dispatch(renameAttachment(props.unitId, props.objectType, props.objectId, attachmentId, name))
  	};
}


Attachments = connect(mapStateToProps, mapDispatchToProps)(Attachments);

export default injectIntl(Attachments);

