export default class UploadAdapter {
	constructor( loader, options ) {
		this.loader = loader;
		this.options = options;
	}

	upload() {
		return this.loader.file
			.then( file => new Promise( ( resolve, reject ) => {
				this._initRequest();
				this._initListeners( resolve, reject, file );
				this._sendRequest( file );
			} ) );
	}

	abort() {
		if ( this.xhr ) {
			this.xhr.abort();
		}
	}

	_initRequest() {
		const xhr = this.xhr = new XMLHttpRequest();

		xhr.open( 'POST', this.options.upload.uploadUrl, true );
		xhr.responseType = 'json';
	}

	_initListeners( resolve, reject, file ) {
		const xhr = this.xhr;
		const loader = this.loader;
		const genericErrorText = `Couldn't upload file: ${ file.name }.`;

		xhr.addEventListener( 'error', () => reject( genericErrorText ) );
		xhr.addEventListener( 'abort', () => reject() );
		xhr.addEventListener( 'load', () => {
			const response = xhr.response;
			if ( !response || response.code == 0 ) {
				return reject( response && response.code == 0 ? response.message : genericErrorText );
			}
			resolve( {
				default: response.data.url ? response.data.url : response.data.src
			} );
		} );

		if ( xhr.upload ) {
			xhr.upload.addEventListener( 'progress', evt => {
				if ( evt.lengthComputable ) {
					loader.uploadTotal = evt.total;
					loader.uploaded = evt.loaded;
				}
			} );
		}
	}

	_sendRequest( file ) {
		// Set headers if specified.
		const headers = this.options.upload.headers || {};
		const extendData = this.options.upload.extendData || {};
		// Use the withCredentials flag if specified.
		const withCredentials = this.options.upload.withCredentials || false;
		const uploadName = this.options.upload.uploadName || 'file';
		for (const headerName of Object.keys(headers)) {
			this.xhr.setRequestHeader(headerName, headers[headerName]);
		}
		this.xhr.withCredentials = withCredentials;
		const data = new FormData();
		for (const key of Object.keys(extendData)) {
			data.append(key, extendData[key]);
		}
		data.append( uploadName, file );
		this.xhr.send( data );
	}
}

export function UploadAdapterPlugin( editor ) {
	editor.plugins.get( 'FileRepository' ).createUploadAdapter = ( loader ) => {
		return new UploadAdapter( loader, editor.config._config );
	};
}