<template>
    <div
        v-if="image"
        :class="[
            'strapi-media',
            { 'fill-space': fillSpace, 'can-play': canPlay },
            `fit-${fit}`,
        ]"
        :style="styles"
    >
        <div class="image-sizer">
            <img
                :src="image.url"
                :srcset="srcset"
                :sizes="sizes"
                :alt="image.alternativeText || ''"
                :width="image.width"
                :height="image.height"
                loading="lazy"
                decoding="async"
            />

            <button v-if="!shouldLoop" class="play-button" @click="onPlayClick">
                <svg-play />
            </button>

            <video
                v-if="video?.url"
                :src="video.url"
                :muted="shouldLoop"
                :autoplay="shouldLoop"
                :playsinline="shouldLoop"
                :loop="shouldLoop"
                :controls="!shouldLoop"
                ref="videoRef"
            />
        </div>
    </div>
</template>

<script setup>
import { breakpoints } from '@/libs/theme'
import { computed, ref } from 'vue'

const props = defineProps({
    image: Object,
    video: Object,
    looping: {
        type: Boolean,
        default: () => true,
    },
    aspect: {
        type: [String, Number],
        default: () => -1,
    },
    fillSpace: {
        type: Boolean,
        default: () => false,
    },
    fit: {
        type: String,
        default: () => 'cover',
    },
    mobileSize: {
        type: String,
        default: () => '100vw',
    },
    desktopSize: {
        type: String,
        default: () => '100vw',
    },
})

const videoRef = ref()
const canPlay = ref(props.looping !== false)

const shouldLoop = computed(() => props.looping !== false)
const formats = computed(() => props.image?.formats || {})
const ratio = computed(() => {
    if (!props.image) return 1
    return props.image.height / props.image.width
})
const aspect = computed(() => {
    // calculate if no aspect provided
    if (props.aspect === -1) {
        return ratio.value * 100
    }

    // otherwise, parse provided aspect, handling both 56.25 and 0.5625 style
    const toParse = parseFloat(props.aspect)
    return toParse <= 1 ? toParse * 100 : toParse
})
const styles = computed(() => ({ '--aspect': aspect.value + '%' }))
const srcset = computed(() =>
    Object.values(formats.value)
        .map((f) => `${f.url} ${f.width}w`)
        .join(', '),
)
const sizes = computed(
    () =>
        `(max-width: ${breakpoints.mobile}) ${props.mobileSize}, ${props.desktopSize}`,
)

const onPlayClick = () => {
    canPlay.value = true
    videoRef.value?.play()
}
</script>

<style lang="scss">
.strapi-media {
    position: relative;
    width: 100%;
    overflow: hidden;

    .image-sizer {
        overflow: hidden;
        padding-bottom: var(--aspect);

        img,
        video {
            display: block;
            position: absolute;
            height: 100%;
            width: 100%;
            left: 0;
            top: 0;
        }
        .play-button {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            cursor: pointer;

            svg {
                width: 4rem;
                height: auto;
            }
        }
    }

    // fill space
    &.fill-space {
        position: absolute;
        bottom: 0;
        right: 0;
        left: 0;
        top: 0;

        .image-sizer {
            padding-bottom: 0;
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
        }
    }

    &:not(.can-play) video {
        opacity: 0;
        pointer-events: none;
    }

    // fits
    &.fit-cover .image-sizer > * {
        object-fit: cover;
    }
    &.fit-contain .image-sizer > * {
        object-fit: contain;
    }
}
</style>
