<script>
import Simplebar from 'simplebar-vue';

import SpotIcon from '@components/spotIcon';
import ProjectPost from '@components/projectPost';

export default {
	components: {
		SpotIcon,
		ProjectPost,
		Simplebar
	},
	props: {
		project: Object,
		modeHisto: Boolean
	},
	data() {
		return {
			loading: false,
			updatable: true,
			outOfData: false,
			refIdFirst: 0,
			refIdLast: 0,
			firstChunk: true,
			isOpen: false,
			posts: [],
			refreshRate: 60,
			swipe: {x: null, y: null}
		};
	},
	emits: ['request-last-update', 'new-markers', 'toggle'],
	inject: ['api', 'lang', 'consts', 'hash', 'isMobile'],
	provide() {
		return {
			feed: {
				checkNewFeed: this.checkNewFeed,
				toggle: this.toggle
			}
		};
	},
	watch: {
		project() {
			this.syncUpdateTimer();
		},
		modeHisto() {
			this.syncUpdateTimer();
		},
		firstChunk() {
			this.syncUpdateTimer();
		}
	},
	mounted() {
		this.getScrollElement()?.addEventListener('scroll', this.onFeedScroll);
		this.syncUpdateTimer();
	},
	beforeUnmount() {
		this.getScrollElement()?.removeEventListener('scroll', this.onFeedScroll);
		this.setUpdateTimer(-1);
	},
	methods: {
		async init(pMapIsReady) {
			this.setUpdateTimer(-1);
			this.loading = false;
			this.updatable = true;
			this.outOfData = false;
			this.refIdFirst = 0;
			this.refIdLast = 0;
			this.firstChunk = true;
			this.posts = [];
			this.swipe = {x: null, y: null};

			this.toggle(!this.isMobile(), 0);
			
			await this.getNextFeed();
			this.getScrollElement().scrollTop = 0;
			this.syncUpdateTimer();

			//Direct link post action
			await (this.hash.items.length == 3)
				? this.findPost(this.hash.items[1], this.hash.items[2], pMapIsReady)
				: Promise.resolve();
		},
		getScrollElement() {
			return this.$refs.feedSimpleBar?.scrollElement;
		},
		async findPost(sPostType, iPostId, pMapIsReady = Promise.resolve()) {
			let vPost = await this.goToPost(sPostType, iPostId);
			if(vPost) {
				await pMapIsReady;
				await vPost.executeMainAction(0);
				return vPost;
			}
			else if(!this.outOfData) {
				await this.getNextFeed();
				await this.$nextTick();
				return this.findPost(sPostType, iPostId, pMapIsReady);
			}
			else console.log('Missing element ID "'+iPostId+'" of type "'+sPostType+'"');
			return null;
		},
		async goToPost(sPostType, iPostId) {
			let avPosts = this.$refs.posts.filter((post) => {return post.postId == sPostType+'-'+iPostId;});
			if(avPosts.length == 0) return null;

			//Force next update to have enough subsequent elements to position the post on top of the page
			await this.getNextFeed();

			let vPost = avPosts[0];
			this.getScrollElement().scrollTop += Math.round(
				vPost.$el.getBoundingClientRect().top
				+ window.pageYOffset
				- parseFloat(getComputedStyle(this.$refs.feedSimpleBar.$el).paddingTop)
			);

			return vPost;
		},
		async getNextFeed() {
			if(!this.project || this.outOfData || this.loading) return true;

			//Get next chunk
			this.loading = true;
			let aoData = await this.api.get('next_feed', {id_project: this.project.id, id: this.refIdLast});
			let iPostCount = Object.keys(aoData.feed).length;

			//Update pointers
			this.outOfData = (iPostCount < this.consts.chunk_size);
			if(iPostCount > 0) {
				this.refIdLast = aoData.ref_id_last;
				if(this.firstChunk) this.refIdFirst = aoData.ref_id_first;
			}

			//Add posts
			this.posts.push(...aoData.feed);

			this.loading = false;
			this.firstChunk = false;

			return true;
		},
		onFeedScroll(oEvent) {
			const box = oEvent.currentTarget;
			const content = box.querySelector('.simplebar-content');

			if((box.scrollTop + box.clientHeight) / (content?.offsetHeight || 1) >= 0.8) this.getNextFeed();
		},
		onTouchStart(oEvent) {
			if(!this.isMobile() || !this.isOpen || oEvent.touches.length != 1) return;

			const oTouch = oEvent.touches[0];
			this.swipe = {x: oTouch.clientX, y: oTouch.clientY};
		},
		onTouchEnd(oEvent) {
			const oTouch = oEvent.changedTouches[0];
			if(!oTouch || this.swipe.x === null) return;

			const iDeltaX = oTouch.clientX - this.swipe.x;
			const iDeltaY = oTouch.clientY - this.swipe.y;

			if(iDeltaX > 80 && Math.abs(iDeltaX) > Math.abs(iDeltaY) * 1.5) this.toggle();

			this.swipe = {x: null, y: null};
		},
		setUpdateTimer(iSeconds) {
			if(typeof this.feedTimer != 'undefined') clearTimeout(this.feedTimer);
			if(iSeconds >= 0) this.feedTimer = setTimeout(this.onUpdateTimer, iSeconds * 1000);
		},
		syncUpdateTimer() {
			this.setUpdateTimer((!!this.project && !this.modeHisto && !this.firstChunk)?this.refreshRate:-1);
		},
		async onUpdateTimer() {
			await this.checkNewFeed();
			this.syncUpdateTimer();
		},
		async checkNewFeed() {
			if(!this.project) return;

			let aoData = await this.api.get('new_feed', {id_project: this.project.id, id: this.refIdFirst});
			const aoFeed = aoData.feed || [];
			const aoMarkers = aoData.markers || [];

			if(aoFeed.length > 0) {
				//Update pointer
				this.refIdFirst = aoData.ref_id_first;

				//Add new posts
				this.posts.unshift(...aoFeed);
			}

			if(aoMarkers.length > 0) this.$emit('new-markers', aoMarkers);
			this.$emit('request-last-update');
		},
		toggle(bShow, iAnimDuration=500) {
			this.isOpen = (typeof bShow == 'boolean')?bShow:(!this.isOpen);
			this.$emit('toggle', this.isOpen, iAnimDuration);
			return this.isOpen;
		},
		getWidth() {
			return this.$el.getBoundingClientRect().width;
		}
	}
}
</script>

<template>
	<div id="feed" class="panel panel-right" @touchstart.passive="onTouchStart" @touchend.passive="onTouchEnd">
		<Simplebar id="feed-panel" class="panel-content" ref="feedSimpleBar">
			<div id="feed-header">
				<ProjectPost v-if="modeHisto" :options="{type: 'archived', headerless: true}" />
				<ProjectPost v-else :options="{type: 'poster', relative_time: lang.get('post.new_message')}" />
			</div>
			<div v-if="project" id="feed-posts">
				<ProjectPost v-for="post in posts" :options="post" ref="posts" />
			</div>
			<div id="feed-footer" v-if="loading">
				<ProjectPost :options="{type: 'loading', headerless: true}" />
			</div>
		</Simplebar>
		<div v-if="project" :class="'panel-control panel-control-'+(isMobile()?'bottom':'top')" @click="toggle">
			<div class="panel-control-elem panel-control-icon">
				<SpotIcon :icon="isOpen?'next':'post'" />
			</div>
		</div>
	</div>
</template>
