import { httpExternal } from '~/shared/utils/httpExternal'

// Autocompletion d'adresse branchee sur la Base Adresse Nationale (BAN),
// `api-adresse.data.gouv.fr` — service public francais, gratuit, CORS ouvert.
//
// Appel HTTP DIRECT depuis le front (pas de proxy back), conformement a la spec
// M1 (§ API adresse postale). On passe par `httpExternal` et NON `useApi()` :
// la BAN est un domaine externe, sans cookie de session ni enveloppe Hydra.
//
// Contrat (fige) :
//   searchCity(postalCode)       -> liste { city, postalCode }
//   searchAddress(query, cp?)    -> liste { label, street, postalCode, city }
//   En cas d'erreur/timeout, la methode THROW une AddressAutocompleteUnavailableError.
//   Le composant consommateur catch, affiche un toast d'avertissement et bascule
//   en saisie libre (MalioInputText).

/** URL de l'endpoint de recherche BAN. */
const BAN_SEARCH_URL = 'https://api-adresse.data.gouv.fr/search/'

/** Une suggestion de ville renvoyee a partir d'un code postal. */
export interface CitySuggestion {
    city: string
    postalCode: string
}

/** Une suggestion d'adresse complete (saisie assistee du champ « Adresse »). */
export interface AddressSuggestion {
    label: string
    street: string
    postalCode: string
    city: string
}

export interface AddressAutocomplete {
    searchCity(postalCode: string): Promise<CitySuggestion[]>
    searchAddress(query: string, postalCode?: string): Promise<AddressSuggestion[]>
}

/** Erreur signalant que le service d'autocompletion BAN n'est pas disponible. */
export class AddressAutocompleteUnavailableError extends Error {
    constructor() {
        // Message technique (non affiche tel quel) : le composant remonte son
        // propre libelle i18n. Sert au debug / aux logs uniquement.
        super('Address autocomplete (BAN) is not available.')
        this.name = 'AddressAutocompleteUnavailableError'
    }
}

/** Proprietes d'une « feature » GeoJSON renvoyee par la BAN (champs utilises). */
interface BanFeatureProperties {
    label?: string
    name?: string
    street?: string
    postcode?: string
    city?: string
}

/** Reponse GeoJSON FeatureCollection de la BAN. */
interface BanResponse {
    features?: { properties?: BanFeatureProperties }[]
}

export function useAddressAutocomplete(): AddressAutocomplete {
    return {
        async searchCity(postalCode: string): Promise<CitySuggestion[]> {
            let res: BanResponse
            try {
                res = await httpExternal<BanResponse>(BAN_SEARCH_URL, {
                    query: { q: postalCode, type: 'municipality' },
                })
            } catch {
                // Reseau coupe, 5xx, timeout... -> mode degrade cote composant.
                throw new AddressAutocompleteUnavailableError()
            }

            return (res.features ?? []).map((feature) => {
                const props = feature.properties ?? {}
                return {
                    city: props.city ?? props.name ?? '',
                    postalCode: props.postcode ?? '',
                }
            })
        },

        async searchAddress(query: string, postalCode?: string): Promise<AddressSuggestion[]> {
            // IMPORTANT : pas de `type=housenumber` ici. La BAN ne renvoie un
            // resultat de ce type qu'une fois un numero saisi → une recherche par
            // nom de rue (« boulevard du port ») renverrait 0 resultat pendant
            // toute la frappe. Sans filtre `type`, la BAN classe rues + numeros
            // par pertinence (comportement d'autocompletion attendu).
            // On n'ajoute `postcode` que s'il est fourni (sinon recherche large).
            const banQuery: Record<string, string> = { q: query }
            if (postalCode) {
                banQuery.postcode = postalCode
            }

            let res: BanResponse
            try {
                res = await httpExternal<BanResponse>(BAN_SEARCH_URL, { query: banQuery })
            } catch {
                throw new AddressAutocompleteUnavailableError()
            }

            return (res.features ?? []).map((feature) => {
                const props = feature.properties ?? {}
                return {
                    label: props.label ?? '',
                    // `name` porte la ligne d'adresse complete (numero + voie) ;
                    // `street` ne contient que la voie. On privilegie `name`.
                    street: props.name ?? props.street ?? '',
                    postalCode: props.postcode ?? '',
                    city: props.city ?? '',
                }
            })
        },
    }
}
