import { useState, useCallback } from 'react'

export interface CepData {
    cep: string
    logradouro: string
    bairro: string
    localidade: string   // cidade
    uf: string           // estado (2 letras)
    latitude: number
    longitude: number
}

interface UseCepLookupResult {
    loading: boolean
    error: string | null
    lookup: (cep: string) => Promise<CepData | null>
}

const NOMINATIM_BASE = 'https://nominatim.openstreetmap.org/search'
const HEADERS = { 'Accept-Language': 'pt-BR', 'User-Agent': 'SaveInMed/1.0 (contact@saveinmed.com.br)' }

async function nominatim(params: Record<string, string>): Promise<{ lat: string; lon: string } | null> {
    const qs = new URLSearchParams({ ...params, format: 'json', limit: '1', countrycodes: 'br' }).toString()
    const res = await fetch(`${NOMINATIM_BASE}?${qs}`, { headers: HEADERS })
    if (!res.ok) return null
    const data = await res.json()
    return data.length > 0 ? { lat: data[0].lat, lon: data[0].lon } : null
}

/**
 * Hook que consulta CEP via ViaCEP e geocodifica via Nominatim (OpenStreetMap).
 *
 * Estratégia em cascata (do mais preciso ao mais amplo):
 *  1. Busca pelo código postal (CEP) diretamente
 *  2. Busca por logradouro + bairro + cidade
 *  3. Fallback: busca apenas por cidade + estado
 */
export function useCepLookup(): UseCepLookupResult {
    const [loading, setLoading] = useState(false)
    const [error, setError] = useState<string | null>(null)

    const lookup = useCallback(async (cep: string): Promise<CepData | null> => {
        const cleanCep = cep.replace(/\D/g, '')
        if (cleanCep.length !== 8) {
            setError('CEP deve ter 8 dígitos')
            return null
        }

        setLoading(true)
        setError(null)

        try {
            // 1. ViaCEP: pegar dados do endereço
            const viaCepRes = await fetch(`https://viacep.com.br/ws/${cleanCep}/json/`)
            if (!viaCepRes.ok) throw new Error('Erro ao consultar ViaCEP')
            const addr = await viaCepRes.json()
            if (addr.erro) {
                setError('CEP não encontrado')
                return null
            }

            const { logradouro, bairro, localidade, uf } = addr
            let coords: { lat: string; lon: string } | null = null

            // Cascata de geocoding — tenta do mais específico ao mais genérico

            // Tentativa 1: CEP diretamente como postalcode
            coords = await nominatim({ postalcode: cleanCep })

            // Tentativa 2: logradouro + bairro + cidade (se o CEP não foi reconhecido)
            if (!coords && logradouro) {
                coords = await nominatim({ q: `${logradouro}, ${bairro}, ${localidade}, ${uf}` })
            }

            // Tentativa 3: bairro + cidade
            if (!coords && bairro) {
                coords = await nominatim({ q: `${bairro}, ${localidade}, ${uf}` })
            }

            // Tentativa 4: apenas cidade + estado (sempre funciona)
            if (!coords) {
                coords = await nominatim({ q: `${localidade}, ${uf}` })
            }

            if (!coords) {
                setError('Endereço encontrado, mas não foi possível obter coordenadas. Preencha lat/lng manualmente.')
                // Retorna sem coordenadas mas com cidade/estado
                return { cep: cleanCep, logradouro, bairro, localidade, uf, latitude: 0, longitude: 0 }
            }

            return {
                cep: cleanCep,
                logradouro,
                bairro,
                localidade,
                uf,
                latitude: parseFloat(coords.lat),
                longitude: parseFloat(coords.lon),
            }
        } catch (err) {
            const msg = err instanceof Error ? err.message : 'Erro ao buscar CEP'
            setError(msg)
            return null
        } finally {
            setLoading(false)
        }
    }, [])

    return { loading, error, lookup }
}
