<template>
	<w-dialog
		:value="isVisible"
		dialog-class="task-viewer-dialog"
		class="task-viewer-overlay"
		transition=""
		width="850"
		@close="setTaskHidden"
	>
		<section class="task-viewer" @keydown.esc="saveTask">
			<aside class="task-viewer__sidebar">
				<template v-if="!isLoading">
					
					<!-- ANCHOR Close -->
					<div
						class="task-viewer__sidebar-item"
						@click="setTaskHidden"
					>
						<w-icon>
							mdi mdi-close
						</w-icon>
					</div>

					<w-divider />

					<!-- ANCHOR Join or leave task -->
					<template v-if="$store.state.profile">
						<w-tooltip
							v-if="!isCurrentlyAssigned"
							right
							z-index="600"
						>
							<template #activator="{ on }">
								<div
									class="task-viewer__sidebar-item"
									v-on="on"
									@click="addTaskAssignee($store.state.profile)"
								>
									<w-icon>
										mdi mdi-account-plus
									</w-icon>
								</div>
							</template>
							<span>
								Join task
							</span>
						</w-tooltip>
						<w-tooltip
							v-else
							right
							z-index="600"
						>
							<template #activator="{ on }">
								<div
									class="task-viewer__sidebar-item"
									v-on="on"
									@click="removeTaskAssignee($store.state.profile)"
								>
									<w-icon>
										mdi mdi-account-minus
									</w-icon>
								</div>
							</template>
							<span>
								Leave task
							</span>
						</w-tooltip>
					</template>

					<!-- ANCHOR Upload attachment -->
					<w-tooltip right z-index="600">
						<template #activator="{ on }">
							<div class="task-viewer__sidebar-item" v-on="on">
								<w-icon>
									mdi mdi-upload
								</w-icon>
							</div>
						</template>
						<span>
							Attach file
						</span>
					</w-tooltip>

					<!-- ANCHOR Checklist -->
					<w-tooltip right z-index="600">
						<template #activator="{ on }">
							<div class="task-viewer__sidebar-item" v-on="on">
								<w-icon>
									mdi mdi-checkbox-marked-circle-outline
								</w-icon>
							</div>
						</template>
						<span>
							Checklist
						</span>
					</w-tooltip>

					<!-- ANCHOR Pinned -->
					<w-tooltip
						v-if="!task.isPinned"
						right
						z-index="600"
					>
						<template #activator="{ on }">
							<div
								class="task-viewer__sidebar-item"
								v-on="on"
								@click="toggleTaskPinned"
							>
								<w-icon>
									mdi mdi-pin
								</w-icon>
							</div>
						</template>
						<span>
							Pin task
						</span>
					</w-tooltip>
					<w-tooltip
						v-else
						right
						z-index="600"
					>
						<template #activator="{ on }">
							<div
								class="task-viewer__sidebar-item"
								v-on="on"
								@click="toggleTaskPinned"
							>
								<w-icon>
									mdi mdi-pin-off
								</w-icon>
							</div>
						</template>
						<span>
							Unpin task
						</span>
					</w-tooltip>

					<!-- ANCHOR Move -->
					<w-tooltip right z-index="600">
						<template #activator="{ on }">
							<div class="task-viewer__sidebar-item" v-on="on">
								<w-icon>
									mdi mdi-arrow-right-bottom-bold
								</w-icon>
							</div>
						</template>
						<span>
							Move task
						</span>
					</w-tooltip>

					<!-- ANCHOR Duplicate -->
					<w-tooltip right z-index="600">
						<template #activator="{ on }">
							<div class="task-viewer__sidebar-item" v-on="on">
								<w-icon>
									mdi mdi-content-duplicate
								</w-icon>
							</div>
						</template>
						<span>
							Copy task
						</span>
					</w-tooltip>

					<!-- ANCHOR Watch -->
					<w-tooltip right z-index="600">
						<template #activator="{ on }">
							<div class="task-viewer__sidebar-item" v-on="on">
								<w-icon>
									mdi mdi-eye
								</w-icon>
							</div>
						</template>
						<span>
							Watch
						</span>
					</w-tooltip>

					<!-- ANCHOR Share -->
					<w-tooltip right z-index="600">
						<template #activator="{ on }">
							<div class="task-viewer__sidebar-item" v-on="on">
								<w-icon>
									mdi mdi-share-variant
								</w-icon>
							</div>
						</template>
						<span>
							Share
						</span>
					</w-tooltip>

					<VindiSpacer />

					<!-- ANCHOR Delete -->
					<w-tooltip right z-index="600">
						<template #activator="{ on }">
							<div
								class="task-viewer__sidebar-item"
								v-on="on"
								@click="removeTask"
							>
								<w-icon color="error">
									mdi mdi-delete
								</w-icon>
							</div>
						</template>
						<span>
							Archive
						</span>
					</w-tooltip>
				</template>
			</aside>
			<div class="task-viewer__content">
				<div v-if="isLoading" class="task-viewer__loading">
					<w-progress
						color="primary"
						circle
					/>
				</div>
				<template v-else>
				
					<!-- ANCHOR Parent task -->
					<div
						v-if="task.parentTask"
						class="task-viewer__parent"
						@click="$store.dispatch('openTaskViewer', task.parentTask.id);"
					>
						<w-icon>
							mdi mdi-subdirectory-arrow-right
						</w-icon>
						Child task of
						<span class="task-viewer__parent-summary">
							#{{ task.parentTask.localId }}
							{{ task.parentTask.summary }}
						</span>
					</div>

					<!-- ANCHOR Local id and summary -->
					<div class="task-viewer__row">
						<span
							class="task-viewer__id"
							:style="accentColorStyle"
						>
							#{{ task.localId }}
						</span>
						<w-input
							ref="summary"
							v-model="summary"
							class="task-viewer__summary"
							bg-color="transparent"
							@keydown.enter="$event.target.blur()"
							@blur="updateSummary"
						/>
					</div>

					<w-divider />

					<!-- ANCHOR Author and current list -->
					<div class="task-viewer__row">
						<w-flex :gap="3">
							<VindiAvatar
								:size="30"
								:profile="task.creator"
								@click.native="setTaskHidden"
							/>
							<div>
								<div class="task-viewer__created-by" :style="accentColorStyle">
									Created by {{ task.creator.fullName }}
								</div>
								<div class="task-viewer__created-at">
									{{ creationTime }}
								</div>
							</div>
						</w-flex>
						<VindiSpacer />
						<w-icon :style="accentColorStyle">
							mdi mdi-format-list-bulleted
						</w-icon>
						<w-select
							v-model="taskList"
							class="task-viewer__task-list"
							:items="taskListItems"
							:menu-props="{'z-index': 600}"
							bg-color="transparent"
							color="black"
							no-unselect
						/>
					</div>

					<!-- ANCHOR Description -->
					<div class="task-viewer__description">
						<template v-if="isEditingDesc">
							<VindiEditor
								ref="descEditor"
								v-model="description"
								placeholder="Add a description..."
								class="task-viewer__description-editor"
							/>
							<w-flex :gap="2">
								<VindiSpacer />
								<w-button
									bg-color="transparent"
									icon="mdi mdi-close"
									@click="discardDescription"
								/>
								<w-button
									@click="updateDescription"
								>
									Save
								</w-button>
							</w-flex>
						</template>
						<div
							v-else
							@click="editDescription"
						>
							<div
								v-if="description"
								class="task-viewer__description-preview markdown-enabled"
								v-html="renderedDescription"
							/>
							<div
								v-else
								class="task-viewer__description-placeholder"
							>
								Add a description...
							</div>
						</div>
					</div>

				</template>
			</div>
			<aside class="task-viewer__panel">
				<template v-if="!isLoading">

					<!-- ANCHOR Labels -->
					<div class="task-viewer__panel-section task-viewer__labels">
						<div class="task-viewer__panel-title">
							Labels
							<VindiSpacer />
							<w-menu
								v-model="labelSelector"
								z-index="600"
								align-left
								custom
							>
								<template #activator="{ on }">
									<w-icon
										:style="accentColorStyle"
										v-on="on"
									>
										mdi mdi-cog
									</w-icon>
								</template>
								<div class="simple-list">
									<TaskLabelSelector
										:labels="labelIds"
										:project-id="task.project.id"
										@add="addTaskLabel"
										@remove="removeTaskLabel"
									/>
								</div>
							</w-menu>
						</div>
						<div
							v-if="!labelIds.length"
							class="task-viewer__no-items"
						>
							No labels assigned
						</div>
						<div
							v-for="label in task.labels"
							:key="label.id"
							@click="labelSelector = !labelSelector"
						>
							<TaskLabel
								:value="label"
								class="task-viewer__label"
							/>
						</div>
					</div>

					<!-- ANCHOR Assignees -->
					<div class="task-viewer__panel-section task-viewer__assignees">
						<div class="task-viewer__panel-title">
							Assignees
							<VindiSpacer />
							<w-menu
								z-index="600"
								align-left
								custom
							>
								<template #activator="{ on }">
									<w-icon
										:style="accentColorStyle"
										v-on="on"
									>
										mdi mdi-cog
									</w-icon>
								</template>
								<div class="simple-list">
									<TaskAssigneeSelector
										:assignees="assigneeIds"
										:project-id="task.project.id"
										@add="addTaskAssignee"
										@remove="removeTaskAssignee"
									/>
								</div>
							</w-menu>
						</div>
						<div
							v-if="!assigneeIds.length"
							class="task-viewer__no-items"
						>
							No members assigned
						</div>
						<div
							v-for="(user, i) in task.assignees"
							:key="i"
							class="task-viewer__assignee"
						>
							<VindiAvatar
								:profile="user"
								:size="20"
								:show-border="false"
								@click.native="setTaskHidden"
							/>
							{{ user.fullName }}
						</div>
					</div>

					<!-- ANCHOR Calendar -->
					<div class="task-viewer__panel-section task-viewer__calendar">
						<div class="task-viewer__panel-title">
							Calendar
							<VindiSpacer />
							<w-menu
								z-index="600"
								menu-class="task-viewer__calendar-menu"
								align-left
								custom
							>
								<template #activator="{ on }">
									<w-icon
										:style="accentColorStyle"
										v-on="on"
									>
										mdi mdi-cog
									</w-icon>
								</template>
								<div class="simple-list">
									<VindiDatePicker
										:value="calendarValue"
										show-time
										@input="updateCalendarValue"
									/>
									<div>
										<w-divider class="nmt" />
									</div>
									<div class="task-viewer__calendar-info">
										<w-radios
											v-model="calendarOption"
											:items="calendarOptions"
										/>
									</div>
								</div>
							</w-menu>
						</div>
						<div
							v-if="!task.startTime && !task.endTime"
							class="task-viewer__no-items"
						>
							No dates specified
						</div>
						<div class="task-viewer__calendar-list">
							<div
								v-if="task.startTime"
								class="task-viewer__calendar-item"
							>
								<div class="simple-subtitle">
									Start Date
								</div>
								{{ formatDateTime(task.startTime) }}
							</div>
							<div
								v-if="task.endTime"
								class="task-viewer__calendar-item"
							>
								<div class="simple-subtitle">
									Due Date
								</div>
								{{ formatDateTime(task.endTime) }}
							</div>
						</div>
					</div>

					<!-- ANCHOR Milestones -->
					<div class="task-viewer__panel-section task-viewer__milestones">
						<div class="task-viewer__panel-title">
							Milestones
							<VindiSpacer />
							<w-icon
								:style="accentColorStyle"
							>
								mdi mdi-cog
							</w-icon>
						</div>
						<div
							class="task-viewer__no-items"
						>
							No milestones assigned
						</div>
					</div>

				</template>
			</aside>
		</section>
	</w-dialog>
</template>

<script lang="ts">
import Vue from 'vue';
import { marked } from 'marked';
import { mapState } from "vuex";
import { cloneDeep } from 'lodash';
import { ViewTask } from '~/typings/models';
import updateTask from '~/assets/query/viewer/updateTask.gql';
import moveTask from '~/assets/query/viewer/moveTask.gql';
import popTask from '~/assets/query/viewer/popTask.gql';
import removeLabel from '~/assets/query/viewer/removeLabel.gql';
import addLabel from '~/assets/query/viewer/addLabel.gql';
import removeAssignee from '~/assets/query/viewer/removeAssignee.gql';
import deleteTask from '~/assets/query/project/deleteTask.gql';
import addAssignee from '~/assets/query/viewer/addAssignee.gql';
import dayjs from 'dayjs';

const NO_LIST = Symbol('no-list');

export default Vue.extend({
	name: 'TaskView',
	
	data: () => ({
		isEditingDesc: false,
		labelSelector: false,
		listSelector: false,

		// Editable fields
		summary: '',
		description: '',
		taskList: undefined as number|undefined|typeof NO_LIST,

		// Project configurations
		projectLists: [] as any[],

		// Calendar
		calendarOption: 'START',
		calendarOptions: [
			{ label: 'Start date', value: 'START' },
			{ label: 'Due date', value: 'END' }
		]
	}),

	computed: {
		...mapState({
			task: 'taskView',
			isVisible: 'taskViewOpen'
		}),

		isLoading(): boolean {
			return this.task === undefined;
		},

		accentColorStyle(): any {
			return {
				color: this.task?.project?.accentColor
			};
		},

		accentBgColorStyle(): any {
			return {
				color: this.task?.project?.accentColor
			};
		},

		creationTime(): string {
			const createdAt = parseInt(this.task.createdAt);
			const dateFormat = this.$t('FULL_DATE_FORMAT') as string;

			return dayjs(createdAt).format(dateFormat);
		},

		taskListItems(): any[] {
			const lists = this.projectLists.map(list => {
				const isFull = list.taskLimit && list.taskCount >= list.taskLimit;

				return {
					label: isFull ? list.name + ' (Full)' : list.name,
					value: list.id,
					disabled: isFull
				};
			});

			return [
				{ label: 'Task unlisted', value: NO_LIST },
				...lists
			];
		},

		renderedDescription(): string {
			return this.task ? marked(this.description) : '';
		},

		currentList(): any {
			return this.taskListItems.find((list) => list.value == this.taskList);
		},

		isCurrentlyAssigned(): boolean {
			if(!this.task) {
				return false;
			}
			
			const profile = this.$store.state.profile;

			if(!profile) {
				return false;
			}

			return this.assigneeIds.includes(profile.id);
		},

		assigneeIds(): number[] {
			return this.task.assignees.map((assignee: any) => assignee.id);
		},

		labelIds(): number[] {
			return this.task.labels.map((label: any) => label.id);
		},

		calendarValue(): number {
			return this.calendarOption == 'START'
				? parseInt(this.task.startTime || 0)
				: parseInt(this.task.endTime || 0);
		}
	},

	watch: {
		task(value: ViewTask) {
			this.loadTaskData(value);
		},

		taskList(value, previous) {
			if(previous !== undefined) {
				// Update the local taskCount values to reflect
				// the "full" status of the previous and next list.
				// The timeout is required for the menu to close.
				setTimeout(() => {
					if(value !== NO_LIST) {
						this.getTaskList(value).taskCount++;
					}

					if(previous !== NO_LIST) {
						this.getTaskList(previous).taskCount--;
					}
				}, 100);

				this.updateTaskList();
			}
		}
	},

	mounted() {
		this.loadTaskData(this.task);
	},

	methods: {

		loadTaskData(task: ViewTask) {
			if(!task) return;

			this.summary = task.summary;
			this.description = task.description;
			this.taskList = task.list?.id || NO_LIST;
			this.projectLists = cloneDeep(task.project.lists);
		},

		// Update query helper function
		updateTask(details: any) {
			this.$api.query(updateTask, {
				id: this.task.id,
				details: details
			});
		},

		removeTask() {
			this.$api.query(deleteTask, {
				id: this.task.id
			});

			this.setTaskHidden();
		},

		setTaskHidden() {
			this.$store.commit('hideCurrentTask');
		},

		getTaskList(id: number): any {
			return this.projectLists.find(list => list.id == id);
		},

		editDescription() {
			this.isEditingDesc = true;
			
			this.$nextTick(() => {
				const editor = (this.$refs.descEditor as any).editor;
				
				editor.focus();
				editor.execCommand('selectAll');
			});
		},

		updateSummary() {
			if(!this.summary) {
				this.summary = this.task.summary;
				return;
			}

			this.$store.commit('patchCurrentTask', {
				summary: this.summary
			});

			this.updateTask({
				summary: this.summary
			});
		},

		updateTaskList() {
			if(this.taskList == NO_LIST) {
				this.$api.query(popTask, {
					id: this.task.id
				});
			} else {
				this.$api.query(moveTask, {
					id: this.task.id,
					list: this.taskList
				});
			}
		},

		discardDescription() {
			this.isEditingDesc = false;
			this.description = this.task.description;
		},

		updateDescription() {
			this.isEditingDesc = false;

			this.$store.commit('patchCurrentTask', {
				description: this.description
			});

			this.updateTask({
				description: this.description
			});
		},

		addTaskLabel(label: any) {
			const labels = [ ...this.task.labels, label ];

			this.$store.commit('patchCurrentTask', {
				labels
			});

			this.$api.query(addLabel, {
				id: this.task.id,
				labelId: label.id
			});
		},

		removeTaskLabel(label: any) {
			const labels = this.task.labels.filter((someLabel: any) => someLabel.id != label.id);
			
			this.$store.commit('patchCurrentTask', {
				labels
			});

			this.$api.query(removeLabel, {
				id: this.task.id,
				labelId: label.id
			});
		},

		addTaskAssignee(member: any) {
			const assignees = [ ...this.task.assignees, member ];

			this.$store.commit('patchCurrentTask', {
				assignees
			});

			this.$api.query(addAssignee, {
				id: this.task.id,
				userId: member.id
			});
		},

		removeTaskAssignee(member: any) {
			const assignees = this.task.assignees.filter((assignee: any) => assignee.id != member.id);
			
			this.$store.commit('patchCurrentTask', {
				assignees
			});

			this.$api.query(removeAssignee, {
				id: this.task.id,
				userId: member.id
			});
		},

		toggleTaskPinned() {
			const shouldPin = !this.task.isPinned;

			this.$store.commit('patchCurrentTask', {
				isPinned: shouldPin
			});

			this.updateTask({
				isPinned: shouldPin
			});
		},

		updateCalendarValue(time: number) {
			const fieldName = this.calendarOption == 'START' ? 'startTime' : 'endTime';

			this.$store.commit('patchCurrentTask', {
				[fieldName]: time.toString()
			});

			this.updateTask({
				[fieldName]: time.toString()
			});
		},

		formatDateTime(time: string) {
			return dayjs(parseInt(time)).format(this.$t('FULL_DATE_FORMAT') as string);
		}
	}
});
</script>

<style lang="scss">

$sidebar-size: 2.85rem;

.task-viewer-overlay {
	align-items: flex-start;
	overflow-y: auto;
	inset: 0;
}

.w-card.task-viewer-dialog {
	background-color: unset;
	margin: 100px 0;

	.w-card__content {
		padding: 0;
	}
}

.task-viewer {
	display: flex;

	&__loading {
		display: flex;
		align-items: center;
		justify-content: center;
		height: 100%;
	}
	
	&__sidebar,
	&__content,
	&__panel {
		min-height: 38rem;
	}

	&__content,
	&__panel {
		@include padding(5);

		flex: 1;
	}

	&__sidebar {
		width: $sidebar-size;
		background-color: var(--color-misc-1);
		padding-top: 1rem;
		display: flex;
		flex-direction: column;

		.w-divider {
			@include margin(2, x);
			@include margin(0.75, y);

			border-color: rgba(255, 255, 255, 0.2);
		}
	}

	&__sidebar-item {
		@include transition(colors);

		cursor: pointer;
		display: flex;
		align-items: center;
		justify-content: center;
		height: $sidebar-size;
		width: $sidebar-size;
		font-size: 1.1rem;
		color: white;
		
		&:hover {
			background-color: rgba(0, 0, 0, 0.2);
		}
	}

	&__content {
		background-color: var(--color-shade-0);

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

	&__panel {
		max-width: 14.5rem;
		background-color: var(--color-shade-2);

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

	&__close {
		@include margin(-1.5, t);
		@include margin(-1.5, r);
		@include margin(3, b);
	}

	&__parent {
		@include font-size(sm);
		@include padding(2, b);

		color: #8b8b8b;
		cursor: pointer;
	}

	&__parent-summary {
		color: #363636;

		@include dark {
			color: #c4c4c4;
		}
	}

	&__row {
		display: flex;
		align-items: center;
		gap: 9px;
	}

	&__id {
		@include font-weight(bold);
		@include font-size(xl);
	}

	&__summary {
		flex: 1;

		.w-input__input-wrap {
			@include padding(1.5, l);
		}

		input {
			@include font-size(lg);

			padding-left: 0;
			color: #363636;
		}
	}

	&__created-at, &__created-by {
		@include font-size(sm);
	}

	&__created-at {
		color: #828282;
	}

	&__task-list {
		flex-grow: 0;
		padding: 0;
		width: 140px;

		.w-select__selection-wrap {
			padding-right: 0;
			padding-left: 0;
		}

		input {
			padding-left: 0;
		}
	}

	&__description {
		@include padding(4, t);

		.CodeMirror {
			@include ring(var(--color-primary), 2);

			height: fit-content !important;
			margin-left: -8px;
			min-height: 80px;
		}

		.CodeMirror-lines {
			padding-left: 4px !important;
		}

		.CodeMirror-sizer {
			margin-bottom: unset !important;
		}
	}

	&__description-editor {
		@include margin(2, b);
	}

	&__description .CodeMirror-placeholder,
	&__description-placeholder {
		color: #828282 !important;
		font-style: italic;
	}

	&__description-preview,
	&__description-placeholder {
		@include padding(1.5, y);
	}

	&__panel-section:not(:last-child) {
		@include margin(8, b);
	}

	&__panel-title {
		@include font-size(base);
		@include font-weight(semibold);
		@include margin(1.5, b);

		display: flex;
		align-items: center;

		> .w-icon {
			cursor: pointer;

			&:not(:hover) {
				color: inherit !important;
			}
		}
	}

	&__label {
		@include margin(1, b);
		@include transition(all);
		
		cursor: pointer;
	}

	&__labels-list {
		@include padding(2);
	}

	&__no-items {
		@include font-size(sm);

		color: gray;
	}

	&__assignee {
		@include margin(1, t);
		@include margin(2, b);
		@include font-size(sm);

		display: flex;
		align-items: center;

		.avatar {
			@include margin(2, r);
		}

		> .w-icon {
			@include font-size(base);
			
			cursor: pointer;
		}
	}

	&__calendar-menu {
		.date-picker {
			border: none;
		}
	}

	&__calendar-info {
		@include padding(2, x);
		@include padding(2, b);
	}

	&__calendar-list {
		display: flex;
		flex-direction: column;
		gap: 0.5rem;
	}

	&__calendar-item {
		@include rounded(lg);
		@include padding(2);
		
		background-color: #ccd3e7;
	}
	

	&__actions {
		.w-button {
			@include rounded(md);
			@include padding(3.75, y);
			@include padding(3, x);
			@include margin(2, b);
			@include font-weight(normal);

			justify-content: start;
			width: 100%;
		}

		.w-divider {
			@include margin(0.75, t);

			border-color: rgba(0, 0, 0, 0.1);
		}
	}
}
</style>