<template>
	<section class="project-tasks">
		<div v-if="!tasks.length" class="project-view-empty">
			<ProjectTasksEmptyGraphic />
			<h2>
				Manage your tasks
			</h2>
			<p>
				Add tasks to your project to track individual goals and objectives
			</p>
			<w-button
				bg-color="primary"
				color="white"
				@click="openTaskCreator"
			>
				Create task
				<w-icon class="right">
					mdi mdi-plus
				</w-icon>
			</w-button>
		</div>

		<Container v-else class="project-tasks__content">
			<section
				v-if="pinned.length > 0"
				class="project-tasks__pinned"
			>
				<VindiTitle icon="mdi mdi-pin">
					Pinned tasks
				</VindiTitle>
				<div class="project-tasks__pinned-list">
					<TaskTile
						v-for="task in pinned"
						:key="task.id"
						:task="task"
					/>
				</div>
			</section>

			<section>
				<VindiTitle icon="mdi mdi-clipboard-check-outline">
					Tasks overview
				</VindiTitle>
				<div class="project-tasks__list">
					<div class="project-tasks__header">
						<div>
							<div class="simple-subtitle">
								Sorting
							</div>
							<w-select
								v-model="sortMethod"
								:items="sortMethods"
								bg-color="transparent"
							/>
						</div>
						<w-divider vertical />
						<div>
							<div class="simple-subtitle">
								Filters
							</div>
							<w-flex :gap="5">
								<div class="project-tasks__filter">
									Creator
									<w-icon>
										mdi mdi-chevron-down
									</w-icon>
								</div>
								<div class="project-tasks__filter">
									Label
									<w-icon>
										mdi mdi-chevron-down
									</w-icon>
								</div>
								<div class="project-tasks__filter">
									List
									<w-icon>
										mdi mdi-chevron-down
									</w-icon>
								</div>
								<div class="project-tasks__filter">
									Assignee
									<w-icon>
										mdi mdi-chevron-down
									</w-icon>
								</div>
							</w-flex>
						</div>
						<w-divider vertical />
						<VindiSpacer />
						<w-input
							v-model="taskSearch"
							class="project-tasks__search"
							inner-icon-left="mdi mdi-magnify"
							placeholder="Search task..."
							bg-color="shade-3"
							autocomplete="off"
							color="#eee"
							name="search"
						/>
					</div>
					<w-divider class="nm" />
					<w-table
						:headers="headers"
						:items="tasksList"
						no-headers
					>
						<template #[`item-cell.id`]="{ item }">
							<div
								class="project-tasks__id"
								@click="openTask(item)"
							>
								#{{ item.id }}
							</div>
						</template>

						<template #[`item-cell.summary`]="{ item }">
							<div class="project-tasks__title">
								<div
									class="project-tasks__summary"
									@click="openTask(item)"
								>
									{{ item.summary }}
								</div>
								<div class="project-tasks__labels">
									<TaskLabel
										v-for="label in item.labels"
										:key="label.id"
										:value="label"
									/>
								</div>
							</div>
							<div
								class="project-tasks__status"
							>
								<span class="project-tasks__creator">
									Created by {{ item.creator.fullName }}
								</span>
								
								<!-- Start time -->
								<span
									v-if="item.startTime"
									title="Task has start date"
								>
									<w-icon>
										mdi mdi-calendar
									</w-icon>
									{{ formatCalendarDate(item.startTime) }}
								</span>

								<!-- End time -->
								<span
									v-if="item.endTime"
									title="Task has due date"
								>
									<w-icon>
										mdi mdi-clock-outline
									</w-icon>
									{{ formatCalendarDate(item.endTime) }}
								</span>

								<!-- Attachments -->
								<span
									v-if="item.attachments.length"
									title="Task has attachments"
								>
									<w-icon rotate45a>
										mdi mdi-attachment
									</w-icon>
									{{ item.attachments.length }}
								</span>

								<!-- Pinned -->
								<span
									v-if="item.isPinned"
									title="Task is pinned"
								>
									<w-icon>
										mdi mdi-pin
									</w-icon>
									Pinned
								</span>
							</div>
						</template>

						<template #[`item-cell.list`]="{ item }">
							<span
								v-if="item.list"
								title="Task is listed"
							>
								<w-icon
									class="project-tasks__list-icon"
									:style="computeListIconStyle(item.list)"
									:sm="!item.list.icon"
								>
									{{ item.list.icon || 'mdi mdi-circle' }}
								</w-icon>
								{{ item.list.name }}
							</span>
						</template>

						<template #[`item-cell.members`]="{ item }">
							<div class="project-tasks__assignees">
								<VindiAvatar
									v-for="member in item.assignees"
									:key="member.id"
									:profile="member"
									:show-border="false"
									:size="32"
								/>
							</div>
						</template>

						<template #no-data>
							No tasks match your search criteria
						</template>
					</w-table>
					<w-divider class="nm" />
					<VindiPagination
						v-model="currentPage"
						:total="pageCount"
						:visible="5"
						class="project-tasks__pagination"
					/>
				</div>
			</section>
		</Container>
	</section>
</template>

<script lang="ts">
import Vue from 'vue';
import dayjs from 'dayjs';
import gql from 'graphql-tag';
import { chunk } from 'lodash';
import { parseSlug } from '~/src/helpers';
import fetchTasksPage from '~/assets/query/tasks/fetchTasksPage.gql';

export default Vue.extend({

	async asyncData(context) {
		const result = await context.$api.query(fetchTasksPage, {
			pid: parseSlug(context.params.pid)
		});

		return {
			project: result.project,
			pinned: result.project.pinnedTasks,
			tasks: result.project.tasks
		};
	},

	data: () => ({
		project: null as any,
		pinned: [] as any[],
		tasks: [] as any[],
		manager: null as any,
		currentPage: 0,
		tasksPerPage: 10,
		taskSearch: '',

		// Sorting,
		sortMethod: 'MODIFIED',
		sortMethods: [
			{ label: 'Last modified', value: 'MODIFIED' },
			{ label: 'Last created', value: 'CREATED' },
			{ label: 'Alphabetical', value: 'ALPHABETICAL' },
			{ label: 'Due date', value: 'DUE_DATE' }
		],
		sortFunctions: {
			MODIFIED: 'sortTasksModified',
			CREATED: 'sortTasksCreated',
			ALPHABETICAL: 'sortTasksAlphabetical',
			DUE_DATE: 'sortTasksDueDate'
		} as any,

		// Headers
		headers: [
			{ key: 'id' },
			{ key: 'summary' },
			{ key: 'list' },
			{ key: 'members' },
		],
	}),

	computed: {

		tasksFiltered() {
			const search = this.taskSearch.toLowerCase();
			const method = this.sortFunctions[this.sortMethod];
			const func = (this as any)[method];

			if(!func) {
				throw new Error('Unexpected sort method');
			}

			return [
				...this.tasks
			].filter((task) => {
				return task.summary.toLowerCase().includes(search);
			}).sort(func);
		},

		pageCount(): number {
			return Math.ceil(this.tasksFiltered.length / this.tasksPerPage);
		},

		tasksList(): any[] {
			return chunk(this.tasksFiltered, this.tasksPerPage)[this.currentPage] || [];
		},
	},

	mounted() {
		this.manager = this.$api.createManager();

		const slug = parseSlug(this.$route.params.pid);

		// Create a simple subscription to detect
		// modifications made to project tasks.
		function createQuery(field: string): any {
			return gql`
				subscription ($pid: Int!) {
					${field}(projectId: $pid) {
						id
					}
				}
			`;
		}
		
		this.manager.subscribe({
			query: createQuery('taskCreated'),
			next: this.refetchTasks,
			variables: {
				pid: slug
			}
		});

		this.manager.subscribe({
			query: createQuery('taskUpdated'),
			next: this.refetchTasks,
			variables: {
				pid: slug
			}
		});

		this.manager.subscribe({
			query: createQuery('taskRemoved'),
			next: this.refetchTasks,
			variables: {
				pid: slug
			}
		});
	},

	destroyed() {
		this.manager?.dispose();
	},
	
	methods: {
		openTaskCreator() {
			this.$store.commit('viewNewTaskDialog', true);
		},

		sortTasksModified(left: any, right: any): number {
			const aModified = dayjs(parseInt(left.lastModifiedAt));
			const bModified = dayjs(parseInt(right.lastModifiedAt));

			return aModified.isBefore(bModified) ? 1 : -1;
		},

		sortTasksCreated(left: any, right: any): number {
			const aCreated = dayjs(parseInt(left.createdAt));
			const bCreated = dayjs(parseInt(right.createdAt));

			return aCreated.isBefore(bCreated) ? 1 : -1;
		},

		sortTasksAlphabetical(left: any, right: any): number {
			return left.summary.localeCompare(right.summary);
		},

		sortTasksDueDate(left: any, right: any): number {
			const aTime = dayjs(parseInt(left.endTime || '0'));
			const bTime = dayjs(parseInt(right.endTime || '0'));

			return aTime.isBefore(bTime) ? 1 : -1;
		},

		async refetchTasks() {
			const res = await this.$api.query(fetchTasksPage, {
				pid: this.project.id
			});

			this.pinned = res.project.pinnedTasks;
			this.tasks = res.project.tasks;
		},

		formatDate(task: any): string {
			const lastModified = parseInt(task.lastModifiedAt);
			const dateFormat = this.$t('FULL_DATE_FORMAT') as string;

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

		openTask(task: any) {
			this.$store.dispatch('openTaskViewer', task.id);
		},

		formatCalendarDate(time: string) {
			const date = dayjs(parseInt(time));
			const format = this.$t('SHORT_DATE_FORMAT') as string;

			return date.format(format);
		},

		computeListIconStyle(list: any): any {
			return {
				color: list.color || 'var(--accent-color)'
			};
		}

	}
});
</script>

<style lang="scss">
.project-tasks {

	&__content {
		@include margin(16, t);
		@include padding(8, b);
	}

	&__pinned {
		@include margin(12, b);
	}

	&__pinned-list {
		@include margin(2, t);

		display: grid;
		gap: 0.5rem;

		@include breakpoint(lg) {
			grid-template-columns: repeat(4, minmax(0, 1fr));
		}
	}

	&__list {
		@include shadow;
		@include rounded('3xl');
		@include margin(2, t);
		
		background-color: var(--color-shade-0);
		min-height: 250px;
	}

	&__header {
		@include padding(4);

		display: flex;

		.simple-subtitle {
			padding-bottom: 0;
		}

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

	&__filter {
		@include margin(3.5, t);
		@include font-weight(medium);

		cursor: pointer;
	}

	&__search {
		max-width: 20rem;
	}

	.w-table__cell {
		height: 4.5rem;

		&:first-child {
			@include padding(5, r);

			width: 0;
		}

		&:last-child {
			@include padding(0, l);

			width: 0;
			color: gray;
		}
	}

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

		color: var(--accent-color);
		cursor: pointer;
	}

	&__title {
		display: flex;
		align-items: center;
	}

	&__summary {
		@include padding(2, r);
		@include truncate;

		cursor: pointer;
		min-height: 24px;
	}

	&__labels {
		margin-top: -1px;
		display: flex;
		gap: 0.25rem;

		.task-label {
			@include padding(0.65, y);
			@include padding(1.5, x);

			font-size: 0.7rem;
			line-height: 0.95rem;
		}

		.w-icon {
			font-size: 0.95rem;
		}
	}

	&__status {
		@include font-size(sm);
		@include font-weight(light);

		color: gray;
		display: flex;
		gap: 0.85rem;
	}

	&__creator {
		@include font-weight(normal);
	}

	&__list-icon.size--sm {
		@include margin(0.5, x);
	}

	&__assignees {
		display: flex;
		gap: 0.5rem;
	}

	&__pagination {
		@include padding(4);
	}
}
</style>