<!--
    #VUE3 Done

    Maintains the aspect ratio of an element based on width and height. Does not use css
    aspect (on purpose) because it makes alignment complicated.
-->
<template>
    <div :class="bem({ debug: debug })">
        <div :class="bem('aspect')" :style="aspectStyle">
            <slot />
        </div>
    </div>
</template>

<script>
import aspect from '../plugins/filters/aspect.js';
import { contain } from '../utils/fit';
import PxBaseResize from '../bases/PxBaseResize.vue';

export default {
    name: 'px-aspect',
    mixins: [PxBaseResize],
    props: {
        /**
         * The aspect ratio (can be express as a number or a ratio string like '16:9')
         */
        aspect: { type: [Number, String], default: 16 / 9 },

        /**
         * Horizontal positioning when there is leftover space
         */
        alignX: { default: 0.5 }, // number | 'start' | 'center' | 'end'

        /**
         * Vertical positioning when there is leftover space
         */
        alignY: { default: 0.5 }, // number | 'start' | 'center' | 'end'

        /**
         * When true then draw a border around the fixed aspect area
         */
        debug: { type: Boolean, default: false },
    },
    data() {
        return {
            aspectRect: null,
        };
    },
    computed: {
        aspectRatio() {
            return aspect(this.aspect);
        },
        aspectRatioRect() {
            return {
                width: this.aspectRatio,
                height: 1,
            };
        },
        aspectStyle() {
            if (this.aspectRect) {
                return {
                    width: this.cssPx(this.aspectRect.width),
                    height: this.cssPx(this.aspectRect.height),
                    left: this.cssPx(this.aspectRect.x),
                    top: this.cssPx(this.aspectRect.y),
                };
            }
            return null;
        },
    },
    watch: {
        aspectRatio() {
            this.recalculate();
        },
        alignX() {
            this.recalculate();
        },
        alignY() {
            this.recalculate();
        },
    },
    methods: {
        alignToDecimal(align) {
            if (typeof align == 'number') {
                return Math.max(0, Math.min(1, align));
            }
            if (align === 'center') {
                return 0.5;
            }
            if (align === 'start') {
                return 0;
            }
            if (align === 'end') {
                return 1;
            }

            const float = parseFloat(align);
            return !isNaN(float) ? float : 0.5;
        },
        resize() {
            this.recalculate();
        },
        recalculate() {
            this.aspectRect = contain(
                this.aspectRatioRect,
                {
                    x: 0,
                    y: 0,
                    width: this.$el.clientWidth,
                    height: this.$el.clientHeight,
                },
                //this.$el.getBoundingClientRect(),

                this.alignToDecimal(this.alignX),
                this.alignToDecimal(this.alignY),
            );
        },
    },
};
</script>

<style lang="scss">
@use '../styles/px.scss' as *;
.px-aspect {
    width: 100%;
    height: 100%;
    position: relative;

    &__aspect {
        position: absolute;

        > img,
        > video {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }
    }

    &--debug {
        border: 1px dashed rgba(black, 0.2);
    }

    &--debug & {
        &__aspect {
            @include after() {
                @include abs;
                z-index: 1;
                border: 1px dashed red;
            }
        }
    }
}
</style>
