<script setup lang="ts">
import type SourceSubmitForm from '~/components/SourceSubmitForm.vue';
import { Source, SourceLibrary } from '~/src/classes.ts';
import { loadPronounLibrary } from '~/src/data.ts';
import { changeSourceInjectionKey } from '~/src/injectionKeys.ts';

definePageMeta({
    translatedPaths: (config) => translatedPathByConfigModule(config.sources),
});

const { $translator: translator } = useNuxtApp();
const config = useConfig();

const pronounLibrary = await loadPronounLibrary(config);
const pronouns = pronounLibrary.pronouns;

useSimpleHead({
    title: translator.translate('sources.headerLonger'),
    description: translator.translate('sources.subheader'),
}, translator);

const filter = useFilterWithCategory();

const { data: rawSources } = await useFetch('/api/sources', { lazy: true });
const sourceLibrary = computed(() => {
    if (rawSources.value === null) {
        return undefined;
    }
    return new SourceLibrary(config, rawSources.value);
});

const tocShown = ref(false);
const glue = ` ${translator.translate('pronouns.or')} `;
const submitShown = ref(false);

const tocPronounGroups = computed(() => {
    const pronounGroups = pronounLibrary.split((pronoun) => {
        if (sourceLibrary.value === undefined) {
            return false;
        }
        return sourceLibrary.value.getForPronoun(pronoun.canonicalName).length > 0;
    }, false);
    return [...pronounGroups].filter(([_, groupPronouns]) => groupPronouns.length > 0);
});

const categories = computed(() => {
    return Object.entries(Source.TYPES)
        .filter(([type]) => type)
        .map(([type, icon]) => ({
            key: type,
            text: translator.translate(`sources.type.${type}`),
            icon,
        }));
});

const toId = (str: string): string => {
    return str.replace(/\//g, '-').replace(/&/g, '_');
};

const form = useTemplateRef<InstanceType<typeof SourceSubmitForm>>('form');

const dialogue = useDialogue();

provide(changeSourceInjectionKey, {
    async approve(source: Source) {
        await dialogue.postWithAlertOnError(`/api/sources/approve/${source.id}`);
        rawSources.value = (rawSources.value ?? []).map((sourceRaw) => {
            if (sourceRaw.id !== source.id) {
                return sourceRaw;
            }
            return { ...sourceRaw, approved: true, base_id: null };
        });
    },
    async hide(source: Source) {
        await dialogue.postWithAlertOnError(`/api/sources/hide/${source.id}`);
        rawSources.value = (rawSources.value ?? []).map((sourceRaw) => {
            if (sourceRaw.id !== source.id) {
                return sourceRaw;
            }
            return { ...sourceRaw, approved: false };
        });
    },
    async remove(source: Source) {
        await dialogue.confirm(translator.translate('crud.removeConfirm'), 'danger');

        await dialogue.postWithAlertOnError(`/api/sources/remove/${source.id}`);
        rawSources.value = (rawSources.value ?? []).filter((sourceRaw) => sourceRaw.id !== source.id);
    },
    edit(source: Source) {
        submitShown.value = true;
        nextTick(() => {
            form.value?.edit(source);
        });
    },
});
</script>

<template>
    <Page v-if="config.sources.enabled">
        <h2>
            <Icon v="books" />
            <T>sources.headerLonger</T>
        </h2>

        <p v-if="$t('sources.subheader')">
            <em><T>sources.subheader</T></em>
        </p>

        <section>
            <Share :title="$t('sources.headerLonger')" />
        </section>

        <AdPlaceholder :phkey="['content-0', 'content-mobile-0']" />

        <SourcesChart :sources="rawSources" label="all pronouns" />

        <Loading :value="sourceLibrary" size="5rem">
            <template v-if="sourceLibrary !== undefined">
                <section v-show="config.sources.submit">
                    <SourceSubmitForm v-show="submitShown" ref="form" />
                    <button
                        v-show="!submitShown"
                        type="button"
                        class="btn btn-success w-100"
                        @click="submitShown = true"
                    >
                        <Icon v="plus-circle" />
                        <T>sources.submit.header</T>
                    </button>
                </section>

                <section>
                    <button
                        v-if="!tocShown"
                        type="button"
                        class="btn btn-outline-primary w-100"
                        @click="tocShown = true"
                    >
                        <Icon v="list" />
                        <T>sources.toc</T>
                    </button>
                    <ul v-if="tocShown" class="list-group">
                        <li v-for="[group, groupPronouns] in tocPronounGroups" class="list-group-item">
                            <p class="h5">
                                {{ group.name }}
                            </p>
                            <div v-if="group.description" class="small my-1">
                                <Icon v="info-circle" />
                                <em v-html="group.description"></em>
                            </div>
                            <ul class="list-unstyled">
                                <template v-for="pronoun in groupPronouns">
                                    <li
                                        v-if="config.sources.mergePronouns?.[pronoun.canonicalName] === undefined"
                                        :key="pronoun.canonicalName"
                                    >
                                        <a :href="`#${toId(pronoun.name(glue))}`">
                                            <strong>{{ pronoun.name(glue) }}</strong>
                                            –
                                            <small>{{ pronoun.description }}</small>
                                        </a>
                                        <NormativeBadge v-if="pronoun.normative" />
                                    </li>
                                </template>
                            </ul>
                        </li>
                        <li v-if="sourceLibrary.multiple.length" class="list-group-item">
                            <p class="h5 mb-0">
                                <a :href="`#${$t('pronouns.alt.raw')}`">
                                    <strong><T>pronouns.alt.header</T></strong>
                                </a>
                            </p>
                        </li>
                        <li v-if="sourceLibrary.getForPronoun('', pronounLibrary)" class="list-group-item">
                            <p class="h5 mb-0">
                                <a :href="`#${$t('pronouns.othersRaw')}`">
                                    <strong><T>pronouns.others</T></strong>
                                </a>
                            </p>
                        </li>
                    </ul>
                </section>

                <ModerationSection
                    v-model="filter.moderation"
                    kind="sources"
                    :moderation-filters="['unapproved', 'no key']"
                    :entries="sourceLibrary.sources"
                />

                <ModerationRules type="rulesSources" emphasise />

                <FilterBar
                    v-model="filter.text"
                    v-model:category="filter.category"
                    :categories="categories"
                />

                <template v-for="pronoun in pronouns">
                    <section v-if="config.sources.mergePronouns?.[pronoun.canonicalName] === undefined && sourceLibrary.getForPronoun(pronoun.canonicalName).length">
                        <SourceList
                            :sources="sourceLibrary.getForPronoun(pronoun.canonicalName)"
                            :pronoun="pronoun"
                            :filter="filter"
                        >
                            <h2 :id="toId(pronoun.name(glue))" class="h4">
                                <nuxt-link :to="`/${pronoun.canonicalName}`">
                                    {{ pronoun.description }}
                                    <small>({{ pronoun.name(glue) }})</small>
                                </nuxt-link>
                            </h2>
                        </SourceList>
                    </section>
                </template>

                <a :id="$t('pronouns.alt.raw')"></a>
                <template v-for="multiple in sourceLibrary.multiple">
                    <section v-if="sourceLibrary.getForPronoun(multiple).length">
                        <SourceList
                            :sources="sourceLibrary.getForPronoun(multiple)"
                            :filter="filter"
                        >
                            <h2 :id="toId(multiple)" class="h4">
                                <nuxt-link :to="`/${multiple}`">
                                    <T>pronouns.alt.header</T>
                                    <small>({{ multiple.replace(/&/g, glue) }})</small>
                                </nuxt-link>
                            </h2>
                        </SourceList>
                    </section>
                </template>

                <section v-if="sourceLibrary.getForPronoun('', pronounLibrary)">
                    <SourceList
                        :sources="sourceLibrary.getForPronoun('', pronounLibrary)"
                        :filter="filter"
                    >
                        <h2 :id="$t('pronouns.othersRaw')" class="h4">
                            <T>pronouns.others</T>
                        </h2>
                    </SourceList>
                </section>
            </template>
        </Loading>

        <AdPlaceholder :phkey="['content-1', 'content-mobile-1']" />
    </Page>
</template>
