<template>
    <div
        :class="bem({ resizing: resizing, showOverlay: showOverlay })"
        :style="{
            width: cssPx(width, false, null),
            height: cssPx(height, false, null),
        }"
    >
        <slot />
        <div v-if="allowResizeX" :class="bem('resize-x')" @mousedown="mousedown('x', $event)"></div>
        <div v-if="allowResizeY" :class="bem('resize-y')" @mousedown="mousedown('y', $event)"></div>
        <div v-if="showOverlay" :class="bem('size')">
            {{ cssPx(width) || 'auto' }}, {{ cssPx(height) || 'auto' }}
        </div>
    </div>
</template>

<script>
export default {
    name: 'px-resizer',
    props: {
        /**
         * Whether resize functionality is enabled in various directions.
         * @values x, y, xy, null
         * */
        allowResize: { type: String, default: 'xy' }, // x, y, xy, null

        /**
         * Whether resize functionality is enabled in various directions.
         * @values resizing, always, never
         * */
        overlayVisible: { type: [String, Boolean], default: 'resizing' },

        /** Multiply dragged pixels by this amount when calculating the new size in the x direction. */
        multiplierX: { type: Number, default: 1 },

        /** Multiply dragged pixels by this amount when calculating the new size in the y direction. */
        multiplierY: { type: Number, default: 1 },

        /** The initial width of the component. */
        initialWidth: { type: Number, default: null },

        /** The initial width of the component. */
        initialHeight: { type: Number, default: null },
    },
    data() {
        return { resizing: false, width: this.initialWidth, height: this.initialHeight };
    },
    computed: {
        allowResizeX() {
            return this.allowResize && this.allowResize.indexOf('x') > -1;
        },
        allowResizeY() {
            return this.allowResize && this.allowResize.indexOf('y') > -1;
        },
        showOverlay() {
            if (this.overlayVisible === 'always' || this.overlayVisible === true) {
                return true;
            }
            if (this.overlayVisible === 'never' || this.overlayVisible === false) {
                return false;
            }
            return this.overlayVisible === 'resizing' && this.resizing;
        },
    },
    methods: {
        emitResize(width, height) {
            /**
             * Fired in realtime as the component is resized (mouse drag).
             */
            this.$emit('resize', { width, height });
        },

        emitResizeStart() {
            /**
             * Fired when resizing starts due to user interaction (mouse down).
             */
            this.$emit('resize-start');
        },

        emitResizeEnd() {
            /**
             * Fired when resizing due to user interaction ends (mouse up).
             */
            this.$emit('resize-start');
        },
        setSize(size) {
            this.width = size.w;
            this.height = size.h;
            this.emitResize(this.width, this.height);
        },
        updateSize(width, height, limitDirection) {
            if (limitDirection == 'x') {
                this.width = width;
            } else if (limitDirection == 'y') {
                this.height = height;
            } else {
                this.height = height;
                this.width = width;
            }
            this.emitResize(this.width, this.height);
        },
        mousedown(direction, e) {
            if (document) {
                this.resizing = true;

                this.emitResizeStart();

                let r = this.$el.getBoundingClientRect();

                this.downDirection = direction;
                this.downPoint = { x: e.screenX, y: e.screenY };
                this.downWidth = r.width;
                this.downHeight = r.height;

                this.updateSize(r.width, r.height, this.downDirection);

                document.body.style.userSelect = 'none';
                document.addEventListener('mousemove', this.mousemove);
                document.addEventListener('mouseup', this.mouseup);
            }
        },

        mousemove(e) {
            let delta = { x: this.downPoint.x - e.screenX, y: this.downPoint.y - e.screenY };
            this.updateSize(
                Math.max(0, this.downWidth - delta.x * this.multiplierX),
                Math.max(0, this.downHeight - delta.y * this.multiplierY),
                this.downDirection,
            );
            e.preventDefault();
        },
        mouseup() {
            document.body.style.removeProperty('user-select');
            this.resizing = false;
            this.emitResizeEnd();
            document.removeEventListener('mousemove', this.mousemove);
            document.removeEventListener('mouseup', this.mouseup);
        },
    },
};
</script>

<style lang="scss">
@use '../styles/px.scss' as *;
@use 'sass:color';

@at-root {
    :root {
        --px-resizer-color: #{accent()};
        --px-resizer-color-hover: #{color.adjust(accent(), $lightness: -10%)};
        --px-resizer-width: 3px;
        --px-resizer-height: 24px;
        --px-resizer-hit-width: 24px;
        --px-resizer-offset: 10px;
    }
}
.px-resizer {
    position: relative;
    margin: 0 auto;
    display: inline-block;
    width: 100%;
    height: auto;

    @include after() {
        @include abs(0);
        border: 2px solid transparent;
        pointer-events: none;
    }

    &--resizing {
        @include bem(content) {
            //opacity: 0.75;
            pointer-events: none;
        }
    }

    &--show-overlay {
        &::after {
            border: 1px dashed var(--px-resizer-color);
            border-radius: inherit;
        }
    }

    &__resize-x,
    &__resize-y {
        color: var(--px-resizer-color);
        &:hover {
            color: var(--px-resizer-color-hover);
        }
        &:active {
            opacity: 0.5;
        }
    }

    &__resize-x {
        @include center-y();
        cursor: ew-resize;
        width: var(--px-resizer-hit-width);
        height: var(--px-resizer-height);
        right: calc(var(--px-resizer-hit-width) * -1);

        @include after() {
            position: absolute;
            top: 0;
            left: var(--px-resizer-offset);
            width: var(--px-resizer-width);
            height: var(--px-resizer-height);
            background-color: currentColor;
        }
    }

    &__resize-y {
        @include center-x();
        cursor: ns-resize;

        height: var(--px-resizer-hit-width);
        width: var(--px-resizer-height);
        bottom: calc(var(--px-resizer-hit-width) * -1);

        @include after() {
            position: absolute;
            left: 0;
            top: var(--px-resizer-offset);
            height: var(--px-resizer-width);
            width: var(--px-resizer-height);
            background-color: currentColor;
        }
    }

    &__size {
        @include no-select();
        //font-family: $ff;
        white-space: nowrap;
        position: absolute;
        top: 0;
        right: 0;
        background-color: accent();
        color: white;
        pointer-events: none;
        font-size: 11px;
        font-weight: 500;
        line-height: 1.5;
        padding: 0 0.5em;
    }
}
</style>
