import call from './call';

export default class S3FileUploader {
	constructor() {
		this.listeners = {};
	}

	on(event, handler) {
		this.listeners[event] = this.listeners[event] || [];
		this.listeners[event].push(handler);
	}

	trigger(event, data) {
		let handlers = this.listeners[event] || [];
		handlers.forEach(handler => {
			handler.call(this, data);
		});
	}

	upload(file, options) {
		return new Promise(async (resolve, reject) => {
			async function getUploadLink() {
				try {
					let response = await fetch(
						`/api/action/jcloud.api.site.get_upload_link?file=${file.name}`
					);
					let data = await response.json();
					return data.message;
				} catch (e) {
					reject(e);
				}
			}
			const upload_link = await getUploadLink();
			const file_path = upload_link?.fields?.key;

			if (!file_path) {
				return;
			}

			let xhr = new XMLHttpRequest();
			xhr.upload.addEventListener('loadstart', () => {
				this.trigger('start');
			});
			xhr.upload.addEventListener('progress', e => {
				if (e.lengthComputable) {
					this.trigger('progress', {
						uploaded: e.loaded,
						total: e.total
					});
				}
			});
			xhr.upload.addEventListener('load', () => {
				this.trigger('finish');
			});
			xhr.addEventListener('error', () => {
				this.trigger('error');
				reject();
			});
			xhr.onreadystatechange = () => {
				if (xhr.readyState == XMLHttpRequest.DONE) {
					let error;
					if (xhr.status === 200 || xhr.status === 204) {
						let r = null;
						try {
							r = JSON.parse(xhr.responseText);
						} catch (e) {
							r = xhr.responseText;
						}
						let out =
							r.message ||
							call('jcloud.api.site.uploaded_backup_info', {
								file: file.name,
								path: file_path,
								type: file.type,
								size: file.size
							});
						resolve(out || upload_link.fields.key);
					} else {
						// response from aws is in xml
						let xmlDoc = new DOMParser().parseFromString(
							xhr.responseText,
							'text/xml'
						);
						let code =
							xmlDoc.getElementsByTagName('Code')[0].childNodes[0].nodeValue;
						let message =
							xmlDoc.getElementsByTagName('Message')[0].childNodes[0].nodeValue;
						console.error(`${code}: ${message}`);
						error = xhr.responseText;
					}
					if (error && error.exc) {
						console.error(JSON.parse(error.exc)[0]);
					}
					reject(error);
				}
			};

			xhr.open('POST', upload_link.url, true);
			xhr.setRequestHeader('Accept', 'application/json');

			let form_data = new FormData();
			for (let key in upload_link.fields) {
				if (upload_link.fields.hasOwnProperty(key)) {
					form_data.append(key, upload_link.fields[key]);
				}
			}
			if (file) {
				form_data.append('file', file, file.name);
			}

			xhr.send(form_data);
		});
	}
}
