<template>
	<div class="content details">
		<h3 v-if="canWrite || comments.length > 0">
			<span class="icon is-grey">
				<icon :icon="['far', 'comments']"/>
			</span>
			Comments
		</h3>
		<div class="comments">
			<span class="is-inline-flex is-align-items-center" v-if="taskCommentService.loading && saving === null && !creating">
				<span class="loader is-inline-block mr-2"></span>
				Loading comments...
			</span>
			<div :key="c.id" class="media comment" v-for="c in comments">
				<figure class="media-left is-hidden-mobile">
					<img :src="c.author.getAvatarUrl(48)" alt="" class="image is-avatar" height="48" width="48"/>
				</figure>
				<div class="media-content">
					<div class="comment-info">
						<img :src="c.author.getAvatarUrl(20)" alt="" class="image is-avatar" height="20" width="20"/>
						<strong>{{ c.author.getDisplayName() }}</strong>&nbsp;
						<span v-tooltip="formatDate(c.created)">{{ formatDateSince(c.created) }}</span>
						<span v-if="+new Date(c.created) !== +new Date(c.updated)" v-tooltip="formatDate(c.updated)">
							· edited {{ formatDateSince(c.updated) }}
						</span>
						<transition name="fade">
							<span class="is-inline-flex" v-if="taskCommentService.loading && saving === c.id">
								<span class="loader is-inline-block mr-2"></span>
								Saving...
							</span>
							<span class="has-text-success" v-if="!taskCommentService.loading && saved === c.id">
								Saved!
							</span>
						</transition>
					</div>
					<editor
						:has-preview="true"
						:is-edit-enabled="canWrite"
						:upload-callback="attachmentUpload"
						:upload-enabled="true"
						@change="() => {toggleEdit(c);editComment()}"
						v-model="c.comment"
						:has-edit-bottom="true"
						:bottom-actions="actions[c.id]"
					/>
				</div>
			</div>
			<div class="media comment" v-if="canWrite">
				<figure class="media-left is-hidden-mobile">
					<img :src="userAvatar" alt="" class="image is-avatar" height="48" width="48"/>
				</figure>
				<div class="media-content">
					<div class="form">
						<transition name="fade">
							<span class="is-inline-flex" v-if="taskCommentService.loading && creating">
								<span class="loader is-inline-block mr-2"></span>
								Creating comment...
							</span>
						</transition>
						<div class="field">
							<editor
								:class="{'is-loading': taskCommentService.loading && !isCommentEdit}"
								:has-preview="false"
								:upload-callback="attachmentUpload"
								:upload-enabled="true"
								placeholder="Add your comment..."
								v-if="editorActive"
								v-model="newComment.comment"
							/>
						</div>
						<div class="field">
							<button :class="{'is-loading': taskCommentService.loading && !isCommentEdit}"
									:disabled="newComment.comment === ''"
									@click="addComment()" class="button is-primary">Comment
							</button>
						</div>
					</div>
				</div>
			</div>
		</div>
		<modal
			@close="showDeleteModal = false"
			@submit="deleteComment()"
			v-if="showDeleteModal">
			<span slot="header">Delete this comment</span>
			<p slot="text">Are you sure you want to delete this comment?
				<br/>This <b>CANNOT BE UNDONE!</b></p>
		</modal>
	</div>
</template>

<script>
import TaskCommentService from '../../../services/taskComment'
import TaskCommentModel from '../../../models/taskComment'
import attachmentUpload from '../mixins/attachmentUpload'
import LoadingComponent from '../../misc/loading'
import ErrorComponent from '../../misc/error'

export default {
	name: 'comments',
	components: {
		editor: () => ({
			component: import(/* webpackChunkName: "editor" */ '../../input/editor'),
			loading: LoadingComponent,
			error: ErrorComponent,
			timeout: 60000,
		}),
	},
	mixins: [
		attachmentUpload,
	],
	props: {
		taskId: {
			type: Number,
			required: true,
		},
		canWrite: {
			default: true,
		},
	},
	data() {
		return {
			comments: [],

			showDeleteModal: false,
			commentToDelete: TaskCommentModel,

			isCommentEdit: false,
			commentEdit: TaskCommentModel,

			taskCommentService: TaskCommentService,
			newComment: TaskCommentModel,
			editorActive: true,
			actions: {},

			saved: null,
			saving: null,
			creating: false,
		}
	},
	created() {
		this.taskCommentService = new TaskCommentService()
		this.newComment = new TaskCommentModel({taskId: this.taskId})
		this.commentEdit = new TaskCommentModel({taskId: this.taskId})
		this.commentToDelete = new TaskCommentModel({taskId: this.taskId})
		this.comments = []
	},
	mounted() {
		this.loadComments()
	},
	watch: {
		taskId() {
			this.loadComments()
		},
		canWrite() {
			this.makeActions()
		},
	},
	computed: {
		userAvatar() {
			return this.$store.state.auth.info.getAvatarUrl(48)
		},
	},
	methods: {
		loadComments() {
			this.taskCommentService.getAll({taskId: this.taskId})
				.then(r => {
					this.$set(this, 'comments', r)
					this.makeActions()
				})
				.catch(e => {
					this.error(e, this)
				})
		},
		addComment() {
			if (this.newComment.comment === '') {
				return
			}

			// This makes the editor trigger its mounted function again which makes it forget every input
			// it currently has in its textarea. This is a counter-hack to a hack inside of vue-easymde
			// which made it impossible to detect change from the outside. Therefore the component would
			// not update if new content from the outside was made available.
			// See https://github.com/NikulinIlya/vue-easymde/issues/3
			this.editorActive = false
			this.$nextTick(() => this.editorActive = true)
			this.creating = true

			this.taskCommentService.create(this.newComment)
				.then(r => {
					this.comments.push(r)
					this.newComment.comment = ''
					this.success({message: 'The comment was added successfully.'}, this)
				})
				.catch(e => {
					this.error(e, this)
				})
				.finally(() => {
					this.creating = false
				})
		},
		toggleEdit(comment) {
			this.isCommentEdit = !this.isCommentEdit
			this.commentEdit = comment
		},
		toggleDelete(commentId) {
			this.showDeleteModal = !this.showDeleteModal
			this.commentToDelete.id = commentId
		},
		editComment() {
			if (this.commentEdit.comment === '') {
				return
			}

			this.saving = this.commentEdit.id

			this.commentEdit.taskId = this.taskId
			this.taskCommentService.update(this.commentEdit)
				.then(r => {
					for (const c in this.comments) {
						if (this.comments[c].id === this.commentEdit.id) {
							this.$set(this.comments, c, r)
						}
					}
					this.saved = this.commentEdit.id
					setTimeout(() => {
						this.saved = null
					}, 2000)
				})
				.catch(e => {
					this.error(e, this)
				})
				.finally(() => {
					this.isCommentEdit = false
					this.saving = null
				})
		},
		deleteComment() {
			this.taskCommentService.delete(this.commentToDelete)
				.then(() => {
					for (const a in this.comments) {
						if (this.comments[a].id === this.commentToDelete.id) {
							this.comments.splice(a, 1)
						}
					}
				})
				.catch(e => {
					this.error(e, this)
				})
				.finally(() => {
					this.showDeleteModal = false
				})
		},
		makeActions() {
			if (this.canWrite) {
				this.comments.forEach(c => {
					this.$set(this.actions, c.id, [{
						action: () => this.toggleDelete(c.id),
						title: 'Remove',
					}])
				})
			}
		}
	},
}
</script>
