<template>
	<div class="file-upload">
		<div class="file-upload__trigger">
			<slot name="activator" :on="handlers" />
		</div>
		<input
			ref="uploadInput"
			type="file"
			accept=".png,.jpg,.jpeg,.gif"
			@change="onFileChanged"
		>
		<w-dialog
			v-model="cropDialog"
			dialog-class="file-upload__dialog"
			width="500"
			persistent
		>
			<section-title icon="mdi mdi-crop">
				Crop image
				<spacer />
				<w-button
					
					color="black"
					icon="mdi mdi-close"
					@click="cropDialog = false"
				/>
			</section-title>

			<w-divider />

			<cropper
				class="file-upload__cropper"
				:src="cropData"
				v-bind="cropProps"
				@change="onFileCropped"
			/>

			<w-divider />

			<div class="file-upload__options">
				<w-button
					bg-color="accent-1"
					color="white"
					class="file-upload__continue"
					@click="confirmCrop"
				>
					Continue
					<w-icon class="right">
						mdi mdi-check
					</w-icon>
				</w-button>
			</div>
		</w-dialog>
	</div>
</template>

<script lang="ts">
import Vue from 'vue';
import { Optional } from '../typings/helpers';

export default Vue.extend({
	name: 'FileUpload',

	props: {
		showCropper: {
			type: Boolean
		},
		cropProps: {
			type: Object,
			default: () => {}
		}
	},

	data: () => ({
		cropDialog: false,
		cropData: null,
		cropCanvas: undefined as Optional<HTMLCanvasElement>,
		fileName: ''
	}),

	computed: {
		hasPreviewListener(): boolean {
			return this.$listeners && !!this.$listeners.preview;
		},
		handlers(): any {
			return {
				click: this.openPicker
			};
		}
	},

	methods: {
		openPicker() {
			(this.$refs.uploadInput as any).click();
		},
		createPreview(data: Blob, callback: (result: any) => void) {
			let reader = new FileReader();

			reader.onload = (event: any) => {
				callback(event.target.result);
			};

			reader.readAsDataURL(data);
		},
		onFileChanged(e: any) {
			const file: File = e.target.files[0];

			this.fileName = file.name;

			// Postpone the emission of input until
			// the crop has been confirmed.
			if(!this.showCropper) {
				this.$emit('input', file);
			}

			// Generate a data URL preview
			if(this.showCropper || this.hasPreviewListener) {
				this.createPreview(file, (result) => {
					if(this.showCropper) {
						this.cropData = result;
						this.cropDialog = true;
					} else {
						this.$emit('preview', result);
					}
				});
			}

			// Reset the input
			e.target.value = '';
		},
		onFileCropped(e: any) {
			this.cropCanvas = e.canvas;
		},
		confirmCrop() {
			this.cropDialog = false;

			if(!this.cropCanvas) return;

			this.cropCanvas.toBlob((blob: Blob|null) => {
				if(!blob) return;

				// Create a new file given the croppped image
				// contents combined with the original file name
				const file = new File([blob], this.fileName);
 
				this.$emit('input', file);

				if(this.hasPreviewListener) {
					this.createPreview(file, (result) => {
						this.$emit('preview', result);
					});
				}
			});
		}
	}
});
</script>

<style lang="scss">
.file-upload {

	input {
		display: none;
	}

	&__dialog {
		@include rounded(xl);

		@include dark {
			background-color: var(--color-shade-2);
		}
	}

	&__cropper {
		@include padding(3, y);

		overflow: hidden;
	}

	&__options {
		display: flex;

		.w-button {
			width: 100%;
		}
	}
}
</style>