<template>
    <MalioDrawer
        :model-value="modelValue"
        drawer-class="w-full max-w-lg"
        header-class="border-b border-black"
        footer-class="justify-between border-t border-black p-6"
        @update:model-value="emit('update:modelValue', $event)"
    >
        <template #header>
            <h2 class="text-2xl font-bold">
                {{ headerLabel }}
            </h2>
        </template>

        <form class="flex flex-col py-4 gap-2" @submit.prevent="handleSave">
            <!-- Nom (RG-1.02 obligatoire / RG-1.04 longueur 2-120 apres trim).
                 Erreur miroir client + erreurs server-side (422) mappees sur ce champ. -->
            <MalioInputText
                v-model="form.name.value"
                :label="t('admin.categories.form.name')"
                input-class="w-full"
                :max-length="120"
                :error="form.errors.name"
                required
            />

            <!-- Types (RG-1.05 : au moins un obligatoire). MalioSelectCheckbox
                 porte un tableau d'ids (categoryType id) ; conversion en tableau
                 d'IRI au moment du save par le composable useCategoryForm. -->
            <MalioSelectCheckbox
                v-model="form.categoryTypeIds.value"
                :options="typeOptions"
                :label="t('admin.categories.form.types')"
                :error="form.errors.categoryTypes"
                :display-tag="true"
                :disabled="loadingTypes"
                required
            />
        </form>

        <!-- Footer fixe : depuis 1.7.1 le slot #footer est un frere du body
             scrollable (shrink-0), donc reellement fige sans sticky. -->
        <template #footer>
            <MalioButton
                v-if="canShowDelete"
                :label="t('common.delete')"
                variant="danger"
                icon-name="mdi:delete-outline"
                icon-position="left"
                button-class="w-m-btn-action"
                @click="emit('delete')"
            />
            <MalioButton
                v-else
                :label="t('common.cancel')"
                variant="tertiary"
                button-class="w-m-btn-action"
                @click="emit('update:modelValue', false)"
            />
            <MalioButton
                v-if="canShowSave"
                :label="isCreateMode ? t('common.validate') : t('common.save')"
                variant="primary"
                button-class="w-m-btn-action"
                :disabled="form.submitting.value || loadingTypes"
                @click="handleSave"
            />
        </template>
    </MalioDrawer>
</template>

<script setup lang="ts">
import type { Category } from '~/modules/catalog/types/category'

const { t } = useI18n()
const { can } = usePermissions()
const { types, loadingTypes, fetchTypes } = useCategoriesAdmin()
// Instance dediee de form pour ce drawer — state isole (cf. useCategoryForm
// n'est pas singleton, contrairement a useCategoriesAdmin).
const form = useCategoryForm()

const props = defineProps<{
    modelValue: boolean
    category: Category | null
}>()

const emit = defineEmits<{
    'update:modelValue': [value: boolean]
    saved: []
    delete: []
}>()

// Mode du drawer : creation (pas de category prop, POST au save) ou
// modification d'une categorie existante (PATCH au save). Pas de distinction
// view/edit : comme les autres drawers, le titre et le bouton Enregistrer sont
// stables quel que soit l'etat « dirty » du formulaire.
const isCreateMode = computed(() => props.category === null)

const headerLabel = computed(() =>
    isCreateMode.value
        ? t('admin.categories.createCategory')
        : t('admin.categories.editCategory'),
)

// Le bouton Supprimer n'est visible qu'en consultation/edition d'une categorie
// existante et seulement pour les users ayant la permission manage. En mode
// creation on affiche un bouton Annuler a la place.
const canShowDelete = computed(
    () => !isCreateMode.value && can('catalog.categories.manage'),
)

// Save : visible en creation, et en consultation/edition d'une categorie
// existante (l'utilisateur doit pouvoir enregistrer sans qu'un champ ait
// d'abord ete modifie). Le bouton reste neanmoins protege par son `disabled`
// pendant la soumission / le chargement des types.
const canShowSave = computed(
    () => isCreateMode.value || can('catalog.categories.manage'),
)

const typeOptions = computed(() =>
    types.value.map(ct => ({
        label: ct.label,
        value: ct.id,
    })),
)

// Re-initialise le form quand la categorie selectionnee change (clic sur une
// autre ligne sans fermer le drawer entre-temps).
watch(() => props.category, (cat) => {
    form.loadFrom(cat)
}, { immediate: true })

// A chaque ouverture du drawer : reload du form + refresh des types (au cas
// ou un type aurait ete ajoute en arriere-plan depuis le dernier fetch — pas
// d'optimisation cache au M0, le referentiel est petit).
watch(
    () => props.modelValue,
    (open) => {
        if (open) {
            form.loadFrom(props.category)
            fetchTypes()
        }
    },
)

/**
 * Sauvegarde : delegue au composable (POST en creation, PATCH en modification).
 * Le toast succes + mapping erreur 409/422 est gere par le composable. Le PATCH
 * envoie le payload complet, donc le bouton Enregistrer sauvegarde a tout
 * moment (meme sans modification). En cas de succes, on ferme le drawer et on
 * previent le parent pour qu'il refresh la liste.
 */
async function handleSave(): Promise<void> {
    const result = isCreateMode.value
        ? await form.submitCreate()
        : props.category
            ? await form.submitUpdate(props.category.id)
            : null
    if (result) {
        emit('saved')
        emit('update:modelValue', false)
    }
}
</script>
