<template>
    <span
        v-if="v && svgs[v as string] !== undefined"
        v-html="svgs[v as string]"
    ></span>
    <img
        v-else-if="iconSource"
        :src="iconSource"
        :style="`height: ${size}em; width: ${size}em; display: inline;`"
        alt=""
        :class="['icon', $attrs.class]"
        @error="fallBack"
    >
    <span v-else aria-hidden="true" :class="[`fa${iconSet}`, `fa-${icon}`, 'fa-fw', hover ? 'fa-hover' : '']" :style></span>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import type { PropType } from 'vue';

import blueSkySvg from '~~/public/img/bluesky.svg?raw';

const postprocessSvg = (svg: string): string => svg.replace('<svg ', '<svg class="icon" ');

const buildQueue = (v: string | (string | undefined)[] | null): { value: string; fallbacks: string[]; svgs: Record<string, any> } => {
    const rawValues = Array.isArray(v) ? v : [v];
    let values = rawValues.filter((x) => !!x) as string[];

    if (!values.length) {
        values = ['spacer'];
    }

    return {
        value: values.shift()!,
        fallbacks: values,
        svgs: {
            bluesky: postprocessSvg(blueSkySvg),
        },
    };
};

export default defineComponent({
    props: {
        v: { required: true, type: [String, Array] as PropType<string | (string | undefined)[] | null> },
        set: { default: 'l', type: String as PropType<'l' | 's' | 'b'> },
        size: { default: 1, type: Number },
        inverse: { type: Boolean },
        hover: { type: Boolean },
    },
    data() {
        return buildQueue(this.v);
    },
    computed: {
        valueParts(): string[] {
            return this.value.split(':');
        },
        icon(): string {
            const icon = this.valueParts[this.valueParts.length - 1];
            if (icon === 'neutrum') {
                return 'neuter';
            }
            return icon;
        },
        iconSet(): string {
            return this.valueParts.length > 1 ? this.valueParts[0] : this.set;
        },
        iconSource(): string | null {
            if (this.value.startsWith('https://')) {
                return this.value;
            }
            if (this.value.endsWith('.svg')) {
                return `/img/${this.inverse ? this.value.replace('.svg', '-inverse.svg') : this.value}`;
            }
            if (this.value.endsWith('.png')) {
                return `/img/${this.inverse ? this.value.replace('.png', '-inverse.png') : this.value}`;
            }
            return null;
        },
        style(): string {
            const properties = [];
            if (this.size !== 1) {
                properties.push(`font-size: ${this.size}em`);
            }
            if (this.v === 'neutrum') {
                properties.push('transform: rotate(225deg)');
            }
            return properties.join(';');
        },
    },
    watch: {
        v(v) {
            const { value, fallbacks } = buildQueue(v);

            this.value = value;
            this.fallbacks = fallbacks;
        },
    },
    methods: {
        fallBack() {
            if (!this.fallbacks.length) {
                return;
            }

            this.value = this.fallbacks.shift()!;
        },
    },
});
</script>

<style lang="scss">
.fa-hover:hover {
    font-weight: 900;
}
</style>
