<script setup lang="ts">
import { useNuxtApp } from 'nuxt/app';

import type NameSubmitForm from '~/components/NameSubmitForm.vue';
import useConfig from '~/composables/useConfig.ts';
import useDialogue from '~/composables/useDialogue.ts';
import useHash from '~/composables/useHash.ts';
import useSimpleHead from '~/composables/useSimpleHead.ts';
import { Name, type NameRaw } from '~/src/classes.ts';
import { buildDict } from '~/src/helpers.ts';

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

const { $translator: translator } = useNuxtApp();
useSimpleHead({
    title: translator.translate('names.headerLong'),
    description: translator.translate('names.description'),
}, translator);
const { handleHash, setHash } = useHash();

const namesAsyncData = useAsyncData(async () => {
    const namesRaw = await $fetch<NameRaw[]>('/api/names');

    return buildDict(function* () {
        const sorted = namesRaw.sort((a, b) => {
            if (a.approved && !b.approved) {
                return 1;
            }
            if (!a.approved && b.approved) {
                return -1;
            }
            return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
        });
        for (const n of sorted) {
            yield [n.id, new Name(n)];
        }
    });
}, {
    server: false,
});

const config = useConfig();

const filter = ref('');
watch(filter, () => {
    setHash('', filter.value);
});

const names = computed(() => {
    if (namesAsyncData.status.value !== 'success') {
        return {};
    }
    return namesAsyncData.data.value!;
});

const filterBar = useTemplateRef('filterBar');
onMounted(async () => {
    handleHash('', (hash) => {
        filter.value = hash;
        if (hash) {
            filterBar.value?.focus();
        }
    });
});

const visibleNames = computed(() => {
    return Object.values(names.value).filter((n) => n.matches(filter.value));
});

const form = useTemplateRef<InstanceType<typeof NameSubmitForm>>('form');
const edit = (name: Name) => {
    form.value?.edit(name);
};

const dialogue = useDialogue();
const approve = async (name: Name) => {
    await dialogue.postWithAlertOnError(`/api/names/approve/${name.id}`);
    if (name.base) {
        delete names.value[name.base];
    }
    name.approved = true;
    name.base = null;
};
const hide = async (name: Name) => {
    await dialogue.postWithAlertOnError(`/api/names/hide/${name.id}`);
    name.approved = false;
};
const remove = async (name: Name) => {
    await dialogue.confirm(translator.translate('crud.removeConfirm'), 'danger');

    await dialogue.postWithAlertOnError(`/api/names/remove/${name.id}`);
    delete names.value[name.id];
};

// those must be methods, not computed, because when modified, they don't get updated in the view for some reason
const namesCountApproved = () => {
    return Object.values(names.value).filter((n) => n.approved).length;
};
const namesCountPending = () => {
    return Object.values(names.value).filter((n) => !n.approved).length;
};
</script>

<template>
    <Page>
        <NotFound v-if="!config.names || !config.names.enabled || !config.names.published && !$isGranted('names')" />
        <div v-else>
            <CommunityNav />

            <h2>
                <Icon v="signature" />
                <T>names.headerLong</T>
            </h2>

            <section>
                <T>names.intro</T>
                <NamesLinks />
            </section>

            <section v-if="$isGranted('names')" class="px-3">
                <div class="alert alert-info">
                    <strong>{{ namesCountApproved() }}</strong> <T>nouns.approved</T>,
                    <strong>{{ namesCountPending() }}</strong> <T>nouns.pending</T>.
                </div>
            </section>

            <FilterBar
                ref="filterBar"
                v-model="filter"
                submit-button
                @submit-clicked="form?.focus()"
            />

            <section>
                <Loading :value="namesAsyncData.data.value">
                    <ul class="list-group small">
                        <template v-if="visibleNames.length">
                            <li v-for="name in visibleNames" :class="['list-group-item', name.approved ? '' : 'marked']">
                                <NamesEntry :name="name">
                                    <ul class="list-inline small">
                                        <template v-if="$isGranted('names')">
                                            <li v-if="name.author" class="list-inline-item small">
                                                <nuxt-link :to="`/@${name.author}`" class="btn btn-outline-dark btn-sm">
                                                    <Icon v="user" />
                                                    <span class="btn-label">
                                                        <T>crud.author</T><T>quotation.colon</T>
                                                        @{{ name.author }}
                                                    </span>
                                                </nuxt-link>
                                            </li>
                                            <li v-if="!name.approved" class="list-inline-item">
                                                <button class="btn btn-success btn-sm" @click="approve(name)">
                                                    <Icon v="check" />
                                                    <span class="btn-label"><T>crud.approve</T></span>
                                                </button>
                                            </li>
                                            <li v-else class="list-inline-item" @click="hide(name)">
                                                <button class="btn btn-outline-secondary btn-sm">
                                                    <Icon v="times" />
                                                    <span class="btn-label"><T>crud.hide</T></span>
                                                </button>
                                            </li>
                                            <li class="list-inline-item">
                                                <button class="btn btn-outline-danger btn-sm" @click="remove(name)">
                                                    <Icon v="trash" />
                                                    <span class="btn-label"><T>crud.remove</T></span>
                                                </button>
                                            </li>
                                        </template>
                                        <li class="list-inline-item">
                                            <button class="btn btn-outline-primary btn-sm" @click="edit(name)">
                                                <Icon v="pen" />
                                                <span class="btn-label">
                                                    <T v-if="$isGranted('names')">crud.edit</T>
                                                    <T v-else>nouns.edit</T>
                                                </span>
                                            </button>
                                        </li>
                                    </ul>
                                </NamesEntry>

                                <small v-if="name.base && names[name.base]">
                                    <hr>
                                    <p><strong><T>nouns.edited</T><T>quotation.colon</T></strong></p>
                                    <Diff switchable>
                                        <template #before><NamesEntry :name="names[name.base]" /></template>
                                        <template #after><NamesEntry :name="name" /></template>
                                    </Diff>
                                </small>
                            </li>
                        </template>
                        <template v-else>
                            <li class="list-group-item text-center">
                                <Icon v="search" />
                                <T>names.empty</T>
                            </li>
                        </template>
                    </ul>
                </Loading>
            </section>

            <Separator icon="plus" />

            <NameSubmitForm ref="form" />
        </div>
    </Page>
</template>

<style lang="scss">
    @import "assets/variables";

    @include media-breakpoint-up('md') {
        .w-md-50 {
            width: 50%;
        }
    }

    .list-group-item.marked {
        border-inline-start: 3px solid $primary;
    }
</style>
