<template>
	<!-- Bulk contacts edit modal -->
	<Modal v-if="isProcessing || isProcessDone"
		:clear-view-delay="-1"
		:can-close="isProcessDone"
		@close="closeProcess">
		<AddToGroupView v-bind="processStatus" @close="closeProcess" />
	</Modal>

	<!-- contacts picker -->
	<EntityPicker v-else-if="showPicker"
		:confirm-label="t('contacts', 'Add to {group}', { group: pickerforGroup.name })"
		:data-types="pickerTypes"
		:data-set="pickerData"
		@close="onContactPickerClose"
		@submit="onContactPickerPick" />
</template>

<script>
import { subscribe } from '@nextcloud/event-bus'
import pLimit from 'p-limit'

import Modal from '@nextcloud/vue/dist/Components/Modal'

import AddToGroupView from '../../views/Processing/AddToGroupView'
import appendContactToGroup from '../../services/appendContactToGroup'
import EntityPicker from './EntityPicker'

export default {
	name: 'ContactsPicker',

	components: {
		AddToGroupView,
		EntityPicker,
		Modal,

	},

	data() {
		return {
			// Entity picker
			showPicker: false,
			pickerforGroup: null,
			pickerData: [],
			pickerTypes: [{
				id: 'contact',
				label: t('contacts', 'Contacts'),
			}],

			// Bulk processing
			isProcessing: false,
			isProcessDone: false,
			processStatus: {
				failed: 0,
				progress: 0,
				success: 0,
				total: 0,
				name: '',
			},
		}
	},
	computed: {
		contacts() {
			return this.$store.getters.getContacts
		},
		groups() {
			return this.$store.getters.getGroups
		},
		sortedContacts() {
			return this.$store.getters.getSortedContacts
		},
	},

	mounted() {
		// Watch for a add-to-group event
		subscribe('contacts:group:append', this.addContactsToGroup)
	},

	methods: {
		// Bulk contacts group management handlers
		addContactsToGroup(group) {
			console.debug('Contacts picker opened for group', group)

			// Get the full group if we provided the group name only
			if (typeof group === 'string') {
				group = this.groups.find(a => a.name === group)
				if (!group) {
					console.error('Cannot add contact to an undefined group', group)
					return
				}
			}

			// Init data set
			this.pickerData = this.sortedContacts
				.map(({ key }) => {
					const contact = this.contacts[key]
					return {
						id: contact.key,
						label: contact.displayName,
						type: 'contact',
						readOnly: contact.addressbook.readOnly,
						groups: contact.groups,
					}
				})
				// No read only contacts
				.filter(contact => !contact.readOnly)
				// No contacts already present in group
				.filter(contact => contact.groups.indexOf(group.name) === -1)

			this.showPicker = true
			this.pickerforGroup = group
		},

		onContactPickerClose() {
			this.pickerData = []
			this.showPicker = false
		},

		onContactPickerPick(selection) {
			console.debug('Adding', selection, 'to group', this.pickerforGroup)
			const groupName = this.pickerforGroup.name

			this.isProcessing = true
			this.showPicker = false

			this.processStatus.total = selection.length
			this.processStatus.name = this.pickerforGroup.name
			this.processStatus.progress = 0
			this.processStatus.failed = 0

			// max simultaneous requests
			const limit = pLimit(3)
			const requests = []

			// create the array of requests to send
			selection.map(async entity => {
				try {
					// Get contact
					const contact = this.contacts[entity.id]

					// push contact to server and use limit
					requests.push(limit(() => appendContactToGroup(contact, groupName)
						.then((response) => {
							this.$store.dispatch('addContactToGroup', { contact, groupName })
							this.processStatus.progress++
							this.processStatus.success++
						})
						.catch((error) => {
							this.processStatus.progress++
							this.processStatus.error++
							console.error(error)
						})
					))
				} catch (e) {
					console.error(e)
				}
			})

			Promise.all(requests).then(() => {
				this.isProcessDone = true
				this.showPicker = false

				// Auto close after 3 seconds if no errors
				if (this.processStatus.failed === 0) {
					setTimeout(this.closeProcess, 3000)
				}
			})
		},

		closeProcess() {
			this.pickerforGroup = null
			this.isProcessing = false
			this.isProcessDone = false

			// Reset
			this.processStatus.failed = 0
			this.processStatus.progress = 0
			this.processStatus.success = 0
			this.processStatus.total = 0
		},
	},
}
</script>
