<!--
    Describe this component...
-->
<template>
    <div
        v-if="smoothingEnabled"
        :class="bem()"
        ref="el"
        :style="{
            position: 'relative',
            clipPath: renderMode === 'clip' ? smoothCornersPath : null,
            mask: renderMode === 'mask' ? smoothCornersPath : null,
            ...overrideStyles,
        }"
    >
        <div
            v-if="hasBorder"
            :style="{
                position: 'absolute',
                inset: 0,
                clipPath: renderMode === 'clip' ? borderMaskPath : null,
                mask: renderMode === 'mask' ? borderMaskPath : null,
                backgroundColor: computedBorderColor,
                touchAction: 'none',
            }"
        ></div>

        <slot />
    </div>

    <div v-else>
        <slot />
    </div>
</template>

<script>
import { getSmoothCornersPath, getBorderMaskClipPath } from '../utils/smootherCorners';

export default {
    name: 'px-corners',
    props: {
        smoothingEnabled: { type: Boolean, default: true },
        smoothing: { type: Number, default: 1 },
        maxRadius: { type: [Number, String], default: Infinity },
        minRadius: { type: [Number, String], default: 0 },
        radius: { type: [Array, Number, String], default: 'auto' },
        borderWidth: { type: [Number, String], default: 'auto' },
        borderColor: { type: String, default: 'auto' },

        // clip or mask
        renderMode: { type: String, default: 'clip' },
    },
    data() {
        return {
            dimensions: {
                width: 0,
                height: 0,
            },
            computedRadius: null,
            computedBorderWidth: 0,
            computedBorderColor: null,
            resizeObserver: null,

            // flag that we've detected auto styles
            autoStylesDetected: false,
        };
    },
    computed: {
        smoothCornersPath() {
            if (
                !this.smoothingEnabled ||
                this.dimensions.width <= 0 ||
                this.dimensions.height <= 0
            ) {
                return null;
            }

            return getSmoothCornersPath({
                width: this.dimensions.width,
                height: this.dimensions.height,
                radius: this.computedRadius || this.radius,
                smoothing: this.smoothing,
                borderWidth: 0,
                minRadius: this.minRadius,
                maxRadius: this.maxRadius,
                preserveSmoothing: true,
                renderMode: this.renderMode,
            });
        },
        borderMaskPath() {
            if (
                !this.smoothingEnabled ||
                this.dimensions.width <= 0 ||
                this.dimensions.height <= 0 ||
                this.computedBorderWidth <= 0
            ) {
                return null;
            }

            return getBorderMaskClipPath({
                width: this.dimensions.width,
                height: this.dimensions.height,
                radius: this.computedRadius || this.radius,
                smoothing: this.smoothing,
                borderWidth: this.computedBorderWidth,
                minRadius: this.minRadius,
                maxRadius: this.maxRadius,
                preserveSmoothing: true,
                renderMode: this.renderMode,
            });
        },
        hasBorder() {
            return !!this.borderMaskPath;
        },
        overrideStyles() {
            if (!this.smoothingEnabled || !this.autoStylesDetected) return {};

            return {
                borderRadius: 'unset',
                borderTopLeftRadius: 'unset',
                borderTopRightRadius: 'unset',
                borderBottomRightRadius: 'unset',
                borderBottomLeftRadius: 'unset',
                border: 'unset',
                borderWidth: 'unset',
                borderStyle: 'unset',
                borderColor: 'unset',
            };
        },
    },
    mounted() {
        this.$nextTick(() => {
            if (!this.$refs.el) return;
            if (!this.smoothingEnabled) return;

            this.detectAutoValues();
            this.updateDimensions();
            this.setupResizeObserver();
        });
    },
    beforeUnmount() {
        if (this.resizeObserver) {
            this.resizeObserver.disconnect();
        }
    },
    methods: {
        parseCssDimension(value) {
            if (typeof value === 'string' && value.length > 0) {
                value = value.trim().split(/\s+/)[0];

                if (value.endsWith('px')) return parseFloat(value);
                if (value.endsWith('rem')) {
                    return (
                        parseFloat(value) *
                        parseFloat(getComputedStyle(document.documentElement).fontSize)
                    );
                }
                if (value.endsWith('em')) {
                    return parseFloat(value) * parseFloat(getComputedStyle(this.$refs.el).fontSize);
                }
            }

            return value;
        },
        detectAutoValues() {
            if (!this.$refs.el) return;

            const cs = getComputedStyle(this.$refs.el);

            // auto radius detection
            if (this.radius === 'auto') {
                const radiusTopLeft = cs.getPropertyValue('border-top-left-radius') || '0';
                const radiusTopRight = cs.getPropertyValue('border-top-right-radius') || '0';
                const radiusBottomRight = cs.getPropertyValue('border-bottom-right-radius') || '0';
                const radiusBottomLeft = cs.getPropertyValue('border-bottom-left-radius') || '0';

                this.computedRadius = [
                    radiusTopLeft,
                    radiusTopRight,
                    radiusBottomRight,
                    radiusBottomLeft,
                ].map(r => this.parseCssDimension(r));
            }

            // auto border width detection
            if (this.borderWidth === 'auto') {
                // try border-width first, fallback to border-top-width
                let borderWidth = cs.getPropertyValue('border-width') || '0';
                if (borderWidth === '0' || borderWidth === '0px') {
                    borderWidth = cs.getPropertyValue('border-top-width') || '0';
                }
                this.computedBorderWidth = this.parseCssDimension(borderWidth);
            } else {
                this.computedBorderWidth = parseFloat(this.borderWidth) || 0;
            }

            // auto border color detection
            if (this.borderColor === 'auto') {
                this.computedBorderColor = cs.getPropertyValue('border-color') || 'transparent';
            } else {
                this.computedBorderColor = this.borderColor;
            }

            // flag that we've detected styles, now we can apply overrides
            this.autoStylesDetected = true;
        },
        updateDimensions() {
            if (!this.$refs.el) return;

            const rect = this.$refs.el.getBoundingClientRect();
            this.dimensions.width = rect.width;
            this.dimensions.height = rect.height;
        },
        setupResizeObserver() {
            if (!this.$refs.el) return;

            this.resizeObserver = new ResizeObserver(entries => {
                for (const entry of entries) {
                    this.dimensions.width = entry.contentRect.width;
                    this.dimensions.height = entry.contentRect.height;
                }
            });

            this.resizeObserver.observe(this.$refs.el);
        },
    },
};
</script>

<!-- <style lang="scss" scoped>
// @use '@/styles/include.scss' as *;
@use '../styles/px.scss' as *;
</style> -->
