import AbstractModel from './abstractModel';
import UserModel from './user'
import LabelModel from './label'
import AttachmentModel from './attachment'

export default class TaskModel extends AbstractModel {

	defaultColor = '198CFF'

	constructor(data) {
		super(data)

		this.id = Number(this.id)
		this.listId = Number(this.listId)

		// Make date objects from timestamps
		this.dueDate = this.dueDate ? new Date(this.dueDate) : null
		this.startDate = this.startDate ? new Date(this.startDate) : null
		this.endDate = this.endDate ? new Date(this.endDate) : null

		// Cancel all scheduled notifications for this task to be sure to only have available notifications
		this.cancelScheduledNotifications()
			.then(() => {
				this.reminderDates = this.reminderDates.map(d => {
					d = new Date(d)
					// Every time we see a reminder, we schedule a notification for it
					this.scheduleNotification(d)
					return d
				})
				this.reminderDates.push(null) // To trigger the datepicker
			})

		// Parse the repeat after into something usable
		this.parseRepeatAfter()
		
		// Parse the assignees into user models
		this.assignees = this.assignees.map(a => {
			return new UserModel(a)
		})
		this.createdBy = new UserModel(this.createdBy)
		
		this.labels = this.labels.map(l => {
			return new LabelModel(l)
		})

		// Set the default color
		if (this.hexColor === '') {
			this.hexColor = this.defaultColor
		}
		if (this.hexColor.substring(0, 1) !== '#') {
			this.hexColor = '#' + this.hexColor
		}

		// Make all subtasks to task models
		Object.keys(this.relatedTasks).forEach(relationKind  => {
			this.relatedTasks[relationKind] = this.relatedTasks[relationKind].map(t => {
				return new TaskModel(t)
			})
		})

		// Make all attachments to attachment models
		this.attachments = this.attachments.map(a => {
			return new AttachmentModel(a)
		})

		// Set the task identifier to empty if the list does not have one
		if(this.identifier === `-${this.index}`) {
			this.identifier = ''
		}

		this.created = new Date(this.created)
		this.updated = new Date(this.updated)
	}
	
	defaults() {
		return {
			id: 0,
			text: '',
			description: '',
			done: false,
			priority: 0,
			labels: [],
			assignees: [],
			
			dueDate: 0,
			startDate: 0,
			endDate: 0,
			repeatAfter: 0,
			reminderDates: [],
			parentTaskId: 0,
			hexColor: '',
			percentDone: 0,
			relatedTasks: {},
			attachments: [],
			identifier: '',
			index: 0,

			createdBy: UserModel,
			created: null,
			updated: null,
			
			listId: 0, // Meta, only used when creating a new task
		}
	}
	
	/////////////////
	// Helper functions
	///////////////
	
	/**
	 * Parses the "repeat after x seconds" from the task into a usable js object inside the task.
	 * This function should only be called from the constructor.
	 */
	parseRepeatAfter() {
		let repeatAfterHours = (this.repeatAfter / 60) / 60
		this.repeatAfter = {type: 'hours', amount: repeatAfterHours}

		// if its dividable by 24, its something with days, otherwise hours
		if (repeatAfterHours % 24 === 0) {
			let repeatAfterDays = repeatAfterHours / 24
			if (repeatAfterDays % 7 === 0) {
				this.repeatAfter.type = 'weeks'
				this.repeatAfter.amount = repeatAfterDays / 7
			} else if (repeatAfterDays % 30 === 0) {
				this.repeatAfter.type = 'months'
				this.repeatAfter.amount = repeatAfterDays / 30
			} else if (repeatAfterDays % 365 === 0) {
				this.repeatAfter.type = 'years'
				this.repeatAfter.amount = repeatAfterDays / 365
			} else {
				this.repeatAfter.type = 'days'
				this.repeatAfter.amount = repeatAfterDays
			}
		}
	}

	/**
	 * Checks if the hexColor of a task is dark.
	 * @returns {boolean}
	 */
	hasDarkColor() {
		if (this.hexColor === '#') {
			return true // Defaults to dark
		}

		let rgb = parseInt(this.hexColor.substring(1, 7), 16);   // convert rrggbb to decimal
		let r = (rgb >> 16) & 0xff;  // extract red
		let g = (rgb >>  8) & 0xff;  // extract green
		let b = (rgb >>  0) & 0xff;  // extract blue

		// luma will be a value 0..255 where 0 indicates the darkest, and 255 the brightest
		let luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; // per ITU-R BT.709
		return luma > 128
	}

	async cancelScheduledNotifications() {
		if (!('showTrigger' in Notification.prototype)) {
			console.debug('This browser does not support triggered notifications')
			return
		}

		const registration = await navigator.serviceWorker.getRegistration()
		if (typeof registration === 'undefined') {
			return
		}

		// Get all scheduled notifications for this task and cancel them
		const scheduledNotifications = await registration.getNotifications({
			tag: `vikunja-task-${this.id}`,
			includeTriggered: true,
		})
		console.debug('Already scheduled notifications:', scheduledNotifications)
		scheduledNotifications.forEach(n => n.close())
	}

	async scheduleNotification(date) {

		if(date < new Date()) {
			console.debug('Date is in the past, not scheduling a notification. Date is ', date)
			return
		}

		if (!('showTrigger' in Notification.prototype)) {
			console.debug('This browser does not support triggered notifications')
			return
		}

		const {state} = await navigator.permissions.request({name: 'notifications'});
		if (state !== 'granted') {
			console.debug('Notification permission not granted, not showing notifications')
			return
		}

		const registration = await navigator.serviceWorker.getRegistration()
		if (typeof registration === 'undefined') {
			console.error('No service worker registration available')
			return
		}

		// Register the actual notification
		registration.showNotification('Vikunja Reminder', {
			tag: `vikunja-task-${this.id}`, // Group notifications by task id so we're only showing one notification per task
			body: this.text,
			// eslint-disable-next-line no-undef
			showTrigger: new TimestampTrigger(date),
			badge: '/images/icons/badge-monochrome.png',
			icon: '/images/icons/android-chrome-512x512.png',
			data: {taskId: this.id},
			actions: [
				{
					action: 'mark-as-done',
					title: 'Done'
				},
				{
					action: 'show-task',
					title: 'Show task'
				},
			],
		})
		.then(() => {
			console.debug('Notification scheduled for ' + date)
		})
		.catch(e => {
			console.debug('Error scheduling notification', e)
		})
	}
}

