<?php
// ip_lookup.php
// Interfaz + endpoint simple para consultar ubicación de una IP usando ipapi.co
// Uso: abrir en navegador. Dejar el input vacío para usar la IP del cliente.
// Requiere: PHP + cURL

declare(strict_types=1);

// Si nos llaman como AJAX (fetch desde el front), devolvemos JSON con los datos
if (isset($_GET['ajax']) && $_GET['ajax'] == '1') {
    header('Content-Type: application/json; charset=utf-8');

    // Obtener IP enviada o usar la IP del cliente
    $ip = trim((string)($_GET['ip'] ?? ''));
    if ($ip === '') {
        // Si estás en local (127.0.0.1) y quieres probar, especifica una IP real manualmente
        $ip = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
    }

    // Validar IP (IPv4 / IPv6)
    if (!filter_var($ip, FILTER_VALIDATE_IP)) {
        http_response_code(422);
        echo json_encode(['success' => false, 'message' => 'IP inválida', 'ip' => $ip]);
        exit;
    }

    // Consumir ipapi.co
    $url = "https://ipapi.co/{$ip}/json/";

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 8,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_USERAGENT => 'SGO-IP-Lookup/1.0 (+https://tu-sitio.example)'
    ]);
    $resp = curl_exec($ch);
    $errno = curl_errno($ch);
    $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($errno || !$resp || $httpcode >= 400) {
        http_response_code(502);
        echo json_encode(['success' => false, 'message' => 'Error consultando servicio externo', 'http_code' => $httpcode, 'curl_errno' => $errno]);
        exit;
    }

    $data = json_decode($resp, true);
    if (!is_array($data)) {
        http_response_code(502);
        echo json_encode(['success' => false, 'message' => 'Respuesta externa inválida', 'raw' => $resp]);
        exit;
    }

    // Estructura mínima que devolvemos al front
    $out = [
        'success' => true,
        'ip'      => $ip,
        'city'    => $data['city'] ?? null,
        'region'  => $data['region'] ?? null,
        'country' => $data['country_name'] ?? ($data['country'] ?? null),
        'country_code' => $data['country_code'] ?? null,
        'postal'  => $data['postal'] ?? null,
        'latitude'=> isset($data['latitude']) ? (float)$data['latitude'] : (isset($data['latitude']) ? (float)$data['latitude'] : (float)($data['latitude'] ?? 0)),
        'longitude'=> isset($data['longitude']) ? (float)$data['longitude'] : (isset($data['longitude']) ? (float)$data['longitude'] : (float)($data['longitude'] ?? 0)),
        'org'     => $data['org'] ?? $data['org'] ?? null,
        'asn'     => $data['asn'] ?? null,
        'timezone'=> $data['timezone'] ?? null,
        'utc_offset' => $data['utc_offset'] ?? null,
        'raw'     => $data
    ];

    echo json_encode($out);
    exit;
}
?>
<!doctype html>
<html lang="es">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>Consulta IP · Ubicación</title>

  <!-- Bootstrap 5 desde CDN -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">

  <!-- Leaflet CSS -->
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />

  <style>
    /* estilo compacto y fuente más grande (preferencia que mencionaste) */
    body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial; font-size: 15px; }
    .container { max-width: 980px; margin-top: 18px; }
    label { font-weight: 600; }
    .card { margin-bottom: 10px; }
    #map { height: 360px; border-radius: 6px; }
    .small-muted { font-size: .92rem; color: #6c757d; }
    .k-v { font-weight:700; }
    .nowrap { white-space: nowrap; }
  </style>
</head>
<body>
  <div class="container">
    <h3 class="mb-2">Buscar ubicación por IP</h3>

    <div class="card p-3">
      <form id="ipForm" class="row g-2 align-items-center">
        <div class="col-auto" style="flex:1">
          <label for="ipInput" class="form-label mb-1">IP (dejar vacío para usar tu IP pública)</label>
          <input id="ipInput" class="form-control" type="text" placeholder="ej. 8.8.8.8">
        </div>

        <div class="col-auto mt-3">
          <button id="btnSearch" class="btn btn-primary mt-1">Buscar</button>
          <button id="btnClear" type="button" class="btn btn-outline-secondary mt-1">Limpiar</button>
        </div>
      </form>

      <div id="alertBox" class="mt-2"></div>
    </div>

    <div id="resultArea" style="display:none;">
      <div class="row">
        <div class="col-md-6">
          <div class="card p-3">
            <h6 class="mb-2">Detalles</h6>
            <div class="mb-1"><span class="small-muted">IP:</span> <span id="r_ip" class="k-v"></span></div>
            <div class="mb-1"><span class="small-muted">Organización / ISP:</span> <span id="r_org"></span></div>
            <div class="mb-1"><span class="small-muted">ASN:</span> <span id="r_asn"></span></div>
            <div class="mb-1"><span class="small-muted">Ciudad / Región:</span> <span id="r_city"></span></div>
            <div class="mb-1"><span class="small-muted">País:</span> <span id="r_country"></span> <span id="r_country_code" class="small-muted"></span></div>
            <div class="mb-1"><span class="small-muted">Código postal:</span> <span id="r_postal"></span></div>
            <div class="mb-1"><span class="small-muted">Zona horaria:</span> <span id="r_tz"></span></div>
            <div class="mb-1"><span class="small-muted">UTC offset:</span> <span id="r_utc"></span></div>
            <div class="mb-1"><span class="small-muted">Lat / Lon:</span> <span id="r_latlon" class="nowrap"></span></div>
            <hr>
            <div class="small-muted">Respuesta cruda del proveedor (ipapi.co):</div>
            <pre id="r_raw" style="max-height:160px; overflow:auto; background:#f8f9fa; padding:8px; border-radius:6px;"></pre>
          </div>
        </div>

        <div class="col-md-6">
          <div class="card p-3">
            <h6 class="mb-2">Mapa</h6>
            <div id="map">Cargando mapa...</div>
            <div class="mt-2 small-muted">Si la IP no tiene coordenadas (privada/localhost), el mapa mostrará la vista global.</div>
          </div>
        </div>
      </div>
    </div>

    <div class="text-center small-muted mt-2">Servicio utilizado: <strong>ipapi.co</strong> (consulta gratuita básica). Para producción considera usar una API con clave/plan.</div>
  </div>

  <!-- JS: Bootstrap y Leaflet -->
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
  <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>

  <script>
    const form = document.getElementById('ipForm');
    const ipInput = document.getElementById('ipInput');
    const alertBox = document.getElementById('alertBox');
    const resultArea = document.getElementById('resultArea');

    // Result elements
    const R = {
      ip: document.getElementById('r_ip'),
      org: document.getElementById('r_org'),
      asn: document.getElementById('r_asn'),
      city: document.getElementById('r_city'),
      country: document.getElementById('r_country'),
      country_code: document.getElementById('r_country_code'),
      postal: document.getElementById('r_postal'),
      tz: document.getElementById('r_tz'),
      utc: document.getElementById('r_utc'),
      latlon: document.getElementById('r_latlon'),
      raw: document.getElementById('r_raw')
    };

    // Mapa Leaflet inicial
    let map = L.map('map', { center: [0,0], zoom: 2, zoomControl: true });
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '&copy; OpenStreetMap contributors'
    }).addTo(map);
    let marker = null;

    function showAlert(html, type='warning') {
      alertBox.innerHTML = `<div class="alert alert-${type} py-2" role="alert">${html}</div>`;
    }

    function clearAlert() { alertBox.innerHTML = ''; }

    function clearResults() {
      resultArea.style.display = 'none';
      R.ip.textContent = ''; R.org.textContent = ''; R.asn.textContent = '';
      R.city.textContent = ''; R.country.textContent = ''; R.country_code.textContent = '';
      R.postal.textContent = ''; R.tz.textContent = ''; R.utc.textContent = ''; R.latlon.textContent = '';
      R.raw.textContent = '';
      if (marker) { map.removeLayer(marker); marker = null; }
      map.setView([0,0], 2);
    }

    document.getElementById('btnClear').addEventListener('click', (e) => {
      ipInput.value = '';
      clearAlert();
      clearResults();
    });

    form.addEventListener('submit', async (e) => {
      e.preventDefault();
      clearAlert();

      const ip = ipInput.value.trim();

      // validación simple en cliente (opcional)
      if (ip !== '' && !/^[0-9a-fA-F:\.\s]+$/.test(ip)) {
        showAlert('Formato de IP parece inválido (solo dígitos y puntos/2-puntos permitidos).', 'danger');
        return;
      }

      showAlert('Consultando ubicación...', 'info');

      try {
        const q = new URLSearchParams({ ajax: '1', ip: ip });
        const resp = await fetch(window.location.pathname + '?' + q.toString(), { method: 'GET', headers: { 'Accept': 'application/json' }});
        if (!resp.ok) {
          const txt = await resp.text();
          showAlert('Error del servidor: ' + resp.status + ' — ' + (txt || resp.statusText), 'danger');
          return;
        }
        const data = await resp.json();
        if (!data.success) {
          showAlert('No se obtuvo información: ' + (data.message ?? 'sin mensaje'), 'danger');
          return;
        }

        clearAlert();
        resultArea.style.display = 'block';
        R.ip.textContent = data.ip ?? '';
        R.org.textContent = data.org ?? (data.raw.org ?? '') ;
        R.asn.textContent = data.asn ?? (data.raw.asn ?? '');
        R.city.textContent = [data.city, data.region].filter(Boolean).join(' / ');
        R.country.textContent = data.country ?? '';
        R.country_code.textContent = data.country_code ? '(' + data.country_code + ')' : '';
        R.postal.textContent = data.postal ?? '';
        R.tz.textContent = data.timezone ?? '';
        R.utc.textContent = data.utc_offset ?? '';
        R.latlon.textContent = (data.latitude && data.longitude) ? (data.latitude + ', ' + data.longitude) : 'Sin coordenadas';
        R.raw.textContent = JSON.stringify(data.raw ?? data, null, 2);

        // Map: si hay coordenadas, centrar y poner marker
        if (data.latitude && data.longitude && Number(data.latitude) !== 0 && Number(data.longitude) !== 0) {
          const lat = Number(data.latitude);
          const lon = Number(data.longitude);
          map.setView([lat, lon], 10);
          if (marker) map.removeLayer(marker);
          marker = L.marker([lat, lon]).addTo(map).bindPopup(`<b>${data.ip}</b><br>${(data.city||'')}${data.city?', ':''}${data.region||''}<br>${data.country||''}`).openPopup();
        } else {
          // sin coords: vista global
          if (marker) { map.removeLayer(marker); marker = null; }
          map.setView([0,0], 2);
        }

      } catch (err) {
        showAlert('Error inesperado: ' + (err.message ?? err), 'danger');
      }
    });

    // Auto-run: si la página se abre sin interacción, cargar la IP del cliente
    // Comentado por defecto. Descomenta si quieres que cargue al abrir:
    // window.addEventListener('load', () => { document.getElementById('btnSearch').click(); });
  </script>
</body>
</html>
