<script setup lang="ts">
import type { VvIconProps } from '.'
import { addIcon, Icon, iconLoaded } from '@iconify/vue'
import { VvIconPropsDefaults } from '.'

// props
const props = withDefaults(defineProps<VvIconProps>(), VvIconPropsDefaults)

const hasRotate = computed(() => {
    if (typeof props.rotate === 'string') {
        return Number.parseFloat(props.rotate)
    }
    return props.rotate
})

// data
const show = ref(true)

// inject plugin
const volver = useVolver()

// classes
const { modifiers } = toRefs(props)
const bemCssClasses = useModifiers('vv-icon', modifiers)

// provider name
const provider = computed(() => {
    return props.provider || volver?.iconsProvider
})

// icon name
const icon = computed(() => {
    const name = props.name ?? ''
    // compose Iconify icon name format
    const iconName = `@${provider.value}:${props.prefix}:${name}`

    // Check if icon with prefix and provider exist
    if (iconLoaded(iconName)) {
        return iconName
    }

    // Check if icon exist into any collection
    const iconsCollection = volver?.iconsCollections.find(
        (iconsCollection) => {
            const icon = `@${provider.value}:${iconsCollection.prefix}:${name}`
            return iconLoaded(icon)
        },
    )
    if (iconsCollection) {
        return `@${provider.value}:${iconsCollection.prefix}:${name}`
    }

    return name
})

/**
 * Get SVG content from SVG string
 * @param {string} svg
 * @return {SVGSVGElement | null} https://developer.mozilla.org/en-US/docs/Web/API/SVGSVGElement
 */
function getSvgContent(svg: string): SVGSVGElement | null {
    if (globalThis.window === undefined) {
        return null
    }
    const domParser = new globalThis.DOMParser()
    const svgDomString = domParser.parseFromString(svg, 'text/html')
    return svgDomString.querySelector('svg')
}

/**
 * Add icon to current Iconify provider
 * @param {string} svg
 */
function addIconFromSvg(svg: string) {
    const svgContentEl = getSvgContent(svg)
    const svgContent = svgContentEl?.innerHTML.trim() || ''
    if (svgContentEl && svgContent) {
        addIcon(`@${provider.value}:${props.prefix}:${props.name}`, {
            body: svgContent,
            // Set height and width from svg content
            height: svgContentEl.viewBox.baseVal.height,
            width: svgContentEl.viewBox.baseVal.width,
        })
    }
}

if (volver) {
    if (
        props.src
        && !iconLoaded(`@${provider.value}:${props.prefix}:${props.name}`)
    ) {
        show.value = false
        volver
            .fetchIcon(props.src)
            .then((svg?: string) => {
                if (svg) {
                    addIconFromSvg(svg)
                }
                // restore visibility even if jsdom is unavailable in SSR
                show.value = true
            })
            .catch((e) => {
                show.value = true
                throw new Error(`Error during fetch icon: ${e?.message}`)
            })
    }
}

if (props.svg) {
    addIconFromSvg(props.svg)
}
</script>

<script lang="ts">
export default {
    name: 'VvIcon',
}
</script>

<template>
    <Icon
        v-if="show"
        :class="bemCssClasses"
        v-bind="{
            inline,
            width,
            height,
            horizontalFlip,
            verticalFlip,
            flip,
            rotate: hasRotate,
            color,
            icon,
        }"
        @load="onLoad"
    />
</template>
