<template>
	<div
		class="bucket"
		:class="{'is-collapsed': isCollapsed}"
	>
		<div class="bucket-header" @click="isCollapsed = false">
			<span
				v-if="bucket.isDoneBucket"
				class="icon is-small has-text-success mr-2"
				v-tooltip="$t('list.kanban.doneBucketHint')"
			>
				<icon icon="check-double"/>
			</span>
			<h2
				@keydown.enter.prevent.stop="($event.target as HTMLInputElement).blur()"
				@keydown.esc.prevent.stop="($event.target as HTMLInputElement).blur()"
				@blur="saveBucketTitle(($event.target as HTMLInputElement).textContent as string)"
				@click="focusBucketTitle"
				class="title input"
				:contenteditable="bucketTitleEditable && canWrite && !isCollapsed || undefined"
				:spellcheck="false">{{ bucket.title }}</h2>
			<span
				:class="{'is-max': bucket.tasks.length >= bucket.limit}"
				class="limit"
				v-if="bucket.limit > 0">
				{{ bucket.tasks.length }}/{{ bucket.limit }}
			</span>
			<dropdown
				class="is-right options"
				v-if="canWrite && !isCollapsed"
				trigger-icon="ellipsis-v"
				@close="hasLimitInput =false"
			>
				<a
					v-if="hasLimitInput"
					@click.stop="hasLimitInput = true"
					class="dropdown-item"
				>
					<div class="field has-addons">
						<div class="control">
							<input
								@keyup.esc="hasLimitInput = false"
								@keyup.enter="hasLimitInput = false"
								:value="bucket.limit"
								@input="setBucketLimit(parseInt(($event.target as HTMLInputElement).value))"
								class="input"
								type="number"
								min="0"
								v-focus.always
							/>
						</div>
						<div class="control">
							<x-button
								:disabled="bucket.limit < 0"
								:icon="['far', 'save']"
								:shadow="false"
								v-cy="'setBucketLimit'"
							/>
						</div>
					</div>
				</a>
				<div
					v-else
					@click.stop="hasLimitInput = true"
					class="dropdown-item"
				>
					{{ $t('list.kanban.limit', {
							limit: bucket.limit > 0
								? bucket.limit
								: $t('list.kanban.noLimit')
						})
					}}
				</div>
				<a
					@click.stop="toggleDoneBucket()"
					class="dropdown-item"
					v-tooltip="$t('list.kanban.doneBucketHintExtended')"
				>
					<span class="icon is-small" :class="{'has-text-success': bucket.isDoneBucket}">
						<icon icon="check-double"/>
					</span>
					{{ $t('list.kanban.doneBucket') }}
				</a>
				<a
					class="dropdown-item"
					@click.stop="isCollapsed = true"
				>
					{{ $t('list.kanban.collapse') }}
				</a>
				<a
					:class="{'is-disabled': isOnlyBucketLeft}"
					@click.stop="emit('openDeleteBucketModal', bucket.id)"
					class="dropdown-item has-text-danger"
					v-tooltip="isOnlyBucketLeft && $t('list.kanban.deleteLast')"
				>
					<span class="icon is-small">
						<icon icon="trash-alt"/>
					</span>
					{{ $t('misc.delete') }}
				</a>
			</dropdown>
		</div>

		<Draggable
			v-bind="dragOptions"
			:modelValue="bucket.tasks"
			@update:modelValue="updateTasks"
			@start="emit('dragstart', bucket.id)"
			@end="emit('dragend', $event)"
			:group="{name: 'tasks', put: shouldAcceptDrop}"
			:disabled="!canWrite"
			:data-bucket-index="bucketIndex"
			tag="transition-group"
			:item-key="(task: TaskModel) => `bucket${bucket.id}-task${task.id}`"
			:component-data="taskDraggableTaskComponentData"
		>
			<template #item="{element: task}">
				<div class="task-item">
					<TaskCard
						class="kanban-card" 
						:task="task"
						:loading="tasksUpdating[task.id]"
					/>
				</div>
			</template>

			<template #footer>
				<TaskNew
					v-if="canWrite"
					:bucketId="bucket.id"
					:listId="bucket.listId"
					:bucketIsEmpty="bucket.tasks.length === 0"
					@scrollTaskContainerToBottom="scrollTaskContainerToBottom"
				/>
			</template>
		</Draggable>
	</div>
</template>

<script setup lang="ts">
import {ref, computed, nextTick} from 'vue'
import {useStore} from 'vuex'
import {useI18n} from 'vue-i18n'
import Draggable from 'vuedraggable'
import { useVModels } from '@vueuse/core'

import {success} from '@/message'
import BucketModel from '@/models/bucket'
import TaskModel from '@/models/task'

import Dropdown from '@/components/misc/dropdown.vue'
import TaskCard from '@/features/kanban/TaskCard.vue'
import TaskNew from '@/features/kanban/TaskNew.vue'

const MIN_SCROLL_HEIGHT_PERCENT = 0.25

const props = defineProps<{
	bucketIndex: number
	isCollapsed: boolean
	canWrite: boolean
	bucket: BucketModel
	isOnlyBucketLeft: boolean
	dragOptions: Object
	params: Object
	shouldAcceptDrop: boolean
	isDraggingTask: boolean
	tasksUpdating: { [taskId: TaskModel['id']]: boolean },
}>()
const emit = defineEmits([
	'openDeleteBucketModal',
	'dragstart',
	'dragend',
	'update:isCollapsed',
])

const {t} = useI18n()
const store = useStore()

const { isCollapsed } = useVModels(props, emit)

const bucketTitleEditable = ref(true)
async function saveBucketTitle(bucketTitle: string) {
		await store.dispatch('kanban/updateBucketTitle', {
			id: props.bucket.id,
			title: bucketTitle,
		})
		bucketTitleEditable.value = false
		success({message: t('list.kanban.bucketTitleSavedSuccess')})
}

async function focusBucketTitle(e: Event) {
	// This little helper allows us to drag a bucket around at the title without focusing on it right away.
	bucketTitleEditable.value = true
	await nextTick();
	
	(e.target as HTMLInputElement).focus()
}

const hasLimitInput = ref(false)

async function setBucketLimit(limit: number) {
	if (limit < 0) {
		return
	}

	await store.dispatch('kanban/updateBucket', {
		...props.bucket,
		limit,
	})
	success({message: t('list.kanban.bucketLimitSavedSuccess')})
}

async function toggleDoneBucket() {
	await store.dispatch('kanban/updateBucket', {
		...props.bucket,
		isDoneBucket: !props.bucket.isDoneBucket,
	})
	success({message: t('list.kanban.doneBucketSavedSuccess')})
}

function updateTasks(tasks: TaskModel[]) {
	store.commit('kanban/setBucketById', {
		...props.bucket,
		tasks,
	})
}

function handleTaskContainerScroll(el: HTMLElement) {
	if (!el) {
		return
	}
	const scrollTopMax = el.scrollHeight - el.clientHeight
	const threshold = el.scrollTop + el.scrollTop * MIN_SCROLL_HEIGHT_PERCENT
	if (scrollTopMax > threshold) {
		return
	}

	store.dispatch('kanban/loadNextTasksForBucket', {
		listId: props.bucket.listId,
		params: props.params,
		bucketId: props.bucket.id,
	})
}

const taskContainer = ref<HTMLElement>()

const taskDraggableTaskComponentData = computed(() => ({
	ref: 'taskContainer',
	onScroll: (event: Event) => handleTaskContainerScroll(event.target as HTMLElement),
	type: 'transition',
	tag: 'div',
	name: !props.isDraggingTask ? 'move-card' : null,
	class: [
		'tasks',
		{'dragging-disabled': !props.canWrite},
	],
}))

function scrollTaskContainerToBottom() {
	if (!taskContainer.value) {
		return
	}
	taskContainer.value.scrollTop = taskContainer.value.scrollHeight
}


</script>

<style lang="scss" scoped>
.bucket {
	--bucket-header-height: 60px;

	border-radius: $radius;
	position: relative;

	display: flex;
	flex-direction: column;
}

.is-collapsed {
	align-self: flex-start;
	transform: rotate(90deg) translateY(-100%);
	transform-origin: top left;
	// Using negative margins instead of translateY here to make all other buckets fill the empty space
	margin-right: calc((var(--bucket-width) - var(--bucket-header-height) - var(--bucket-right-margin)) * -1);
	cursor: pointer;

	.tasks, .bucket-footer {
		display: none;
	}
}

.tasks {
	overflow: hidden auto;
	height: 100%;
}

.task-item {
	background-color: var(--grey-100);
	padding: .25rem .5rem;

	&:first-of-type {
		padding-top: .5rem;
	}
	&:last-of-type {
		padding-bottom: .5rem;
	}	
}

.no-move {
	transition: transform 0s;
}

h2 {
	font-size: 1rem;
	margin: 0;
	font-weight: 600 !important;
}

a.dropdown-item {
	padding-right: 1rem;
}



.bucket-header {
	background-color: var(--grey-100);
	height: min-content;
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: .5rem;
	height: var(--bucket-header-height);
}

.limit {
	padding: 0 .5rem;
	font-weight: bold;

	&.is-max {
		color: var(--danger);
	}
}

.title.input {
	height: auto;
	padding: .4rem .5rem;
	display: inline-block;
	cursor: pointer;
}

:deep(.dropdown-trigger) {
	cursor: pointer;
	padding: .5rem;
}

.bucket-footer {
	position: sticky;
	bottom: 0;
	height: min-content;
}

.move-card-move {
	transform: rotateZ(3deg);
	transition: transform $transition-duration;
}

.move-card-leave-from,
.move-card-leave-to,
.move-card-leave-active {
	display: none;
}
</style>