<!--
  - @copyright Copyright (c) 2020 Marco Ambrosini <marcoambrosini@icloud.com>
  -
  - @author Marco Ambrosini <marcoambrosini@icloud.com>
  -
  - @license GNU AGPL version 3 or any later version
  -
  - This program is free software: you can redistribute it and/or modify
  - it under the terms of the GNU Affero General Public License as
  - published by the Free Software Foundation, either version 3 of the
  - License, or (at your option) any later version.
  -
  - This program is distributed in the hope that it will be useful,
  - but WITHOUT ANY WARRANTY; without even the implied warranty of
  - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  - GNU Affero General Public License for more details.
  -
  - You should have received a copy of the GNU Affero General Public License
  - along with this program. If not, see <http://www.gnu.org/licenses/>.
-->

<template>
	<div class="grid-main-wrapper" :class="{'is-grid': !isStripe, 'transparent': isLessThanTwoVideos}">
		<NcButton v-if="isStripe && !isRecording"
			class="stripe--collapse"
			type="tertiary-no-background"
			:aria-label="stripeButtonTooltip"
			@click="handleClickStripeCollapse">
			<template #icon>
				<ChevronDown v-if="stripeOpen"
					fill-color="#ffffff"
					:size="20" />
				<ChevronUp v-else
					fill-color="#ffffff"
					:size="20" />
			</template>
		</NcButton>
		<transition :name="isStripe ? 'slide-down' : ''">
			<div v-if="!isStripe || stripeOpen" class="wrapper" :style="wrapperStyle">
				<div :class="[isStripe ? 'stripe-wrapper' : 'grid-wrapper']">
					<NcButton v-if="hasPreviousPage && gridWidth > 0"
						type="tertiary-no-background"
						class="grid-navigation grid-navigation__previous"
						:aria-label="t('spreed', 'Previous page of videos')"
						@click="handleClickPrevious">
						<template #icon>
							<ChevronLeft fill-color="#ffffff"
								:size="20" />
						</template>
					</NcButton>
					<div ref="grid"
						class="grid"
						:class="{stripe: isStripe}"
						:style="gridStyle"
						@mousemove="handleMovement"
						@keydown="handleMovement">
						<template v-if="!devMode && (!isLessThanTwoVideos || !isStripe)">
							<EmptyCallView v-if="videos.length === 0 && !isStripe" class="video" :is-grid="true" />
							<template v-for="callParticipantModel in displayedVideos">
								<VideoVue :key="callParticipantModel.attributes.peerId"
									:class="{'video': !isStripe}"
									:show-video-overlay="showVideoOverlay"
									:token="token"
									:model="callParticipantModel"
									:is-grid="true"
									:show-talking-highlight="!isStripe"
									:is-stripe="isStripe"
									:is-promoted="sharedDatas[callParticipantModel.attributes.peerId].promoted"
									:is-selected="isSelected(callParticipantModel)"
									:fit-video="false"
									:video-container-aspect-ratio="videoContainerAspectRatio"
									:shared-data="sharedDatas[callParticipantModel.attributes.peerId]"
									@click-video="handleClickVideo($event, callParticipantModel.attributes.peerId)" />
							</template>
						</template>
						<!-- Grid developer mode -->
						<template v-if="devMode">
							<div v-for="(video, key) in displayedVideos"
								:key="video"
								class="dev-mode-video video"
								:class="{'dev-mode-screenshot': screenshotMode}">
								<img :src="placeholderImage(key)">
								<VideoBottomBar :has-shadow="false"
									:model="placeholderModel(key)"
									:shared-data="placeholderSharedData(key)"
									:token="token"
									:participant-name="placeholderName(key)" />
							</div>
							<h1 v-if="!screenshotMode" class="dev-mode__title">
								Dev mode on ;-)
							</h1>
							<div v-else
								class="dev-mode-video--self video"
								:style="{'background': 'url(' + placeholderImage(8) + ')'}" />
						</template>
						<LocalVideo v-if="!isStripe && !isRecording && !screenshotMode"
							ref="localVideo"
							class="video"
							:is-grid="true"
							:fit-video="isStripe"
							:token="token"
							:local-media-model="localMediaModel"
							:video-container-aspect-ratio="videoContainerAspectRatio"
							:local-call-participant-model="localCallParticipantModel"
							@click-video="handleClickLocalVideo" />
					</div>
					<NcButton v-if="hasNextPage && gridWidth > 0"
						type="tertiary-no-background"
						class="grid-navigation grid-navigation__next"
						:aria-label="t('spreed', 'Next page of videos')"
						@click="handleClickNext">
						<template #icon>
							<ChevronRight fill-color="#ffffff"
								:size="20" />
						</template>
					</NcButton>
				</div>
				<LocalVideo v-if="isStripe && !isRecording && !screenshotMode"
					ref="localVideo"
					class="video"
					:is-stripe="true"
					:show-controls="false"
					:token="token"
					:local-media-model="localMediaModel"
					:video-container-aspect-ratio="videoContainerAspectRatio"
					:local-call-participant-model="localCallParticipantModel"
					@click-video="handleClickLocalVideo" />
				<!-- page indicator (disabled) -->
				<div v-if="numberOfPages !== 0 && hasPagination && false"
					class="pages-indicator">
					<div v-for="(page, index) in numberOfPages"
						:key="index"
						class="pages-indicator__dot"
						:class="{'pages-indicator__dot--active': index === currentPage }" />
				</div>
				<div v-if="devMode && !screenshotMode" class="dev-mode__data">
					<p>GRID INFO</p>
					<p>Videos (total): {{ videosCount }}</p>
					<p>Displayed videos n: {{ displayedVideos.length }}</p>
					<p>Max per page: ~{{ videosCap }}</p>
					<p>Grid width: {{ gridWidth }}</p>
					<p>Grid height: {{ gridHeight }}</p>
					<p>Min video width: {{ minWidth }} </p>
					<p>Min video Height: {{ minHeight }} </p>
					<p>Grid aspect ratio: {{ gridAspectRatio }}</p>
					<p>Number of pages: {{ numberOfPages }}</p>
					<p>Current page: {{ currentPage }}</p>
				</div>
			</div>
		</transition>
	</div>
</template>

<script>
import debounce from 'debounce'

import ChevronDown from 'vue-material-design-icons/ChevronDown.vue'
import ChevronLeft from 'vue-material-design-icons/ChevronLeft.vue'
import ChevronRight from 'vue-material-design-icons/ChevronRight.vue'
import ChevronUp from 'vue-material-design-icons/ChevronUp.vue'

import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import { generateFilePath } from '@nextcloud/router'

import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js'

import EmptyCallView from '../shared/EmptyCallView.vue'
import LocalVideo from '../shared/LocalVideo.vue'
import VideoBottomBar from '../shared/VideoBottomBar.vue'
import VideoVue from '../shared/VideoVue.vue'

export default {
	name: 'Grid',

	components: {
		VideoVue,
		LocalVideo,
		EmptyCallView,
		NcButton,
		VideoBottomBar,
		ChevronRight,
		ChevronLeft,
		ChevronUp,
		ChevronDown,
	},

	directives: {
		Tooltip,
	},

	props: {
		/**
		 * Minimum width of the video components
		 */
		minWidth: {
			type: Number,
			default: 200,
		},
		/**
		 * Minimum height of the video components
		 */
		minHeight: {
			type: Number,
			default: 150,
		},
		/**
		 * Max number of videos per page. `0`, the default value, means no cap
		 */
		videosCap: {
			type: Number,
			default: 0,
		},
		videosCapEnforced: {
			type: Boolean,
			default: false,
		},
		targetAspectRatio: {
			type: Number,
			default: 1,
		},
		/**
		 * Developer mode: If enabled it allows to debug the grid using dummy
		 * videos
		 */
		devMode: {
			type: Boolean,
			default: false,
		},
		screenshotMode: {
			type: Boolean,
			default: false,
		},
		/**
		 * The number of dummy videos in dev mode
		 */
		dummies: {
			type: Number,
			default: 8,
		},
		/**
		 * Display the overflow of videos in separate pages;
		 */
		hasPagination: {
			type: Boolean,
			default: false,
		},
		/**
		 * To be set to true when the grid is in the promoted view.
		 */
		isStripe: {
			type: Boolean,
			default: false,
		},
		isSidebar: {
			type: Boolean,
			default: false,
		},
		isRecording: {
			type: Boolean,
			default: false,
		},
		callParticipantModels: {
			type: Array,
			required: true,
		},
		localMediaModel: {
			type: Object,
			required: true,
		},
		localCallParticipantModel: {
			type: Object,
			required: true,
		},
		token: {
			type: String,
			required: true,
		},
		sharedDatas: {
			type: Object,
			required: true,
		},
		isLocalVideoSelectable: {
			type: Boolean,
			default: false,
		},
		screens: {
			type: Array,
			default: () => [],
		},
	},

	emits: ['select-video', 'click-local-video'],

	data() {
		return {
			gridWidth: 0,
			gridHeight: 0,
			// Columns of the grid at any given moment
			columns: 0,
			// Rows of the grid at any given moment
			rows: 0,
			// The current page
			currentPage: 0,
			// Videos controls and name
			showVideoOverlay: true,
			// Timer for the videos bottom bar
			showVideoOverlayTimer: null,
		}
	},

	computed: {
		stripeButtonTooltip() {
			if (this.stripeOpen) {
				return t('spreed', 'Collapse stripe')
			} else {
				return t('spreed', 'Expand stripe')
			}
		},

		// The videos array. This is the total number of grid elements.
		// Depending on `gridWidth`, `gridHeight`, `minWidth`, `minHeight` and
		// `videosCap`, these videos are shown in one or more grid 'pages'.
		videos() {
			if (this.devMode) {
				return Array.from(Array(this.dummies).keys())
			} else {
				return this.callParticipantModels
			}
		},

		// Number of video components (it does not include the local video)
		videosCount() {
			if (!this.isStripe && this.videos.length === 0) {
				// Count the emptycontent as a grid element
				return 1
			}

			return this.videos.length
		},
		videoWidth() {
			return this.gridWidth / this.columns
		},
		videoHeight() {
			return this.gridHeight / this.rows
		},

		// Array of videos that are being displayed in the grid at any given
		// moment
		displayedVideos() {
			if (!this.slots) {
				return []
			}

			const slots = (this.videosCap && this.videosCapEnforced) ? Math.min(this.videosCap, this.slots) : this.slots

			// Slice the `videos` array to display the current page of videos
			if (((this.currentPage + 1) * slots) >= this.videos.length) {
				return this.videos.slice(this.currentPage * slots)
			}

			return this.videos.slice(this.currentPage * slots, (this.currentPage + 1) * slots)
		},

		isLessThanTwoVideos() {
			// without screen share, we don't want to duplicate videos if we were to show them in the stripe
			// however, if a screen share is in progress, it means the video of the presenting user is not visible,
			// so we can show it in the stripe
			return this.videos.length <= 1 && !this.screens.length
		},

		dpiFactor() {
			if (this.isStripe) {
				// On the stripe we only ever want 1 row, so we ignore the DPR
				// as the height of the grid is the height of the video elements then.
				return 1.0
			}

			const devicePixelRatio = window.devicePixelRatio

			// Some sanity check to not screw up the math.
			if (devicePixelRatio < 0.5) {
				return 0.5
			}

			if (devicePixelRatio > 2.0) {
				return 2.0
			}

			return devicePixelRatio
		},

		dpiAwareMinWidth() {
			return this.minWidth / this.dpiFactor
		},

		dpiAwareMinHeight() {
			return this.minHeight / this.dpiFactor
		},

		// The aspect ratio of the grid (in terms of px)
		gridAspectRatio() {
			return (this.gridWidth / this.gridHeight).toPrecision([2])
		},

		// Max number of columns possible
		columnsMax() {
			if (Math.floor(this.gridWidth / this.dpiAwareMinWidth) < 1) {
				// Return at least 1 column
				return 1
			} else {
				return Math.floor(this.gridWidth / this.dpiAwareMinWidth)
			}
		},

		// Max number of rows possible
		rowsMax() {
			if (Math.floor(this.gridHeight / this.dpiAwareMinHeight) < 1) {
				// Return at least 1 row
				return 1
			} else {
				return Math.floor(this.gridHeight / this.dpiAwareMinHeight)
			}
		},

		// Number of grid slots at any given moment
		// The local video always takes one slot if the grid view is not shown
		// as a stripe.
		slots() {
			return this.isStripe ? this.rows * this.columns : this.rows * this.columns - 1
		},

		// Grid pages at any given moment
		numberOfPages() {
			return Math.ceil(this.videosCount / this.slots)
		},

		// Hides or displays the `grid-navigation next` button
		hasNextPage() {
			if (this.displayedVideos.length !== 0 && this.hasPagination) {
				return this.displayedVideos.at(-1) !== this.videos.at(-1)
			} else {
				return false
			}
		},

		// Hides or displays the `grid-navigation previous` button
		hasPreviousPage() {
			if (this.displayedVideos.length !== 0 && this.hasPagination) {
				return this.displayedVideos[0] !== this.videos[0]
			} else {
				return false
			}
		},

		// TODO: rebuild the grid to have optimal for last page
		// isLastPage() {
		// return !this.hasNextPage
		// },

		// Computed css to reactively style the grid
		gridStyle() {
			let columns = this.columns
			let rows = this.rows

			// If there are no other videos the empty call view is shown above
			// the local video.
			if (this.videos.length === 0 && !this.isStripe) {
				columns = 1
				rows = 2
			}

			return {
				gridTemplateColumns: `repeat(${columns}, minmax(${this.dpiAwareMinWidth}px, 1fr))`,
				gridTemplateRows: `repeat(${rows}, minmax(${this.dpiAwareMinHeight}px, 1fr))`,
			}
		},

		// Check if there's an overflow of videos (videos that don't fit in the grid)
		hasVideoOverflow() {
			return this.videosCount > this.slots
		},

		sidebarStatus() {
			return this.$store.getters.getSidebarStatus
		},
		// Current aspect ratio of each video component
		videoContainerAspectRatio() {
			return (this.gridWidth / this.columns) / (this.gridHeight / this.rows)
		},
		wrapperStyle() {
			if (this.isStripe) {
				return 'height: 250px'
			} else {
				return 'height: 100%'
			}
		},

		stripeOpen() {
			return this.$store.getters.isStripeOpen && !this.isRecording
		},
	},

	watch: {
		// If the video array size changes, rebuild the grid
		'videos.length'() {
			this.makeGrid()
		},
		// TODO: rebuild the grid to have optimal for last page
		// Exception for when navigating in and away from the last page of the
		// grid
		/**
		isLastPage(newValue, oldValue) {
			 if (this.hasPagination) {
				 // If navigating into last page, make grid for last page
				if (newValue && this.currentPage !== 0) {
					this.makeGridForLastPage()
				} else if (!newValue) {
				// TODO: make a proper grid for when navigating away from last page
					this.makeGrid()
				}
			 }
		 },
		 */
		isStripe() {
			this.rebuildGrid()

			// Reset current page when switching between stripe and full grid,
			// as the previous page is meaningless in the new mode.
			this.currentPage = 0
		},

		stripeOpen() {
			this.rebuildGrid()
		},

		sidebarStatus() {
			// Handle the resize after the sidebar animation has completed
			setTimeout(this.handleResize, 500)
		},

		numberOfPages() {
			if (this.currentPage >= this.numberOfPages) {
				this.currentPage = Math.max(0, this.numberOfPages - 1)
			}
		},
	},

	// bind event handlers to the `handleResize` method
	mounted() {
		window.addEventListener('resize', this.handleResize)
		subscribe('navigation-toggled', this.handleResize)
		this.makeGrid()

		window.OCA.Talk.gridDebugInformation = this.gridDebugInformation
	},
	beforeDestroy() {
		window.OCA.Talk.gridDebugInformation = () => console.debug('Not in a call')

		window.removeEventListener('resize', this.handleResize)
		unsubscribe('navigation-toggled', this.handleResize)
	},

	methods: {
		gridDebugInformation() {
			console.debug('Grid debug information')
			console.debug({
				minWidth: this.minWidth,
				minHeight: this.minHeight,
				videosCap: this.videosCap,
				videosCapEnforced: this.videosCapEnforced,
				targetAspectRatio: this.targetAspectRatio,
				videosCount: this.videosCount,
				videoWidth: this.videoWidth,
				videoHeight: this.videoHeight,
				devicePixelRatio: window.devicePixelRatio,
				dpiFactor: this.dpiFactor,
				dpiAwareMinWidth: this.dpiAwareMinWidth,
				dpiAwareMinHeight: this.dpiAwareMinHeight,
				gridAspectRatio: this.gridAspectRatio,
				columnsMax: this.columnsMax,
				rowsMax: this.rowsMax,
				numberOfPages: this.numberOfPages,
				videoContainerAspectRatio: this.videoContainerAspectRatio,
				bodyWidth: document.body.clientWidth,
				bodyHeight: document.body.clientHeight,
				gridWidth: this.$refs.grid.clientWidth,
				gridHeight: this.$refs.grid.clientHeight,
			})
		},

		rebuildGrid() {
			console.debug('isStripe: ', this.isStripe)
			console.debug('stripeOpen: ', this.stripeOpen)
			console.debug('previousGridWidth: ', this.gridWidth, 'previousGridHeight: ', this.gridHeight)
			console.debug('newGridWidth: ', this.gridWidth, 'newGridHeight: ', this.gridHeight)
			if (!this.isStripe || this.stripeOpen) {
				this.$nextTick(this.makeGrid)
			}
		},

		placeholderImage(i) {
			return generateFilePath('spreed', 'docs', 'screenshotplaceholders/placeholder-' + i + '.jpeg')
		},

		placeholderName(i) {
			switch (i) {
			case 0:
				return 'Sandra McKinney'
			case 1:
				return 'Chris Wurst'
			case 2:
				return 'Edeltraut Bobb'
			case 3:
				return 'Arthur Blitz'
			case 4:
				return 'Roeland Douma'
			case 5:
				return 'Vanessa Steg'
			case 6:
				return 'Emily Grant'
			case 7:
				return 'Tobias Kaminsky'
			case 8:
				return 'Adrian Ada'
			}
		},

		placeholderModel(i) {
			return {
				attributes: {
					audioAvailable: i === 1 || i === 2 || i === 4 || i === 5 || i === 6 || i === 7 || i === 8,
					audioEnabled: i === 8,
					videoAvailable: true,
					screen: false,
					currentVolume: 0.75,
					volumeThreshold: 0.75,
					localScreen: false,
					raisedHand: {
						state: i === 0 || i === 1 || i === 6,
					},
				},
				forceMute: () => {},
				on: () => {},
				off: () => {},
				getWebRtc: () => {
					return {
						connection: {
							getSendVideoIfAvailable: () => {},
						},
					}
				},
			}
		},

		placeholderSharedData() {
			return {
				videoEnabled: {
					isVideoEnabled() {
						return true
					},
				},
				remoteVideoBlocker: {
					isVideoEnabled() {
						return true
					},
				},
				screenVisible: false,
			}
		},

		// whenever the document is resized, re-set the 'clientWidth' variable
		handleResize(event) {
			// TODO: properly handle resizes when not on first page:
			// currently if the user is not on the 'first page', upon resize the
			// current position in the videos array is lost (first element
			// in the grid goes back to be first video)
			debounce(this.makeGrid(), 200)
		},

		// Find the right size if the grid in rows and columns (we already know
		// the size in px).
		makeGrid() {
			if (!this.$refs.grid) {
				return
			}
			this.gridWidth = this.$refs.grid.clientWidth
			this.gridHeight = this.$refs.grid.clientHeight
			// prevent making grid if no videos
			if (this.videos.length === 0) {
				this.columns = 0
				this.rows = 0
				return
			}

			if (this.devMode) {
				console.debug('Recreating grid: videos: ', this.videos.length, 'columns: ', this.columnsMax + ', rows: ' + this.rowsMax)
			}

			// We start by assigning the max possible value to our rows and columns
			// variables. These variables are kept in the data and represent how the
			// grid looks at any given moment. We do this based on `gridWidth`,
			// `gridHeight`, `minWidth` and `minHeight`. If the video is used in the
			// context of the promoted view, we se 1 row directly, and we remove 1 column
			// (one of the participants will be in the promoted video slot)
			this.columns = this.columnsMax
			this.rows = this.rowsMax
			// This values would already work if the grid is entirely populated with
			// video elements. However, if we'd have only a couple of videos to display
			// and a very big screen, we'd now have a lot of columns and rows, and our
			// video components would occupy only the first 2 slots and be too small.
			// To solve this, we shrink this 'max grid' we've just created to fit the
			// number of videos that we have.
			if (this.videosCap !== 0 && this.videosCount > this.videosCap) {
				this.shrinkGrid(this.videosCap)
			} else {
				this.shrinkGrid(this.videosCount)
			}
		},

		// Fine tune the number of rows and columns of the grid
		async shrinkGrid(numberOfVideos) {
			if (this.devMode) {
				console.debug('Shrinking grid: columns', this.columns + ', rows: ' + this.rows)
			}

			// No need to shrink more if 1 row and 1 column
			if (this.rows === 1 && this.columns === 1) {
				return
			}

			let currentColumns = this.columns
			let currentRows = this.rows
			let currentSlots = this.isStripe ? currentColumns * currentRows : currentColumns * currentRows - 1

			// Run this code only if we don't have an 'overflow' of videos. If the
			// videos are populating the grid, there's no point in shrinking it.
			while (numberOfVideos < currentSlots) {
				const previousColumns = currentColumns
				const previousRows = currentRows

				// Current video dimensions
				const videoWidth = this.gridWidth / currentColumns
				const videoHeight = this.gridHeight / currentRows

				// Hypothetical width/height with one column/row less than current
				const videoWidthWithOneColumnLess = this.gridWidth / (currentColumns - 1)
				const videoHeightWithOneRowLess = this.gridHeight / (currentRows - 1)

				// Hypothetical aspect ratio with one column/row less than current
				const aspectRatioWithOneColumnLess = videoWidthWithOneColumnLess / videoHeight
				const aspectRatioWithOneRowLess = videoWidth / videoHeightWithOneRowLess

				// Deltas with target aspect ratio
				const deltaAspectRatioWithOneColumnLess = Math.abs(aspectRatioWithOneColumnLess - this.targetAspectRatio)
				const deltaAspectRatioWithOneRowLess = Math.abs(aspectRatioWithOneRowLess - this.targetAspectRatio)

				if (this.devMode) {
					console.debug('deltaAspectRatioWithOneColumnLess: ', deltaAspectRatioWithOneColumnLess, 'deltaAspectRatioWithOneRowLess: ', deltaAspectRatioWithOneRowLess)
				}
				// Compare the deltas to find out whether we need to remove a column or a row
				if (deltaAspectRatioWithOneColumnLess <= deltaAspectRatioWithOneRowLess) {
					if (currentColumns >= 2) {
						currentColumns--
					}

					currentSlots = this.isStripe ? currentColumns * currentRows : currentColumns * currentRows - 1

					// Check that there are still enough slots available
					if (numberOfVideos > currentSlots) {
						// If not, revert the changes and break the loop
						currentColumns++
						break
					}
				} else {
					if (currentRows >= 2) {
						currentRows--
					}

					currentSlots = this.isStripe ? currentColumns * currentRows : currentColumns * currentRows - 1

					// Check that there are still enough slots available
					if (numberOfVideos > currentSlots) {
						// If not, revert the changes and break the loop
						currentRows++
						break
					}
				}

				if (previousColumns === currentColumns && previousRows === currentRows) {
					break
				}
			}

			this.columns = currentColumns
			this.rows = currentRows
		},

		// The last grid page is very likely not to have the same number of
		// elements as the previous pages so the grid needs to be tweaked
		// accordingly
		// makeGridForLastPage() {
		// this.columns = this.columnsMax
		// this.rows = this.rowsMax
		// // The displayed videos for the last page have already been set
		// // in `handleClickNext`
		// this.shrinkGrid(this.displayedVideos.length)
		// },

		handleClickNext() {
			this.currentPage++
			console.debug('handleclicknext, ', 'currentPage ', this.currentPage, 'slots ', this.slot, 'videos.length ', this.videos.length)
		},
		handleClickPrevious() {
			this.currentPage--
			console.debug('handleclickprevious, ', 'currentPage ', this.currentPage, 'slots ', this.slots, 'videos.length ', this.videos.length)
		},

		handleClickStripeCollapse() {
			this.$store.dispatch('setCallViewMode', { isStripeOpen: !this.stripeOpen })
		},

		handleMovement() {
			// TODO: debounce this
			this.setTimerForUiControls()
		},
		setTimerForUiControls() {
			if (this.showVideoOverlayTimer !== null) {
				clearTimeout(this.showVideoOverlayTimer)
			}
			this.showVideoOverlay = true
			this.showVideoOverlayTimer = setTimeout(() => { this.showVideoOverlay = false }, 5000)
		},

		handleClickVideo(event, peerId) {
			console.debug('selected-video peer id', peerId)
			this.$emit('select-video', peerId)
		},

		handleClickLocalVideo() {
			this.$emit('click-local-video')
		},

		isSelected(callParticipantModel) {
			return callParticipantModel.attributes.peerId === this.$store.getters.selectedVideoPeerId
		},

	},
}

</script>

<style lang="scss" scoped>
@import '../../../assets/variables';

.grid-main-wrapper {
	position: relative;
	width: 100%;
}

.grid-main-wrapper.transparent {
	background: transparent;
}

.grid-main-wrapper.is-grid {
	height: 100%;
}

.wrapper {
	width: 100%;
	display: flex;
	position: relative;
	bottom: 0;
	left: 0;
}

.grid {
	display: grid;
	height: 100%;
	width: 100%;

	grid-row-gap: 8px;
	grid-column-gap: 8px;

	&.stripe {
		padding: 8px 8px 0 0;
	}
}

.empty-call-view {
	position: relative;
	padding: 16px;
}

.grid-wrapper {
	width: 100%;
	position: relative;
	flex: 1 0 auto;
}

.stripe-wrapper {
	width: 100%;
	position: relative;
}

.dev-mode-video {
	&:not(.dev-mode-screenshot) {
		border: 1px solid #00FF41;
		color: #00FF41;
	}
	position: relative;

	&--self {
		background-size: cover !important;
		border-radius: calc(var(--default-clickable-area) / 2);
	}

	img {
		object-fit: cover;
		height: 100%;
		width: 100%;
		border-radius: calc(var(--default-clickable-area)/2);
	}

	.wrapper {
		position: absolute;
	}
}

.dev-mode__title {
	position: absolute;
	left: 44px;
	color: #00FF41;
	z-index: 100;
	line-height: 120px;
	font-weight: 900;
	font-size: 100px !important;
	top: 88px;
	opacity: 25%;
}

.dev-mode__data {
	font-family: monospace;
	position: fixed;
	color: #00FF41;
	left: 20px;
	bottom: 50%;
	padding: 20px;
	background: rgba(0,0,0,0.8);
	border: 1px solid #00FF41;
	width: 212px;
	font-size: 12px;
	z-index: 999999999999999;
	& p {
		text-overflow: ellipsis;
		overflow: hidden;
		white-space: nowrap;
	}
}

.video:last-child {
	grid-column-end: -1;
}

.grid-navigation {
	z-index: 2;
	background-color: rgba(0, 0, 0, 0.5);

	&:hover,
	&:focus {
		background-color: rgba(0, 0, 0, 0.8) !important;
	}

	.grid-wrapper & {
		position: absolute;
		top: calc(50% - var(--default-clickable-area) / 2);
		&__previous {
			left: -4px;
		}
		&__next {
			right: -4px;
		}
	}

	.stripe-wrapper & {
		position: absolute;
		top: 16px;
		&__previous {
			left: 8px;
		}
		&__next {
			right: 16px;
		}
	}
}

.pages-indicator {
	position: absolute;
	right: 50%;
	top: 4px;
	display: flex;
	background-color: var(--color-background-hover);
	height: 44px;
	padding: 0 22px;
	border-radius: 22px;
	&__dot {
		width: 8px;
		height: 8px;
		margin: auto 4px;
		border-radius: 4px;
		background-color: white;
		opacity: 80%;
		box-shadow: 0 0 4px black;

		&--active {
			opacity: 100%;
		}
	}
}

.stripe--collapse {
	position: absolute !important;
	top: calc(-1 * var(--default-clickable-area));
	right: 0;
	z-index: 2;
	opacity: .7;

	.app-content:hover & {
		background-color: rgba(0, 0, 0, 0.1) !important;

		&:hover,
		&:focus {
			opacity: 1;
			background-color: rgba(0, 0, 0, 0.2) !important;
		}
	}

	&:active {
		/* needed again to override default active button style */
		background: none;
	}
}

</style>
