<template>
    <Tooltip v-if="celebrate1M" :text="$t('home.million')">
        <span
            ref="confettiLogo"
            :class="['bg-primary logo-wrapper rounded-circle d-inline-flex justify-content-center align-items-center', $attrs.class]"
            @mouseenter="fireConfetti"
        >
            <span class="logo" v-html="svg.replace(`<path `, `<path style='fill: #fff' `)"></span>
        </span>
    </Tooltip>
    <span
        v-else-if="flag"
        :class="['logo-wrapper rounded-circle d-inline-flex justify-content-center align-items-center', forceShowFlag || forceShowFlagDyn ? 'logo-flag-forced' : '', flagName ? 'logo-has-flag' : '', $attrs.class]"
        :style="flagName ? `--flag: url('/flags/${flagName}.png')` : ''"
        @transitionend="resetFlagIfNotOverwritten"
    >
        <span class="logo" v-html="svg"></span>
    </span>
    <span v-else :class="['logo', $attrs.class]" v-html="svg"></span>
</template>

<script lang="ts">
import { useFetch } from 'nuxt/app';
import { storeToRefs } from 'pinia';
import { defineComponent } from 'vue';

import logoSvg from '../public/logo/logo.svg?raw';
import { buildCalendar } from '../src/calendar/calendar.ts';
import { Day } from '../src/calendar/helpers.ts';
import { ImmutableArray } from '../src/helpers.ts';
import { useMainStore } from '../store/index.ts';

interface Data {
    svg: string;
    flagName: string | null;
    forceShowFlagDyn: boolean;
}

interface Refs {
    confettiLogo: HTMLSpanElement | undefined;
}

export default defineComponent({
    props: {
        flag: { type: Boolean },
        forceShowFlag: { type: Boolean },
        day: { default: () => Day.today(), type: Day },
    },
    async setup() {
        const runtimeConfig = useRuntimeConfig();

        const { data: stats } = await useFetch<{ overall: { users: number } }>(
            '/api/admin/stats-public',
            { lazy: true },
        );

        return {
            stats,
            selectedDay: storeToRefs(useMainStore()).selectedDay,
            calendar: buildCalendar(runtimeConfig.public.baseUrl),
        };
    },
    data(): Data {
        return {
            svg: logoSvg.replace('/></svg>', 'fill="currentColor"/></svg>'),
            flagName: null,
            forceShowFlagDyn: false,
        };
    },
    computed: {
        $tRefs(): Refs {
            return this.$refs as unknown as Refs;
        },
        celebrate1M(): boolean {
            return this.stats !== null && this.stats.overall.users >= 1_000_000 && this.stats.overall.users < 1_005_000;
        },
    },
    watch: {
        selectedDay() {
            this.forceShowFlagDyn = !!this.selectedDay;
            // removing the flag from the selected day is deferred until the transition has finished
            // so that it does not suddenly change
            if (this.selectedDay !== null) {
                this.flagName = this.selectFlag();
            }
        },
    },
    mounted() {
        setTimeout(() => this.fireConfetti(), 1000);
    },
    methods: {
        async fireConfetti() {
            await this.$nextTick();
            if (!this.$tRefs.confettiLogo?.offsetParent) {
                return;
            }

            if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
                return;
            }

            const confetti = (await import('canvas-confetti')).default;

            const origin = {
                x: (this.$tRefs.confettiLogo.offsetLeft + this.$tRefs.confettiLogo.offsetWidth) / window.innerWidth,
                y: (this.$tRefs.confettiLogo.offsetTop + this.$tRefs.confettiLogo.offsetHeight) / window.innerHeight,
            };

            const centre = { x: 0.5, y: 0.5 };

            const angleRadians = -Math.atan((centre.y - origin.y) / (centre.x - origin.x));
            const angleDegrees = angleRadians * (180 / Math.PI);

            await confetti({
                particleCount: 200,
                angle: angleDegrees,
                spread: 120,
                shapes: ['star'],
                origin,
                scalar: 0.8,
                decay: 0.9,
            });
        },
        selectFlag(): string | null {
            const events = this.calendar.getCurrentYear()!.eventsByDate[(this.selectedDay || this.day).toString()];
            if (!events) {
                return null;
            }
            return new ImmutableArray(...events)
                .filter((e) => e.display.type === 'flag' && !e.display.name.startsWith('_'))
                .sorted((a, b) => b.level - a.level)
                .groupBy((e) => e.level)
                .indexOrFallback(0, ['0', new ImmutableArray()])[1]
                .map((e) => e.display.name)
                .randomElement();
        },
        resetFlagIfNotOverwritten(): void {
            if (this.selectedDay === null) {
                this.flagName = this.selectFlag();
            }
        },
    },
});
</script>

<style lang="scss">
    .logo-wrapper {
        width: 1.3em;
        height: 1.3em;
        position: relative;
        overflow: hidden;
        &:before {
            content: ' ';
            display: block;
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-image: var(--flag);
            background-position: center;
            background-size: cover;
            background-repeat: no-repeat;
            z-index: -5;

            opacity: 0;
            transition: all .25s ease-in-out;
        }
    }

    .logo {
        height: 1em;
        width: 1em;
        display: inline-block;
        vertical-align: middle;
        svg {
            vertical-align: baseline !important;
        }
    }

    .logo-wrapper.logo-flag-forced.logo-has-flag, a:hover .logo-wrapper.logo-has-flag {
        svg path {
            stroke: white;
            stroke-width: 10;
        }
        &:before {
            opacity: 1;
        }
    }

    body[data-theme="dark"] {
        .logo-wrapper.logo-flag-forced.logo-has-flag, a:hover .logo-wrapper.logo-has-flag {
            svg path {
                stroke: black;
            }
        }
    }
</style>
