<script setup lang="ts">
import { useStorage } from '@vueuse/core';
import sorter from 'avris-sorter';
import { useCookie } from 'nuxt/app';

import useConfig from '~/composables/useConfig.ts';
import useDark from '~/composables/useDark.ts';
import useDialogue from '~/composables/useDialogue.ts';
import { longtimeCookieSetting } from '~/src/cookieSettings.ts';
import { LoadScriptError } from '~/src/errors.ts';
import { executeUnlessPrerendering, sha256 } from '~/src/helpers.ts';
import { useMainStore } from '~/store/index.ts';

// no need to be super secure, just a sign that the page is not public
const TESTER_PASSWORD_HASH = '3754c03824c4ea3b13e7b4b2d7ad35992dbf64f9ee680493fc7093bf176f49e5';

declare global {
    interface Window {
        dataLayer: unknown[];
        gnshbrequest: {
            cmd: any[];
            forceInternalRequest: () => void;
        };
        adpushup: {
            que: any[];
        };
    }
}

const { $translator: translator, $isGranted: isGranted, $locales: locales, $loadScript: loadScript } = useNuxtApp();
const config = useConfig();
const runtimeConfig = useRuntimeConfig();

const store = useMainStore();

useDark();

const testerPasswordCookie = useCookie('tester-password', longtimeCookieSetting);
const testerPassword = ref('');

const requiresLogin = computed((): boolean => {
    return !config.macrolanguage?.enabled && (runtimeConfig.public.env === 'test' ||
        config.locale !== '_' && !locales[config.locale]?.published);
});
const testerPasswordValid = ref<boolean | undefined>();
const checkTesterPassword = async () => {
    if (testerPassword.value) {
        testerPasswordCookie.value = testerPassword.value;
    }
    if (testerPasswordCookie.value) {
        testerPasswordValid.value = await sha256(testerPasswordCookie.value) === TESTER_PASSWORD_HASH;
    }
};

if (requiresLogin.value) {
    await checkTesterPassword();
}

onMounted(executeUnlessPrerendering(() => {
    sorter();

    confirmAge();

    loadAds();

    let needsRefresh = false;
    const bc = new BroadcastChannel('account_switch');
    bc.onmessage = (ev): void => {
        if (ev.data !== store.user?.username) {
            needsRefresh = true;
            if (document.hasFocus()) {
                needsRefresh = false;
                window.location.reload();
            }
        }
    };
    window.onfocus = (): void => {
        if (needsRefresh) {
            needsRefresh = false;
            window.location.reload();
        }
    };
}));

const dialogue = useDialogue();
const confirmAge = async (): Promise<void> => {
    if (!translator.has('footer.ageLimit') || localStorage.getItem('ageConfirmed')) {
        return;
    }

    await dialogue.alert(translator.translate('footer.ageLimit'));

    localStorage.setItem('ageConfirmed', '1');
};

const provider = useStorage<string | null>('ads-provider', null);

if (provider.value === null) {
    provider.value = Math.random() < 0.7 ? 'publift' : 'pushup';
}

const adsEnabled = computed((): boolean => {
    if (isGranted() && provider.value === 'none') {
        return false;
    }

    return !!config.ads?.enabled && import.meta.env?.APP_ENV === 'production';
});

const loadAdsForProvider = {
    publift: async (): Promise<void> => {
        await loadScript(
            'publift',
            'https://cdn.fuseplatform.net/publift/tags/2/3329/fuse.js',
            undefined,
            'head',
        );
    },
    geniee: async (): Promise<void> => {
        window.gnshbrequest = window.gnshbrequest || { cmd: [] };
        window.gnshbrequest.cmd.push(function () {
            window.gnshbrequest.forceInternalRequest();
        });

        await loadScript(
            'gpt',
            'https://securepubads.g.doubleclick.net/tag/js/gpt.js',
            undefined,
            'head',
        );
        await loadScript(
            'geniee',
            'https://cpt.geniee.jp/hb/v1/222988/2860/wrapper.min.js',
            undefined,
            'head',
        );
    },
    pushup: async (): Promise<void> => {
        await loadScript(
            'adpushup',
            'https://cdn.adpushup.com/47589/adpushup.js',
            undefined,
            'head',
        );
    },
};

const loadAds = async (): Promise<void> => {
    if (!adsEnabled.value) {
        return;
    }

    try {
        console.log('loading', provider.value);
        const key = provider.value as keyof typeof loadAdsForProvider;
        if (!Object.hasOwn(loadAdsForProvider, key)) {
            throw new Error(`Invalid provider: ${key}`);
        }
        await loadAdsForProvider[key]();
    } catch (error) {
        if (error instanceof LoadScriptError) {
            return;
        }
        throw error;
    }
};
</script>

<template>
    <div v-if="requiresLogin && !testerPasswordValid" class="body">
        <div class="container">
            <div class="alert alert-warning m-3 text-center">
                <Icon v="exclamation-triangle" />
                This is a test server
            </div>
            <div class="m-3">
                <div class="input-group py-1">
                    <input v-model="testerPassword" class="form-control" type="password" placeholder="Password" @keydown.enter.prevent="checkTesterPassword">
                    <button type="button" class="btn btn-primary btn-sm border" @click.prevent="checkTesterPassword">
                        <Icon v="sign-in" />
                        Sign in
                    </button>
                </div>
                <p v-if="testerPasswordCookie && testerPasswordValid === false" class="small text-danger">
                    <Icon v="exclamation-triangle" />
                    Password invalid
                </p>
            </div>
        </div>
    </div>
    <div v-else class="body">
        <div class="flex-grow-1 vh">
            <Header />
            <slot></slot>
            <TranslationMode />
            <ScrollButton />
        </div>
        <Footer />
        <Lightbox />
    </div>
</template>

<style lang="scss">
    @import "assets/variables";
    @import "~avris-sorter/dist/Sorter.min.css";

    .vh {
        min-height: calc(100vh - #{$header-height});
    }
</style>
