/* global React */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ---------- icons ----------
const Icon = {
  globe: (p) => (
    <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <circle cx="12" cy="12" r="9"/>
      <path d="M3 12h18M12 3c2.5 3 2.5 15 0 18M12 3c-2.5 3-2.5 15 0 18"/>
    </svg>
  ),
  copy: (p) => (
    <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <rect x="9" y="9" width="11" height="11" rx="2"/>
      <path d="M5 15V5a2 2 0 0 1 2-2h10"/>
    </svg>
  ),
  check: (p) => (
    <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M4 12.5L10 18 20 6"/>
    </svg>
  ),
  sun: (p) => (
    <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <circle cx="12" cy="12" r="4"/>
      <path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4l1.4-1.4M17 7l1.4-1.4"/>
    </svg>
  ),
  moon: (p) => (
    <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M20 14.5A8 8 0 1 1 9.5 4 6.5 6.5 0 0 0 20 14.5Z"/>
    </svg>
  ),
  menu: (p) => (
    <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" {...p}>
      <path d="M4 7h16M4 12h16M4 17h16"/>
    </svg>
  ),
  arrow: (p) => (
    <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M5 12h14M13 6l6 6-6 6"/>
    </svg>
  ),
  chev: (p) => (
    <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M6 9l6 6 6-6"/>
    </svg>
  ),
  shield: (p) => (
    <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M12 3l8 3v6c0 4.5-3.4 8.5-8 9.5C7.4 20.5 4 16.5 4 12V6l8-3z"/>
    </svg>
  ),
  search: (p) => (
    <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <circle cx="11" cy="11" r="7"/>
      <path d="M16.5 16.5L21 21"/>
    </svg>
  ),
  pin: (p) => (
    <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M12 22s7-6.5 7-12a7 7 0 1 0-14 0c0 5.5 7 12 7 12z"/>
      <circle cx="12" cy="10" r="2.5"/>
    </svg>
  ),
  zap: (p) => (
    <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M13 2L4 14h7l-1 8 9-12h-7l1-8z"/>
    </svg>
  ),
  ping: (p) => (
    <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <circle cx="12" cy="12" r="2"/>
      <path d="M7 7a7 7 0 0 1 10 0M5 5a10 10 0 0 1 14 0M9 9a4 4 0 0 1 6 0"/>
    </svg>
  ),
  dns: (p) => (
    <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <rect x="3" y="4" width="18" height="6" rx="1.5"/>
      <rect x="3" y="14" width="18" height="6" rx="1.5"/>
      <circle cx="7" cy="7" r="0.8" fill="currentColor"/>
      <circle cx="7" cy="17" r="0.8" fill="currentColor"/>
    </svg>
  ),
  whois: (p) => (
    <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M4 6h16M4 6v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6"/>
      <path d="M9 11h6M9 14h4"/>
    </svg>
  ),
  reverse: (p) => (
    <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M21 12a9 9 0 1 1-3-6.7L21 8"/>
      <path d="M21 3v5h-5"/>
    </svg>
  ),
  speed: (p) => (
    <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M4 18a8 8 0 1 1 16 0"/>
      <path d="M12 18l4-5"/>
      <circle cx="12" cy="18" r="1.4" fill="currentColor"/>
    </svg>
  ),
  trash: (p) => (
    <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M4 7h16M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2M6 7l1 13a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2l1-13"/>
    </svg>
  ),
  close: (p) => (
    <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" {...p}>
      <path d="M18 6L6 18M6 6l12 12"/>
    </svg>
  ),
  clock: (p) => (
    <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" {...p}>
      <circle cx="12" cy="12" r="9"/>
      <path d="M12 7v5l3 3"/>
    </svg>
  ),
  ban: (p) => (
    <svg viewBox="0 0 24 24" width="40" height="40" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" {...p}>
      <circle cx="12" cy="12" r="9"/>
      <path d="M5.6 5.6l12.8 12.8"/>
    </svg>
  ),
};

// ---------- mock data (fallback only) ----------
const MOCK_IP = {
  ipv4: "187.32.144.218",
  ipv6: "2804:14d:5cb1:8e2c:1f3a:9d4e:b701:42c8",
  city: "São Paulo", region: "São Paulo", country: "Brasil",
  countryCode: "BR", postal: "01310-100",
  timezone: "America/Sao_Paulo (UTC−03:00)",
  isp: "Vivo S.A. (Telefônica Brasil)", asn: "AS27699",
  hostname: "187-32-144-218.user.vivozap.com.br",
  proxy: false, vpn: false, lat: -23.5505, lon: -46.6333,
};

// ---------- real IP fetch from backend ----------
async function fetchMyIP() {
  const res = await fetch('/api/myip');
  if (res.status === 429) {
    const retryAfter = res.headers.get('Retry-After');
    const secs = retryAfter ? parseInt(retryAfter, 10) : 43200;
    const err = new Error('rate_limited');
    err.code = 'rate_limited';
    err.retryAfter = secs;
    err.retryTs = Date.now() + secs * 1000;
    throw err;
  }
  if (!res.ok) throw new Error('fetch_failed');
  return res.json();
}

// ---------- client-side rate-limit guard (localStorage) ----------
const RL_KEY = 'vermeip:rl';

function readLocalRL() {
  try { return JSON.parse(localStorage.getItem(RL_KEY) || 'null'); } catch { return null; }
}
function markLocalRateLimited(retryTs) {
  try { localStorage.setItem(RL_KEY, JSON.stringify({ retryTs })); } catch {}
}
function checkLocalRateLimit() {
  const rl = readLocalRL();
  if (!rl) return { allowed: true };
  if (rl.retryTs && Date.now() < rl.retryTs) return { allowed: false, retryTs: rl.retryTs };
  return { allowed: true };
}

// ---------- helpers ----------
function copyText(text) {
  if (navigator.clipboard?.writeText) return navigator.clipboard.writeText(text);
  const ta = document.createElement('textarea');
  ta.value = text; document.body.appendChild(ta);
  ta.select(); document.execCommand('copy'); document.body.removeChild(ta);
  return Promise.resolve();
}

function CopyBtn({ value, label = 'Copiar' }) {
  const [copied, setCopied] = useState(false);
  return (
    <button
      className={'copy-btn' + (copied ? ' copied' : '')}
      title={label} aria-label={label}
      onClick={(e) => { e.stopPropagation(); copyText(value).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1200); }); }}
    >
      {copied ? <Icon.check/> : <Icon.copy/>}
    </button>
  );
}

// hash route
function useHashRoute() {
  const [hash, setHash] = useState(() => (window.location.hash.slice(1) || '/'));
  useEffect(() => {
    const onHash = () => setHash(window.location.hash.slice(1) || '/');
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);
  return [hash, (h) => { window.location.hash = h; }];
}

// localStorage history
const HIST_KEY = 'vermeip:history';
function pushHistory(entry) {
  try {
    const arr = JSON.parse(localStorage.getItem(HIST_KEY) || '[]');
    const next = [{ ...entry, t: Date.now() }, ...arr.filter(x => !(x.kind === entry.kind && x.q === entry.q))].slice(0, 12);
    localStorage.setItem(HIST_KEY, JSON.stringify(next));
    window.dispatchEvent(new CustomEvent('vermeip:history-update'));
  } catch {}
}
function useHistory() {
  const [items, setItems] = useState(() => {
    try { return JSON.parse(localStorage.getItem(HIST_KEY) || '[]'); } catch { return []; }
  });
  useEffect(() => {
    const f = () => { try { setItems(JSON.parse(localStorage.getItem(HIST_KEY) || '[]')); } catch {} };
    window.addEventListener('vermeip:history-update', f);
    window.addEventListener('storage', f);
    return () => { window.removeEventListener('vermeip:history-update', f); window.removeEventListener('storage', f); };
  }, []);
  const clear = () => { localStorage.removeItem(HIST_KEY); window.dispatchEvent(new CustomEvent('vermeip:history-update')); };
  return [items, clear];
}

function timeAgo(t) {
  const s = Math.max(1, Math.floor((Date.now() - t) / 1000));
  if (s < 60) return `há ${s}s`;
  if (s < 3600) return `há ${Math.floor(s/60)}min`;
  if (s < 86400) return `há ${Math.floor(s/3600)}h`;
  return `há ${Math.floor(s/86400)}d`;
}

// countdown formatter HH:MM:SS
function fmtCountdown(ms) {
  const total = Math.max(0, Math.floor(ms / 1000));
  const h = Math.floor(total / 3600);
  const m = Math.floor((total % 3600) / 60);
  const s = total % 60;
  return [h, m, s].map(n => String(n).padStart(2, '0')).join(':');
}

Object.assign(window, {
  React, useState, useEffect, useRef, useMemo, useCallback,
  Icon, MOCK_IP,
  fetchMyIP, checkLocalRateLimit, markLocalRateLimited,
  copyText, CopyBtn,
  useHashRoute, pushHistory, useHistory, timeAgo, fmtCountdown,
});
