#!/usr/bin/env bash
# geolocate_ip
# ------------
# Geolocaliza una IP o dominio usando la API pública de ip-api.com.
# Muestra país, ciudad, ISP, ASN y detecta VPN/Proxy/Hosting.
#
# USO (directo):
#   geolocate_ip <ip_o_dominio>
#
# Depende de: curl, dig (para resolver dominios)

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../shell/bash_colors.sh"
source "$SCRIPT_DIR/../shell/bash_log.sh"
bash_colors
bash_log_init

# ─── Constantes ───────────────────────────────────────────────────────────────

_GEOIP_API="http://ip-api.com/json"
_GEOIP_FIELDS="status,message,country,countryCode,regionName,city,zip,lat,lon,isp,org,as,proxy,hosting,query"

# ─── Funciones puras ──────────────────────────────────────────────────────────

_geo_is_ip() {
    [[ "$1" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
}

_geo_build_api_url() {
    local target="$1"
    echo "${_GEOIP_API}/${target}?fields=${_GEOIP_FIELDS}"
}

_geo_extract_field() {
    local json="$1"
    local key="$2"
    echo "$json" | grep -o "\"${key}\":[^,}]*" | cut -d: -f2- | tr -d '"' | xargs
}

# ─── Funciones de efecto ──────────────────────────────────────────────────────

_geo_resolve_domain() {
    local domain="$1"
    dig +short A "$domain" 2>/dev/null | head -1 || true
}

_geo_fetch() {
    local target="$1"
    local url
    url="$(_geo_build_api_url "$target")"
    curl -s --max-time 10 "$url" 2>/dev/null
}

_geo_display_result() {
    local json="$1"

    local status
    status="$(_geo_extract_field "$json" "status")"
    if [[ "$status" != "success" ]]; then
        local msg
        msg="$(_geo_extract_field "$json" "message")"
        error "La API devolvió error: ${msg:-respuesta inesperada}" >&2
        return 1
    fi

    local ip_queried country country_code region city zip lat lon isp org asn proxy hosting
    ip_queried="$(_geo_extract_field "$json" "query")"
    country="$(_geo_extract_field "$json" "country")"
    country_code="$(_geo_extract_field "$json" "countryCode")"
    region="$(_geo_extract_field "$json" "regionName")"
    city="$(_geo_extract_field "$json" "city")"
    zip="$(_geo_extract_field "$json" "zip")"
    lat="$(_geo_extract_field "$json" "lat")"
    lon="$(_geo_extract_field "$json" "lon")"
    isp="$(_geo_extract_field "$json" "isp")"
    org="$(_geo_extract_field "$json" "org")"
    asn="$(_geo_extract_field "$json" "as")"
    proxy="$(_geo_extract_field "$json" "proxy")"
    hosting="$(_geo_extract_field "$json" "hosting")"

    echo ""
    echo -e "${PURPLE}════════════════════════════════════════════════════════════${NC}"
    echo -e "  ${CYAN}IP consultada:${NC}  ${ip_queried}"
    echo -e "  ${CYAN}País:${NC}           ${country} (${country_code})"
    echo -e "  ${CYAN}Región:${NC}         ${region}"
    echo -e "  ${CYAN}Ciudad:${NC}         ${city} ${zip}"
    echo -e "  ${CYAN}Coordenadas:${NC}    ${lat}, ${lon}"
    echo -e "  ${CYAN}ISP:${NC}            ${isp}"
    echo -e "  ${CYAN}Organización:${NC}   ${org}"
    echo -e "  ${CYAN}ASN:${NC}            ${asn}"
    echo ""

    if [[ "$proxy" == "true" ]]; then
        echo -e "  ${RED}[!] VPN / Proxy detectado${NC}"
    fi
    if [[ "$hosting" == "true" ]]; then
        echo -e "  ${YELLOW}[i] Hosting / datacenter detectado${NC}"
    fi
    if [[ "$proxy" != "true" && "$hosting" != "true" ]]; then
        echo -e "  ${GREEN}[ok] Sin indicios de VPN, Proxy o Tor${NC}"
    fi

    echo -e "${PURPLE}════════════════════════════════════════════════════════════${NC}"
}

# ─── Punto de entrada ─────────────────────────────────────────────────────────

geolocate_ip() {
    local target="$1"

    if [[ -z "$target" ]]; then
        error "geolocate_ip: se requiere una IP o dominio como argumento" >&2
        return 1
    fi

    if ! command -v curl &>/dev/null; then
        error "geolocate_ip: 'curl' no está instalado (sudo apt install curl)" >&2
        return 1
    fi

    local query_target="$target"

    if ! _geo_is_ip "$target"; then
        info "Resolviendo dominio a IP..."
        local resolved
        resolved="$(_geo_resolve_domain "$target")"
        if [[ -z "$resolved" ]]; then
            error "geolocate_ip: no se pudo resolver '$target'" >&2
            return 1
        fi
        info "Resuelto: ${target} -> ${resolved}"
        query_target="$resolved"
    fi

    info "Consultando geolocalización de ${query_target}..."
    local json
    json="$(_geo_fetch "$query_target")"

    if [[ -z "$json" ]]; then
        error "geolocate_ip: no se obtuvo respuesta de la API" >&2
        return 1
    fi

    _geo_display_result "$json"
}

# Ejecutar si se llama directamente
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    geolocate_ip "$@"
fi
