import { ref } from 'vue'

/**
 * Charge les referentiels (listes courtes) alimentant les selects de l'ecran
 * « Ajouter un client » : categories, sites, modes de TVA, delais et types de
 * reglement, banques, pays, et les listes distributeurs / courtiers.
 *
 * Toutes les collections sont recuperees en entier via l'echappatoire prevue
 * `?pagination=false` (referentiels de quelques dizaines d'entrees max), avec
 * l'en-tete `Accept: application/ld+json` impose par API Platform 4 pour obtenir
 * l'enveloppe Hydra (`member`). Les valeurs d'option sont les IRI Hydra (`@id`)
 * pour pouvoir etre renvoyees telles quelles dans les payloads POST/PATCH
 * (relations ManyToOne / ManyToMany).
 *
 * Etat 100 % local a l'instance (refs) — aucune persistance URL.
 */

/** Option generique au format attendu par MalioSelect / MalioSelectCheckbox ({ label, value }). */
export interface RefOption {
    value: string
    label: string
}

/** Option de type de reglement enrichie de son code stable (RG-1.12 / RG-1.13). */
export interface PaymentTypeOption extends RefOption {
    code: string
}

/** Option de categorie enrichie de son code stable (filtrage RG-1.29 cote adresse). */
export interface CategoryOption extends RefOption {
    code: string
}

/** Option de client (distributeur / courtier) — value = IRI du client lie. */
export type ClientOption = RefOption

interface HydraMember {
    '@id': string
}

interface CategoryMember extends HydraMember {
    code: string
    name: string
}

interface SiteMember extends HydraMember {
    name: string
    postalCode: string
}

interface ReferentialMember extends HydraMember {
    code: string
    label: string
}

interface ClientMember extends HydraMember {
    companyName: string
}

interface CountryMember extends HydraMember {
    code: string
    name: string
}

const LD_JSON_HEADERS = { Accept: 'application/ld+json' }

export function useClientReferentials() {
    const api = useApi()

    const categories = ref<CategoryOption[]>([])
    const sites = ref<RefOption[]>([])
    const tvaModes = ref<RefOption[]>([])
    const paymentDelays = ref<RefOption[]>([])
    const paymentTypes = ref<PaymentTypeOption[]>([])
    const banks = ref<RefOption[]>([])
    const countries = ref<RefOption[]>([])
    const distributors = ref<ClientOption[]>([])
    const brokers = ref<ClientOption[]>([])

    /** Recupere une collection complete (pagination desactivee) en Hydra. */
    async function fetchAll<T extends HydraMember>(
        url: string,
        query: Record<string, string | string[]> = {},
    ): Promise<T[]> {
        const res = await api.get<{ member?: T[] }>(
            url,
            { pagination: 'false', ...query },
            { headers: LD_JSON_HEADERS, toast: false },
        )
        return res.member ?? []
    }

    /**
     * Charge en parallele les referentiels communs (hors distributeurs/courtiers,
     * charges a la demande selon la relation choisie).
     *
     * Chargement RESILIENT (Promise.allSettled) : chaque referentiel est isole.
     * Necessaire pour les roles metier qui n'ont pas toutes les permissions de
     * lecture — ex. Compta a `commercial.clients.view` (donc /tva_modes, /banks...
     * accessibles) mais PAS `catalog.categories.view` ni `sites.view` : sans
     * isolation, le 403 sur /categories ferait echouer tout le bloc et viderait
     * les selects comptables dont Compta a besoin sur l'ecran de modification.
     * Un referentiel en echec reste simplement vide (l'ecran d'edition complete
     * l'affichage des valeurs courantes depuis l'embed du detail client).
     */
    async function loadCommon(): Promise<void> {
        await Promise.allSettled([
            // Taxonomie multi-types (ERP-84) : un client ne porte que des categories
            // de type CLIENT (pas FOURNISSEUR) -> on filtre la collection cote API.
            fetchAll<CategoryMember>('/categories', { typeCode: 'CLIENT' })
                .then((cats) => { categories.value = cats.map(c => ({ value: c['@id'], label: c.name, code: c.code })) }),
            fetchAll<SiteMember>('/sites')
                // Libelle = numero de departement (2 premiers chiffres du code
                // postal du site), ex: 86100 -> « 86 ». Le code postal est deja
                // expose par /sites (groupe site:read) — aucune colonne a ajouter.
                .then((sitesList) => { sites.value = sitesList.map(s => ({ value: s['@id'], label: (s.postalCode ?? '').slice(0, 2) })) }),
            fetchAll<ReferentialMember>('/tva_modes')
                .then((tva) => { tvaModes.value = tva.map(t => ({ value: t['@id'], label: t.label })) }),
            fetchAll<ReferentialMember>('/payment_delays')
                .then((delays) => { paymentDelays.value = delays.map(d => ({ value: d['@id'], label: d.label })) }),
            fetchAll<ReferentialMember>('/payment_types')
                .then((types) => { paymentTypes.value = types.map(t => ({ value: t['@id'], label: t.label, code: t.code })) }),
            fetchAll<ReferentialMember>('/banks')
                .then((banksList) => { banks.value = banksList.map(b => ({ value: b['@id'], label: b.label })) }),
            // Pays (ERP-116) : la valeur d'option est le NOM du pays (et non l'IRI),
            // car l'adresse stocke `country` en chaine libre (« France »...). On
            // conserve ainsi la compatibilite avec les adresses existantes sans FK
            // ni migration de donnees a ce stade. value === label.
            fetchAll<CountryMember>('/countries')
                .then((list) => { countries.value = list.map(c => ({ value: c.name, label: c.name })) }),
        ])
    }

    /** Liste des clients pouvant etre choisis comme distributeur (code DISTRIBUTEUR). */
    async function loadDistributors(): Promise<void> {
        if (distributors.value.length > 0) {
            return
        }
        const clients = await fetchAll<ClientMember>('/clients', { categoryCode: 'DISTRIBUTEUR' })
        distributors.value = clients.map(c => ({ value: c['@id'], label: c.companyName }))
    }

    /** Liste des clients pouvant etre choisis comme courtier (code COURTIER). */
    async function loadBrokers(): Promise<void> {
        if (brokers.value.length > 0) {
            return
        }
        const clients = await fetchAll<ClientMember>('/clients', { categoryCode: 'COURTIER' })
        brokers.value = clients.map(c => ({ value: c['@id'], label: c.companyName }))
    }

    return {
        categories,
        sites,
        tvaModes,
        paymentDelays,
        paymentTypes,
        banks,
        countries,
        distributors,
        brokers,
        loadCommon,
        loadDistributors,
        loadBrokers,
    }
}
