<template>
	<section
		class="carousel-container"
		aria-label="Featured content"
		@mouseenter="pauseAutoplay"
		@mouseleave="resumeAutoplay"
	>
		<KagolCarousel
			v-model="activePage"
			class="home-carousel"
			:autoplay="false"
			:interval="1000"
		>
			<article
				v-for="slide in slides"
				:key="slide.id"
				ref="slideEls"
				class="carousel-slide"
			>
				<div class="mask"></div>
				<div class="banner-title" v-if="slide.title">{{ slide.title }}</div>
				<img
					v-if="!slide.video"
					class="carousel-banner image"
					:src="slide.image"
					:alt="slide.alt"
				/>
				<video
					v-else
					class="carousel-banner video"
					:alt="slide.alt"
					:controls="false"
					autoplay
					muted
					loop
				>
					<source :src="slide.video" type="video/mp4" />
				</video>

				<div class="desc flex flex-center" v-if="slide.description">
					<span class="desc-fill" aria-hidden="true"></span>
					<span class="desc-index-group">
						<span class="desc-line" aria-hidden="true"></span>
						<span class="desc-index-frame">
							<span class="desc-index">{{ slide.number }}</span>
							<span class="desc-index-cover" aria-hidden="true"></span>
						</span>
					</span>
					<p class="desc-copy">{{ slide.description }}</p>
				</div>
			</article>

			<template #pagination="{ prevPage, nextPage }">
				<nav class="carousel-pagination" aria-label="Carousel pagination">
					<button
						class="carousel-pagination-button carousel-pagination-button-prev"
						type="button"
						aria-label="Previous slide"
						@click="prevPage"
					>
						<span
							class="carousel-pagination-arrow carousel-pagination-arrow-prev"
						></span>
					</button>
					<button
						class="carousel-pagination-button carousel-pagination-button-next"
						type="button"
						aria-label="Next slide"
						@click="nextPage"
					>
						<span
							class="carousel-pagination-arrow carousel-pagination-arrow-next"
						></span>
					</button>
				</nav>
			</template>

			<template #indicator></template>
		</KagolCarousel>
	</section>
</template>

<script setup lang="ts">
	import { Carousel as KagolCarousel } from '@kagol/vue-carousel'
	import '@kagol/vue-carousel/dist/style.css'
	import { gsap } from 'gsap'
	import {
		nextTick,
		onBeforeUnmount,
		onMounted,
		shallowRef,
		useTemplateRef,
		watch
	} from 'vue'
	import mainBanner01 from '../../../assets/images/home/mainbanner01.jpg'
	import mainBanner02 from '../../../assets/images/home/mainbanner02.jpg'
	import Video from '@/assets/images/home/hero-desktop.mp4'

	type HomeSlide = {
		id: string
		image: string
		video: string
		alt: string
		title?: string
		number?: string
		description?: string
	}

	const activePage = shallowRef(1)
	const isAutoplayEnabled = shallowRef(false)
	const slideEls = useTemplateRef<HTMLElement[]>('slideEls')
	const slides: readonly HomeSlide[] = [
		{
			id: 'aida',
			image: mainBanner01,
			video: '',
			alt: 'Code Create product banner',
			title: 'Shaping the future\nof fashion design',
			number: '01',
			description:
				"World's first and only designer-led AI system that streamlines ideation from hours to seconds"
		},
		{
			id: 'mixi',
			image: mainBanner02,
			video: '',
			alt: 'Code Create product banner',
			title: 'Be the game changer,\n subscribe now!',
			number: '02',
			description: 'Make the first move to streamline and facilitate your inspiration process'
		},
		{
			id: 'video',
			image: '',
			video: Video,
			alt: 'Code Create product video banner'
		}
	]
	const descAnimationDelay = 1
	let activeSlideIndex: number | null = null
	let descAnimationFrame = 0
	let descTimeline: ReturnType<typeof gsap.timeline> | null = null

	function getActiveSlideIndex() {
		const slideCount = slides.length

		return ((activePage.value - 1) % slideCount + slideCount) % slideCount
	}

	function prefersReducedMotion() {
		return window.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false
	}

	function playDescAnimation(slideIndex: number) {
		const activeSlide = slideEls.value?.[slideIndex]
		const desc = activeSlide?.querySelector<HTMLElement>('.desc')
		const fill = desc?.querySelector<HTMLElement>('.desc-fill')
		const line = desc?.querySelector<HTMLElement>('.desc-line')
		const index = desc?.querySelector<HTMLElement>('.desc-index')
		const cover = desc?.querySelector<HTMLElement>('.desc-index-cover')
		const copy = desc?.querySelector<HTMLElement>('.desc-copy')

		descTimeline?.kill()
		descTimeline = null

		if (!fill || !line || !index || !cover || !copy) {
			return
		}

		gsap.killTweensOf([fill, line, index, cover, copy])

		if (prefersReducedMotion()) {
			gsap.set(fill, { width: '100%' })
			gsap.set(line, { autoAlpha: 1, width: 1, x: 0 })
			gsap.set(index, { autoAlpha: 1, x: 0 })
			gsap.set(cover, { autoAlpha: 0, xPercent: 110 })
			gsap.set(copy, { autoAlpha: 1, x: 0 })
			return
		}

		gsap.set(fill, { width: 0 })
		gsap.set(line, { autoAlpha: 0, width: 5, x: 18 })
		gsap.set(index, { autoAlpha: 0, x: -34 })
		gsap.set(cover, { autoAlpha: 0, xPercent: 0 })
		gsap.set(copy, { autoAlpha: 0, x: 22 })

		descTimeline = gsap
			.timeline({
				delay: descAnimationDelay,
				defaults: {
					ease: 'power3.out'
				}
			})
			.addLabel('panel', 0)
			.to(fill, { duration: 1.05, ease: 'power2.out', width: '100%' }, 'panel')
			.to(line, { autoAlpha: 1, duration: 0.9, width: 1, x: 0 }, 'panel+=0.12')
			.addLabel('number', 1.18)
			.set(index, { autoAlpha: 1 }, 'number')
			.set(cover, { autoAlpha: 1 }, 'number')
			.to(index, { duration: 0.7, x: 0 }, 'number')
			.to(cover, { duration: 0.72, ease: 'power2.inOut', xPercent: 110 }, 'number+=0.08')
			.to(copy, { autoAlpha: 1, duration: 0.72, x: 0 }, '>')
	}

	function queueDescAnimation() {
		const slideIndex = getActiveSlideIndex()

		if (slideIndex === activeSlideIndex) {
			return
		}

		activeSlideIndex = slideIndex
		nextTick(() => {
			if (descAnimationFrame) {
				window.cancelAnimationFrame(descAnimationFrame)
			}

			descAnimationFrame = window.requestAnimationFrame(() => {
				descAnimationFrame = 0
				playDescAnimation(slideIndex)
			})
		})
	}

	function pauseAutoplay() {
		isAutoplayEnabled.value = false
	}

	function resumeAutoplay() {
		isAutoplayEnabled.value = true
	}

	onMounted(() => {
		resumeAutoplay()
		queueDescAnimation()
	})

	onBeforeUnmount(() => {
		if (descAnimationFrame) {
			window.cancelAnimationFrame(descAnimationFrame)
		}

		descTimeline?.kill()
	})

	watch(activePage, queueDescAnimation)
</script>

<style scoped lang="less">
	.carousel-container {
		width: 100%;
		overflow: hidden;
	}

	.home-carousel {
		.carousel-slide {
			position: relative;
			width: 100%;
			aspect-ratio: 16 / 9;
			height: 960px;
			overflow: hidden;
			.mask {
				position: absolute;
				top: 0;
				left: 0;
				right: 0;
				bottom: 0;
				background-color: rgba(0, 0, 0, 0.35);
				z-index: 2;
			}
			.carousel-banner {
				display: block;
				width: 100%;
				height: 100%;
				object-fit: cover;
				position: absolute;
			}
			.banner-title {
				position: absolute;
				right: 50%;
				top: 50%;
				white-space: pre-line;
				color: #fff;
				font-size: 64px;
				font-family: 'Poppins';
				transform: translateY(-70%);
				z-index: 3;
			}
			.desc {
				position: absolute;
				left: 0;
				bottom: 0;
				z-index: 3;
				display: flex;
				align-items: center;
				gap: 24px;
				height: 140px;
				width: 656px;
				color: #ffffff;
				background: transparent;
				isolation: isolate;
			}
			.desc-fill {
				position: absolute;
				inset: 0 auto 0 0;
				z-index: 0;
				display: block;
				width: 0;
				background: #a51f24;
				pointer-events: none;
			}
			
			.desc-index-group {
				position: relative;
				z-index: 1;
				flex: 0 0 auto;
			}
			.desc-line {
				position: absolute;
				top: -160%;
				left: 50%;
				display: block;
				width: 1px;
				height: 65px;
				background: rgba(255, 255, 255, 0.72);
				opacity: 0;
				transform: translateX(-50%);
				will-change: transform, width, opacity;
			}
			.desc-index-frame {
				position: relative;
				display: block;
				overflow: hidden;
			}
			.desc-index {
				flex: 0 0 auto;
				position: relative;
				z-index: 1;
				display: block;
				font-family: 'Poppins';
				font-size: 52px;
				font-weight: 700;
				line-height: 1;
				opacity: 0;
				will-change: transform, opacity;
			}
			.desc-index-cover {
				position: absolute;
				inset: 0;
				z-index: 2;
				display: block;
				background: #ffffff;
				opacity: 0;
				pointer-events: none;
				will-change: transform;
			}
			.desc-copy {
				position: relative;
				z-index: 1;
				max-width: 440px;
				margin: 0;
				font-family: 'Poppins';
				font-size: 14px;
				font-weight: 600;
				line-height: 1.45;
				opacity: 0;
				will-change: transform, opacity;
			}
		}
		.carousel-pagination {
			position: absolute;
			right: 0;
			bottom: 0;
			z-index: 2;
			display: flex;
			flex-direction: column;
			width: 70px;
			height: 140px;
			transform: translateX(100%);
			transition: transform 0.28s ease;
			will-change: transform;
		}
		.carousel-pagination-button {
			position: relative;
			display: flex;
			flex: 1 1 0;
			align-items: center;
			justify-content: center;
			width: 100%;
			padding: 0;
			border: 0;
			color: #ffffff;
			background: #65090c;
			cursor: pointer;
			appearance: none;
			transition: background-color 0.2s ease;
		}

		.carousel-pagination-button:hover {
			background: rgba(255, 255, 255, 0.75);
		}

		.carousel-pagination-button:focus-visible {
			position: relative;
			z-index: 1;
			outline: 2px solid #ffffff;
			outline-offset: -6px;
		}

		.carousel-pagination-arrow {
			position: absolute;
			top: 50%;
			left: 50%;
			display: block;
			box-sizing: border-box;
			width: 20px;
			height: 20px;
			border-top: 2.5px solid currentColor;
			border-right: 2.5px solid currentColor;
		}

		.carousel-pagination-arrow-prev {
			transform: translate(-50%, -50%) rotate(225deg);
		}

		.carousel-pagination-arrow-next {
			transform: translate(-50%, -50%) rotate(45deg);
		}
	}

	.carousel-container:hover .carousel-pagination {
		transform: translateX(0);
	}

	:deep(.xui-carousel) {
		width: 100%;
	}

	:deep(.xui-carousel-item-container) {
		height: 100%;
	}

	@media (max-width: 768px) {
		.carousel-slide {
			min-height: 320px;
		}

		.home-carousel {
			.carousel-slide {
				.desc {
					width: 100%;
					min-width: 0;
					height: auto;
					min-height: 92px;
					padding: 16px 20px;
				}
				.desc-line {
					top: -28px;
					height: 42px;
				}
				.desc-index {
					font-size: 40px;
				}
				.desc-copy {
					max-width: none;
					font-size: 12px;
				}
			}
		}

		.carousel-pagination-arrow {
			width: 18px;
			height: 18px;
		}
	}
</style>
