<template>
    <div>
        <PageHeader>
            {{ t('admin.categories.title') }}
            <template #actions>
                <!-- gap-8 = 32px d'espacement entre Filtres et Ajouter (meme
                     design que le Repertoire Clients). -->
                <div class="flex items-center gap-8">
                    <!-- Bouton Filtres a GAUCHE d'Ajouter. Le compteur reflete
                         les filtres actifs. -->
                    <MalioButton
                        variant="tertiary"
                        :label="filterButtonLabel"
                        icon-name="mdi:tune"
                        icon-position="left"
                        icon-size="24"
                        @click="openFilters"
                    />
                    <MalioButton
                        v-if="canManage"
                        variant="secondary"
                        :label="t('admin.categories.newCategory')"
                        icon-name="mdi:add-bold"
                        icon-position="left"
                        @click="openCreateDrawer"
                    />
                </div>
            </template>
        </PageHeader>

        <!-- Table des categories. Tri serveur (name ASC, RG-1.10) +
             pagination serveur via usePaginatedList (#73). Le composable
             remplace l'ancien chargement « tout en un coup » a volumetrie
             cible ≤ 300 — la pagination est desormais alignee sur la regle
             projet (toute collection paginee, regle ABSOLUE n°13). -->
        <MalioDataTable
            :columns="columns"
            :items="categoryItems"
            :total-items="totalItems"
            :page="currentPage"
            :per-page="itemsPerPage"
            :per-page-options="itemsPerPageOptions"
            :row-clickable="true"
            :empty-message="t('admin.categories.noCategories')"
            @row-click="onRowClick"
            @update:page="goToPage"
            @update:per-page="setItemsPerPage"
        />

        <!-- Drawer creation / consultation / edition. -->
        <CategoryDrawer
            v-model="drawerOpen"
            :category="selectedCategory"
            @saved="onCategorySaved"
            @delete="onDeleteRequest"
        />

        <!-- Modale de confirmation suppression (soft delete cote serveur). -->
        <CategoryDeleteModal
            v-model="deleteModalOpen"
            :category-name="categoryToDelete?.name ?? ''"
            :loading="deleting"
            @confirm="handleDelete"
        />

        <!-- Drawer de filtres : etat BROUILLON, applique uniquement au clic sur
             « Appliquer ». Meme pattern que le Repertoire Clients. Etat 100 %
             local, jamais dans l'URL (regle ABSOLUE n°6). -->
        <MalioDrawer
            v-model="filterDrawerOpen"
            drawer-class="max-w-[450px]"
            body-class="p-0"
            footer-class="justify-between border-t border-black p-6"
        >
            <template #header>
                <h2 class="text-[24px] font-bold uppercase">{{ t('admin.categories.filters.title') }}</h2>
            </template>

            <MalioAccordion>
                <!-- Recherche par nom (param `name`, partiel insensible a la casse). -->
                <MalioAccordionItem :title="t('admin.categories.filters.search')" value="search">
                    <MalioInputText
                        v-model="draftSearch"
                        icon-name="mdi:magnify"
                    />
                </MalioAccordionItem>

                <!-- Type(s) : cases a cocher (multi). Une categorie remonte si
                     elle porte AU MOINS UN des types coches (OR cote back). -->
                <MalioAccordionItem :title="t('admin.categories.filters.types')" value="types">
                    <div class="flex flex-col">
                        <MalioCheckbox
                            v-for="opt in typeFilterOptions"
                            :id="`filter-type-${opt.value}`"
                            :key="opt.value"
                            :label="opt.label"
                            :model-value="draftTypeIds.includes(opt.value)"
                            @update:model-value="(val: boolean) => toggleType(opt.value, val)"
                        />
                    </div>
                </MalioAccordionItem>
            </MalioAccordion>

            <template #footer>
                <MalioButton
                    variant="tertiary"
                    :label="t('admin.categories.filters.reset')"
                    button-class="w-m-btn-action"
                    @click="resetFilters"
                />
                <MalioButton
                    variant="primary"
                    :label="t('admin.categories.filters.apply')"
                    button-class="w-[170px]"
                    @click="applyFilters"
                />
            </template>
        </MalioDrawer>
    </div>
</template>

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

const { t } = useI18n()
const { can } = usePermissions()
const { types, fetchTypes } = useCategoriesAdmin()
const { submitDelete } = useCategoryForm()

useHead({ title: t('admin.categories.title') })

const canManage = computed(() => can('catalog.categories.manage'))

// Pagination serveur via le composable partage (#73). Le CategoryProvider
// applique deja name ASC (RG-1.10) — pas besoin de defaultSort cote front
// tant qu'aucun OrderFilter n'est expose.
const {
    items: categories,
    totalItems,
    currentPage,
    itemsPerPage,
    itemsPerPageOptions,
    fetch: fetchCategories,
    goToPage,
    setItemsPerPage,
    setFilters,
} = usePaginatedList<Category>({ url: '/categories' })

const drawerOpen = ref(false)
const selectedCategory = ref<Category | null>(null)
const deleteModalOpen = ref(false)
const categoryToDelete = ref<Category | null>(null)
const deleting = ref(false)

// Colonnes du datatable. Les types sont embarques cote API (ManyToMany) — on
// aplatit en libelles joints par une virgule pour l'affichage.
const columns = [
    { key: 'name', label: t('admin.categories.table.name') },
    { key: 'typesLabel', label: t('admin.categories.table.types') },
]

const categoryItems = computed(() =>
    categories.value.map(cat => ({
        id: cat.id,
        name: cat.name,
        typesLabel: (cat.categoryTypes ?? []).map(ct => ct.label).join(', '),
    })),
)

// ── Filtres (drawer) ────────────────────────────────────────────────────────
// Deux niveaux d'etat (pattern Repertoire Clients) :
//  - APPLIED : pilote la liste + le compteur du bouton. Modifie uniquement au
//    clic « Appliquer » / « Réinitialiser ».
//  - DRAFT : edite librement dans le drawer ; recopie vers applied a la validation.
const filterDrawerOpen = ref(false)

const draftSearch = ref('')
const draftTypeIds = ref<number[]>([])

const appliedSearch = ref('')
const appliedTypeIds = ref<number[]>([])

// Options du filtre Type(s), derivees du referentiel deja charge (fetchTypes).
const typeFilterOptions = computed(() =>
    types.value.map(ct => ({ value: ct.id, label: ct.label })),
)

const activeFilterCount = computed(() => {
    let count = 0
    if (appliedSearch.value.trim() !== '') count++
    if (appliedTypeIds.value.length > 0) count++
    return count
})

const filterButtonLabel = computed(() => {
    const base = t('admin.categories.filters.title')
    return activeFilterCount.value > 0 ? `${base} (${activeFilterCount.value})` : base
})

// Recopie l'etat applique vers le brouillon puis ouvre le drawer.
function openFilters(): void {
    draftSearch.value = appliedSearch.value
    draftTypeIds.value = [...appliedTypeIds.value]
    filterDrawerOpen.value = true
}

function toggleType(id: number, selected: boolean): void {
    draftTypeIds.value = selected
        ? [...draftTypeIds.value, id]
        : draftTypeIds.value.filter(t => t !== id)
}

/**
 * Construit le payload de filtres serveur a partir de l'etat applique. Cle
 * `typeId[]` pour que PHP la parse en tableau (OR cote back). Filtres vides omis.
 */
function buildFilterPayload(): Record<string, string | string[]> {
    const payload: Record<string, string | string[]> = {}
    if (appliedSearch.value.trim() !== '') payload.name = appliedSearch.value.trim()
    if (appliedTypeIds.value.length > 0) payload['typeId[]'] = appliedTypeIds.value.map(String)
    return payload
}

// « Appliquer » : recopie brouillon → applied, pousse les filtres (retombe en
// page 1 via usePaginatedList) et ferme le drawer.
function applyFilters(): void {
    appliedSearch.value = draftSearch.value.trim()
    appliedTypeIds.value = [...draftTypeIds.value]

    setFilters(buildFilterPayload(), { replace: true })
    filterDrawerOpen.value = false
}

// « Réinitialiser » : vide brouillon ET applied, recharge la liste complete.
// Le drawer reste ouvert pour montrer le formulaire vide.
function resetFilters(): void {
    draftSearch.value = ''
    draftTypeIds.value = []
    appliedSearch.value = ''
    appliedTypeIds.value = []

    setFilters({}, { replace: true })
}

function getCategoryById(id: number): Category | undefined {
    return categories.value.find(c => c.id === id)
}

function onRowClick(item: Record<string, unknown>) {
    const category = getCategoryById(item.id as number)
    if (category) openEditDrawer(category)
}

function openCreateDrawer() {
    selectedCategory.value = null
    drawerOpen.value = true
}

function openEditDrawer(category: Category) {
    selectedCategory.value = category
    drawerOpen.value = true
}

function onDeleteRequest() {
    if (!selectedCategory.value) return
    categoryToDelete.value = selectedCategory.value
    deleteModalOpen.value = true
}

/**
 * Soft delete via le composable de form (qui gere toast + erreur). Refresh
 * de la liste a la fin pour retirer la ligne. L'index unique partiel
 * autorise une recreation ulterieure avec le meme couple (name, type) —
 * RG-1.07.
 */
async function handleDelete(): Promise<void> {
    if (!categoryToDelete.value) return
    deleting.value = true
    try {
        const ok = await submitDelete(categoryToDelete.value.id)
        if (ok) {
            deleteModalOpen.value = false
            categoryToDelete.value = null
            drawerOpen.value = false
            await fetchCategories()
        }
    } finally {
        deleting.value = false
    }
}

function onCategorySaved() {
    fetchCategories()
}

// Chargement initial des deux ressources (liste + referentiel des types).
// Le referentiel est pre-charge ici (et pas dans le drawer) pour que le
// select soit pret au moment ou l'utilisateur clique sur « + Ajouter ».
onMounted(() => {
    fetchCategories()
    fetchTypes()
})
</script>
