import { ref } from 'vue' import { useApi } from './useApi' import { useToast } from './useToast' import { extractCollection, extractTotal } from '~/shared/utils/apiHelpers' export interface ConstructeurTelephone { '@id'?: string id?: string numero: string label?: string | null } export interface ConstructeurCategorieRef { '@id'?: string id: string name: string } export interface Constructeur { '@id'?: string id: string name: string email?: string | null telephones?: ConstructeurTelephone[] categories?: ConstructeurCategorieRef[] createdAt?: string updatedAt?: string } interface ConstructeurResult { success: boolean data?: Constructeur | Constructeur[] error?: string } export interface ConstructeurPageOptions { page?: number itemsPerPage?: number search?: string categoryId?: string orderField?: 'name' | 'email' | 'createdAt' orderDirection?: 'asc' | 'desc' } export interface ConstructeurPageResult { success: boolean items: Constructeur[] totalItems: number totalPages: number currentPage: number error?: string } const constructeurs = ref([]) const loading = ref(false) const loaded = ref(false) const uniqueConstructeurs = (items: Constructeur[] = []): Constructeur[] => { const map = new Map() items.forEach((item) => { if (item && typeof item === 'object' && typeof item.id === 'string') { map.set(item.id, item) } }) return Array.from(map.values()) } const normalizeIds = (ids: unknown[] = []): string[] => { if (!Array.isArray(ids)) { return [] } return Array.from( new Set( ids .map((value) => (typeof value === 'string' ? value.trim() : '')) .filter((value) => value.length > 0), ), ) } const upsertConstructeurs = (items: Constructeur[] = []) => { if (!Array.isArray(items) || !items.length) { return } const merged = uniqueConstructeurs([...constructeurs.value, ...items]) constructeurs.value = merged } const getIndexedConstructeur = (id: string): Constructeur | null => constructeurs.value.find((item) => item && item.id === id) || null const pendingFetches = new Map>() export function useConstructeurs() { const { get, post, patch, delete: del } = useApi() const { showSuccess, showError } = useToast() const loadConstructeurs = async (search = '', options: { force?: boolean } = {}): Promise => { if (!search && !options.force && loaded.value) { return { success: true, data: constructeurs.value } } loading.value = true try { const params = new URLSearchParams() params.set('itemsPerPage', '2000') if (search) params.set('search', search) const result = await get(`/constructeurs?${params.toString()}`) if (result.success) { const items = extractCollection(result.data) constructeurs.value = uniqueConstructeurs(items) if (!search) loaded.value = true } return result as ConstructeurResult } catch (error) { const err = error as Error console.error('Erreur lors du chargement des fournisseurs:', error) return { success: false, error: err.message } } finally { loading.value = false } } const searchConstructeurs = async (search = ''): Promise => { return loadConstructeurs(search) } const fetchConstructeursPage = async (opts: ConstructeurPageOptions = {}): Promise => { const page = Math.max(1, opts.page ?? 1) const itemsPerPage = Math.max(1, opts.itemsPerPage ?? 30) loading.value = true try { const params = new URLSearchParams() params.set('page', String(page)) params.set('itemsPerPage', String(itemsPerPage)) if (opts.search && opts.search.trim()) params.set('search', opts.search.trim()) if (opts.categoryId) params.set('categories.id', opts.categoryId) if (opts.orderField) { params.set(`order[${opts.orderField}]`, opts.orderDirection ?? 'asc') } const result = await get(`/constructeurs?${params.toString()}`) if (!result.success) { return { success: false, items: [], totalItems: 0, totalPages: 0, currentPage: page, error: result.error } } const items = extractCollection(result.data) const totalItems = extractTotal(result.data, items.length) const totalPages = Math.max(1, Math.ceil(totalItems / itemsPerPage)) upsertConstructeurs(items) return { success: true, items, totalItems, totalPages, currentPage: page } } catch (error) { const err = error as Error console.error('Erreur lors du chargement de la page fournisseurs:', error) return { success: false, items: [], totalItems: 0, totalPages: 0, currentPage: page, error: err.message } } finally { loading.value = false } } const createConstructeur = async (data: Record): Promise => { loading.value = true try { const result = await post('/constructeurs', data) if (result.success) { upsertConstructeurs([result.data as Constructeur]) showSuccess(`Fournisseur "${(result.data as Constructeur).name}" créé`) } else if (result.error) { showError(result.error) } return result as ConstructeurResult } catch (error) { const err = error as Error console.error('Erreur lors de la création du fournisseur:', error) showError('Impossible de créer le fournisseur') return { success: false, error: err.message } } finally { loading.value = false } } const ensureConstructeurs = async (ids: unknown[] = []): Promise => { const normalizedIds = normalizeIds(ids) if (!normalizedIds.length) { return [] } const collected: Constructeur[] = [] const missing: string[] = [] normalizedIds.forEach((id) => { const existing = getIndexedConstructeur(id) if (existing) { collected.push(existing) } else { missing.push(id) } }) if (missing.length) { const fetchTasks = missing.map((id) => { const cached = pendingFetches.get(id) if (cached) { return cached } const task = get(`/constructeurs/${id}`) .then((result) => { if (result.success && result.data) { return result.data as Constructeur } return null }) .catch((error) => { console.error('Erreur lors du chargement du fournisseur:', error) return null }) .finally(() => { pendingFetches.delete(id) }) pendingFetches.set(id, task) return task }) const fetched = await Promise.all(fetchTasks) const validFetched = fetched.filter((item): item is Constructeur => item !== null && item.id !== undefined) if (validFetched.length) { upsertConstructeurs(validFetched) } } return normalizedIds .map((id) => getIndexedConstructeur(id)) .filter((item): item is Constructeur => item !== null) } const updateConstructeur = async (id: string, data: Record): Promise => { loading.value = true try { const result = await patch(`/constructeurs/${id}`, data) if (result.success) { upsertConstructeurs([result.data as Constructeur]) showSuccess(`Fournisseur "${(result.data as Constructeur).name}" mis à jour`) } else if (result.error) { showError(result.error) } return result as ConstructeurResult } catch (error) { const err = error as Error console.error('Erreur lors de la mise à jour du fournisseur:', error) showError('Impossible de mettre à jour le fournisseur') return { success: false, error: err.message } } finally { loading.value = false } } const deleteConstructeur = async (id: string): Promise => { loading.value = true try { const result = await del(`/constructeurs/${id}`) if (result.success) { constructeurs.value = constructeurs.value.filter((item) => item.id !== id) showSuccess('Fournisseur supprimé') } else if (result.error) { showError(result.error) } return result as ConstructeurResult } catch (error) { const err = error as Error console.error('Erreur lors de la suppression du fournisseur:', error) showError('Impossible de supprimer le fournisseur') return { success: false, error: err.message } } finally { loading.value = false } } const getConstructeurById = (id: string) => getIndexedConstructeur(id) return { constructeurs, loading, loadConstructeurs, searchConstructeurs, fetchConstructeursPage, createConstructeur, updateConstructeur, deleteConstructeur, getConstructeurById, ensureConstructeurs, } }