<template>
	<n-config-provider :theme="darkTheme">
		<div id="all">
			<div id="group_select">
				<n-select v-model:value="selected_group" :options="groups" size="large" />
				<n-button secondary type="primary" @click="showAddGroupModal = true" size="large">
					<n-icon><CreateNewFolderRound /></n-icon>
				</n-button>
			</div>

			<div id="camera">
				<div id="prompt_select" v-show="!selected_group">
					<n-icon size="4em"><HandPointUp/></n-icon><br/>
					<h1 style="font-weight:bold;">Please select a photo group</h1>
				</div>
				<n-spin :show="isCameraLoading || isPhotoTaken" v-show="selected_group">
					<div id="camera_preview">
						<video ref="camera" autoplay></video>
						<canvas v-show="false" id="photoTaken" ref="canvas" width="100" height="100"></canvas>
					</div>
				</n-spin>
			</div>

			<div id="take_photo">
				<n-space justify-content="center">
					<n-button
						type="primary" round size="large"
						:disabled="!selected_group || isPhotoTaken || !isCameraCreated"
						@click="takePhoto"
					>
						Take Photo
					</n-button>
				</n-space>
			</div>
		</div>

		<n-modal
			v-model:show="showAddGroupModal"
			:mask-closable="true"
			transform-origin="center"
			preset="card"
			title="Add new Group"
			:bordered="false"
			size="huge">

			<n-input placeholder="Enter group name" size="large" v-model:value="new_group_name" />

			<template #footer>
				<n-space justify-content="end">
					<n-button size="large" @click="showAddGroupModal = false">Cancel</n-button>
					<n-button type="primary" size="large" @click="addNewGroup">Add Group</n-button>
				</n-space>
			</template>
		</n-modal>

		<n-modal
			v-model:show="showPhotoTakenModal"
			:mask-closable="false"
			transform-origin="center"
			preset="card"
			:title="'Upload Photo to '+selected_group_label"
			:bordered="false"
			size="huge">

			<n-space justify-content="center">
				<n-image
					:src="photo.src"
					:width="photo.width*0.75"
				/>
			</n-space>

			<template #footer>
				<n-space justify-content="end">
					<n-button size="large" @click="showPhotoTakenModal = false; isPhotoTaken = false">Back</n-button>
					<n-button type="primary" size="large" @click="uploadPhoto" :loading="isUploading">Upload</n-button>
				</n-space>
			</template>
		</n-modal>
	</n-config-provider>
</template>

<script>
import { useMeta } from 'vue-meta'
import { useMessage } from 'naive-ui'
import {darkTheme} from 'naive-ui'

import CreateNewFolderRound from '@vicons/material/CreateNewFolderRound'
import HandPointUp from '@vicons/fa/HandPointUp'

import { getPhotoGroups, addNewPhotoGroup, addNewPhoto, cropPhoto } from '@/api'

export default {
	components: {
		CreateNewFolderRound,
		HandPointUp,
	},
	setup() {
		useMeta({
			title: 'Capture new Photo',
		})
		const message = useMessage()
		return { message }
	},
	data() {
		return {
			darkTheme,

			groups: [],
			selected_group: null,

			showAddGroupModal: false,
			new_group_name: '',

			isCameraCreated: false,
			isCameraLoading: true,
			isPhotoTaken: false,
			photo: {
				width: 0,
				height: 0,
				src: null
			},
			stream: {
				width: 0,
				height: 0,
			},

			showPhotoTakenModal: false,
			isUploading: false,
		}
	},
	beforeMount() {
		this.fetchPhotoGroups()
	},
	mounted() {
		window.scrollTo(0, 1)
	},
	watch: {
		selected_group: function () {
			if (this.isCameraCreated)
				return
			this.startCamera()
		},
	},
	computed: {
		selected_group_label() {
			if (this.selected_group !== null && this.groups.length > 0) {
				return this.groups.filter(group => group.value === this.selected_group)[0].label
			}
			return ''
		},
	},
	methods: {
		fetchPhotoGroups() {
			this.groups = []
			getPhotoGroups().then((response) => {
				let data = response.data
				for(const data_idx in data) {
					this.groups.push({
						label: data[data_idx].name,
						value: data[data_idx].id,
					})
				}
			}).catch((error)=>{
				this.message.error('There was an error while fetching photo groups: '+error)
			})
		},
		addNewGroup() {
			if (this.new_group_name.length == 0) {
				this.message.error('Please enter a new group name')
				return
			}
			addNewPhotoGroup(this.new_group_name, null).then((response) => {
				this.message.success('Added group '+this.new_group_name)
				this.fetchPhotoGroups()
				this.showAddGroupModal = false
				this.selected_group = response.data.id
			}).catch((error)=>{
				this.message.error('There was an error while adding the group: '+error)
			}).finally(() => {
				this.new_group_name = ''
			})
		},
		startCamera() {			
			this.isCameraLoading = true

			const constraints = (window.constraints = {
				audio: false,
				video: {
					facingMode: 'environment',
					width: { ideal: 4096 },
					height: { ideal: 2160 },
				}
			})

			navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
				this.isCameraLoading = false
				this.$refs.camera.srcObject = stream
				this.isCameraCreated = true

				let stream_settings = stream.getVideoTracks()[0].getSettings()
				this.stream.width = stream_settings.width
				this.stream.height = stream_settings.height

				this.photo.width = document.getElementById('camera_preview').offsetWidth
				this.photo.height = document.getElementById('camera_preview').offsetHeight

				this.$refs.camera.width = this.photo.width
				this.$refs.camera.height = this.photo.height
			}).catch(error => {
				this.message.error('Cannot load device camera! '+error)
			})
		},
		takePhoto() {
			this.isPhotoTaken = true
			
			setTimeout(() => {
				this.photo.height = document.getElementById('camera_preview').offsetHeight

				this.$refs.canvas.width = this.stream.width
				this.$refs.canvas.height = this.stream.height

				const context = this.$refs.canvas.getContext('2d')
				context.drawImage(
					this.$refs.camera,
					0, 0,
					this.stream.width,
					this.stream.height)

				this.photo.src = this.$refs.canvas.toDataURL('image/png')//.replace('image/png', 'image/octet-stream')
				
				this.showPhotoTakenModal = true
			}, 50)
		},
		uploadPhoto() {
			this.isUploading = true
			const dataURLtoFile = (dataurl, filename) => {
				const arr = dataurl.split(',')
				const mime = arr[0].match(/:(.*?);/)[1]
				const bstr = atob(arr[1])
				let n = bstr.length
				const u8arr = new Uint8Array(n)
				while (n) {
					u8arr[n - 1] = bstr.charCodeAt(n - 1)
					n -= 1 // to make eslint happy
				}
				return new File([u8arr], filename, { type: mime })
			}

			const file = dataURLtoFile(this.photo.src, 'upload.png')
			
			addNewPhoto(file, null, this.selected_group).then((response) => {
				this.message.success('Done!')
				this.isPhotoTaken = false
				this.showPhotoTakenModal = false
				this.isUploading = false

				setTimeout(() => {
					cropPhoto(response.data.id, 'auto').then(()=>{
						console.log('photo has been cropped')
					}).catch((error)=>{
						console.error(error)
					})
				}, 100)
			}).catch((error) => {
				this.message.error('There was an error uploading the photo: ' + error)
			})
		},
	},
}
</script>

<style scoped>
html, body {
	margin: 0;
	padding: 0;
	overflow: hidden;
	height: 100vh;
}

* {
	overflow: hidden;
}

#all {
	background-color: #111;
	width: 100vw;
	height: 100vh;
	display: flex;
	flex-direction: column;
	flex-wrap: nowrap;
	overflow: hidden;
	color: white;
	margin: 0;
	padding: 0;
}

#camera_preview {
	height: 75vh;
}

#group_select {
	display: flex;
	height: 7.5vh;
}

#prompt_select {
	display: flex;
	flex-direction: column;
	text-align: center;
	margin-top: 30%;
}

#prompt_select .n-icon {
	margin: auto;
}

#take_photo {
	height: 15vh;
	background-color: #222;
	display: flex;
	justify-content: center;
	bottom: 0;
	position: absolute;
	width: 100%;
}

#take_photo .n-button {
	margin-top: 30%;
}
</style>