// shared.jsx — wspólne komponenty: ikony, header, stopka, pola formularzy, helpery
const { useState, useEffect, useRef, useCallback } = React;

/* ── Ikony (inline SVG, stroke 1.8) ─────────────────────── */
const Ic = {
  Roof: (p) => (
    <svg width={p.size || 34} height={p.size || 34} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M3 11.5 12 4l9 7.5"></path><path d="M5.5 9.6V20h13V9.6"></path>
      <rect x="8.2" y="12" width="7.6" height="4.6" rx="0.6"></rect>
      <path d="M12 12v4.6M8.2 14.3h7.6"></path>
    </svg>
  ),
  Ground: (p) => (
    <svg width={p.size || 34} height={p.size || 34} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M3 20h18"></path><path d="M6.5 9.5 17 6l1.6 4.8-10.5 3.5z"></path>
      <path d="M9.5 14.5V20M14.5 13V20"></path><path d="M11.2 8.1l1.1 3.3M14.4 7l1.1 3.3"></path>
    </svg>
  ),
  Panel: (p) => (
    <svg width={p.size || 22} height={p.size || 22} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <rect x="3" y="4" width="18" height="12" rx="1.5"></rect>
      <path d="M3 10h18M9 4v12M15 4v12M8 20h8M12 16v4"></path>
    </svg>
  ),
  Battery: (p) => (
    <svg width={p.size || 22} height={p.size || 22} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <rect x="5" y="6" width="14" height="14" rx="2"></rect><path d="M9 6V3h6v3"></path>
      <path d="M12 9.5 10 13h4l-2 3.5"></path>
    </svg>
  ),
  Bolt: (p) => (
    <svg width={p.size || 18} height={p.size || 18} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
      <path d="M13 2 4.5 13.5h5L10 22l8.5-11.5h-5L13 2z"></path>
    </svg>
  ),
  Leaf: (p) => (
    <svg width={p.size || 22} height={p.size || 22} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10z"></path>
      <path d="M2 21c0-3 1.85-5.36 5.08-6"></path>
    </svg>
  ),
  Sun: (p) => (
    <svg width={p.size || 22} height={p.size || 22} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <circle cx="12" cy="12" r="4"></circle>
      <path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"></path>
    </svg>
  ),
  Recycle: (p) => (
    <svg width={p.size || 22} height={p.size || 22} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M7 19H4.8a2 2 0 0 1-1.7-3l1.3-2.2M9.5 4.5 11 2l1.5 2.5"></path>
      <path d="M14 8.5 12 5l-2 3.5M19.2 14l1.3 2.2a2 2 0 0 1-1.7 3H16M5.5 11 4 8.5"></path>
      <path d="m9 19 2.5 2.5L14 19"></path>
    </svg>
  ),
  Check: (p) => (
    <svg width={p.size || 14} height={p.size || 14} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M4.5 12.5 10 18 19.5 7"></path>
    </svg>
  ),
  Star: (p) => (
    <svg width={p.size || 12} height={p.size || 12} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
      <path d="M12 2.5l2.9 6 6.6.9-4.8 4.6 1.2 6.5L12 17.4l-5.9 3.1 1.2-6.5L2.5 9.4l6.6-.9z"></path>
    </svg>
  ),
  Phone: (p) => (
    <svg width={p.size || 20} height={p.size || 20} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M5 4h4l2 5-2.5 1.5a12 12 0 0 0 5 5L15 13l5 2v4a2 2 0 0 1-2 2A16 16 0 0 1 3 6a2 2 0 0 1 2-2z"></path>
    </svg>
  ),
  Mail: (p) => (
    <svg width={p.size || 20} height={p.size || 20} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <rect x="3" y="5" width="18" height="14" rx="2"></rect><path d="m3 7 9 6 9-6"></path>
    </svg>
  ),
  Clock: (p) => (
    <svg width={p.size || 20} height={p.size || 20} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <circle cx="12" cy="12" r="9"></circle><path d="M12 7v5l3.5 2"></path>
    </svg>
  ),
  ArrowR: (p) => (
    <svg width={p.size || 18} height={p.size || 18} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M4 12h16m-6-6 6 6-6 6"></path>
    </svg>
  ),
  ArrowDown: (p) => (
    <svg width={p.size || 22} height={p.size || 22} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M12 4v16m-6-6 6 6 6-6"></path>
    </svg>
  ),
  Spinner: (p) => (
    <svg className="spin" width={p.size || 18} height={p.size || 18} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" aria-hidden="true">
      <path d="M12 3a9 9 0 1 0 9 9"></path>
    </svg>
  ),
};

/* ── Helpery ────────────────────────────────────────────── */
const fmtPLN = (n) => new Intl.NumberFormat("pl-PL", { maximumFractionDigits: 0 }).format(Math.round(n)) + " zł";
const fmtNum = (n, d = 1) => new Intl.NumberFormat("pl-PL", { minimumFractionDigits: d, maximumFractionDigits: d }).format(n);

const WOJEWODZTWA = [
  "dolnośląskie", "kujawsko-pomorskie", "lubelskie", "lubuskie", "łódzkie", "małopolskie",
  "mazowieckie", "opolskie", "podkarpackie", "podlaskie", "pomorskie", "śląskie",
  "świętokrzyskie", "warmińsko-mazurskie", "wielkopolskie", "zachodniopomorskie",
];

/* Płynny licznik (count-up) przy zmianie wartości */
function CountUp({ value, format, duration = 450 }) {
  const [disp, setDisp] = useState(value);
  const fromRef = useRef(value);
  const rafRef = useRef(null);
  useEffect(() => {
    const from = fromRef.current;
    if (from === value) return;
    const t0 = performance.now();
    const tick = (t) => {
      const p = Math.min(1, (t - t0) / duration);
      const e = 1 - Math.pow(1 - p, 3);
      setDisp(from + (value - from) * e);
      if (p < 1) rafRef.current = requestAnimationFrame(tick);
      else fromRef.current = value;
    };
    cancelAnimationFrame(rafRef.current);
    rafRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(rafRef.current);
  }, [value, duration]);
  return <span>{format ? format(disp) : Math.round(disp)}</span>;
}

/* Miękkie pojawianie się przy scrollu */
function Reveal({ children, as = "div", className = "", ...rest }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(
      (entries) => entries.forEach((e) => e.isIntersecting && (e.target.classList.add("in"), io.unobserve(e.target))),
      { threshold: 0.12 }
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);
  const Tag = as;
  return <Tag ref={ref} className={`reveal ${className}`} {...rest}>{children}</Tag>;
}

/* Tooltip "i" */
function InfoTip({ text }) {
  return (
    <span className="tooltip-wrap">
      <button type="button" className="info-dot" aria-label={`Wyjaśnienie: ${text}`}>i</button>
      <span className="tooltip-bubble" role="tooltip">{text}</span>
    </span>
  );
}

/* Kreska ozdobna — subtelny przerywnik (tylko na jasnych tłach, żeby był dobrze widoczny) */
function Rule({ w = 260, className = "", style }) {
  return (
    <div className={`rule ${className}`} aria-hidden="true" style={{ width: w, maxWidth: "86%", ...style }}>
      <span className="rule-tip"></span>
      <span className="rule-bar"></span>
      <span className="rule-tip"></span>
    </div>
  );
}

/* Pole formularza z walidacją na żywo */
function Field({ label, type = "text", value, onChange, error, touched, onBlur, placeholder, options, autoComplete, name }) {
  const invalid = touched && error;
  const id = `f-${name}`;
  return (
    <div className={`field ${invalid ? "invalid" : ""}`}>
      <label htmlFor={id}>{label}</label>
      {options ? (
        <select id={id} name={name} value={value} onChange={(e) => onChange(e.target.value)} onBlur={onBlur} aria-invalid={!!invalid}>
          <option value="">— wybierz —</option>
          {options.map((o) => <option key={o} value={o}>{o}</option>)}
        </select>
      ) : (
        <input id={id} name={name} type={type} value={value} placeholder={placeholder} autoComplete={autoComplete}
          onChange={(e) => onChange(e.target.value)} onBlur={onBlur} aria-invalid={!!invalid} />
      )}
      <span className="field-error" role="alert">{invalid ? error : ""}</span>
    </div>
  );
}

/* Walidatory */
const validators = {
  name: (v) => (v.trim().length < 3 ? "Podaj imię i nazwisko" : ""),
  email: (v) => (/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(v.trim()) ? "" : "Podaj poprawny adres e-mail"),
  phone: (v) => (/^[\d\s+-]{9,15}$/.test(v.trim()) && v.replace(/\D/g, "").length >= 9 ? "" : "Podaj poprawny numer telefonu (9 cyfr)"),
  woj: (v) => (v ? "" : "Wybierz województwo"),
  rodo: (v) => (v ? "" : "Zgoda jest wymagana"),
};

/* ── Lightbox (powiększenie zdjęcia ze slotu) ───────────── */
function Lightbox({ src, srcWebp, caption, onClose }) {
  useEffect(() => {
    const onKey = (e) => e.key === "Escape" && onClose();
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => { window.removeEventListener("keydown", onKey); document.body.style.overflow = ""; };
  }, [onClose]);
  return (
    <div className="lightbox" onClick={onClose} role="dialog" aria-modal="true" aria-label={caption || "Powiększenie zdjęcia"}>
      <button className="lightbox-close" onClick={onClose} aria-label="Zamknij">✕</button>
      <div className="lightbox-inner" onClick={(e) => e.stopPropagation()}>
        <div className="lightbox-card">
          <picture>
            <source srcSet={srcWebp} type="image/webp" />
            <img src={src} alt={caption || "Powiększone zdjęcie realizacji"}
                 style={{ width: "100%", maxHeight: "min(74vh, 660px)", objectFit: "contain", display: "block", borderRadius: "12px" }} />
          </picture>
          {caption ? <p style={{ textAlign: "center", fontWeight: 700, margin: "12px 0 2px" }}>{caption}</p> : null}
        </div>
      </div>
    </div>
  );
}

/* ── Header ─────────────────────────────────────────────── */
const NAV = [
  { id: "start", label: "Strona główna" },
  { id: "kalkulator", label: "Kalkulator" },
  { id: "realizacje", label: "Realizacje" },
  { id: "kontakt", label: "Kontakt" },
];
const NAV_LEFT = NAV.slice(0, 2);
const NAV_RIGHT = NAV.slice(2);

function Header({ route, go }) {
  const [open, setOpen] = useState(false);
  const nav = (id) => { setOpen(false); go(id); };
  const link = (n) => (
    <a key={n.id} href={n.id === "start" ? "/" : `/${n.id}`} className={`nav-pill ${route === n.id ? "active" : ""}`}
       aria-current={route === n.id ? "page" : undefined}
       onClick={(e) => { e.preventDefault(); nav(n.id); }}>{n.label}</a>
  );
  return (
    <header className="site-header">
      <div className="container site-header-inner">
        <nav className="nav-group nav-left" aria-label="Nawigacja główna">
          {NAV_LEFT.map(link)}
        </nav>
        <a href="/" className="brand brand-center" onClick={(e) => { e.preventDefault(); nav("start"); }} aria-label="Twój Kalkulator OZE — strona główna">
          <img src="assets/logo.png" alt="Twój Kalkulator OZE" />
        </a>
        <nav className="nav-group nav-right" aria-label="Realizacje i kontakt">
          {NAV_RIGHT.map(link)}
        </nav>
        <button className="hamburger" aria-label={open ? "Zamknij menu" : "Otwórz menu"} aria-expanded={open} onClick={() => setOpen(!open)}>
          <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round">
            {open ? <path d="M5 5l14 14M19 5 5 19"></path> : <path d="M4 7h16M4 12h16M4 17h16"></path>}
          </svg>
        </button>
      </div>
      {open ? (
        <div className="mobile-menu">
          {NAV.map((n) => (
            <a key={n.id} href={n.id === "start" ? "/" : `/${n.id}`} className={`nav-pill ${route === n.id ? "active" : ""}`}
               onClick={(e) => { e.preventDefault(); nav(n.id); }}>{n.label}</a>
          ))}
        </div>
      ) : null}
    </header>
  );
}

/* ── Stopka ─────────────────────────────────────────────── */
function Footer({ go }) {
  return (
    <footer className="site-footer">
      <div className="container">
        <div className="footer-grid">
          <div className="footer-brand">
            <span className="logo-chip"><img src="assets/logo.png" alt="Logo Twój Kalkulator OZE" /></span>
            <div>
              <strong className="footer-name">Twój Kalkulator OZE</strong>
              <p className="footer-sub" style={{ marginTop: 6 }}>Fotowoltaika i magazyny energii — wprost od instalatora.</p>
            </div>
          </div>
          <div className="footer-col">
            <h4 className="footer-col-title">Kontakt</h4>
            <div className="footer-line"><Ic.Phone /> <a href="tel:798040369" style={{ color: "inherit", textDecoration: "none" }}>798-040-369</a></div>
            <div className="footer-line"><Ic.Clock /> pn–pt 10:00–16:00</div>
            <div className="footer-line"><Ic.Mail /> <a href="mailto:kontakt@twojkalkulatoroze.com" style={{ color: "inherit", textDecoration: "none" }}>kontakt@twojkalkulatoroze.com</a></div>
          </div>
          <div className="footer-col">
            <h4 className="footer-col-title">Masz pytania?</h4>
            <p className="footer-sub" style={{ margin: "0 0 14px" }}>
              Skontaktuj się z nami telefonicznie lub przez formularz kontaktowy.
            </p>
            <button className="btn btn-amber" onClick={() => go("kontakt")}>
              Formularz kontaktowy <Ic.ArrowR />
            </button>
          </div>
        </div>
        <div className="footer-exec">
          <span className="exec-logo">
            <picture>
              <source srcSet="assets/pure-eco-energy.webp" type="image/webp" />
              <img src="assets/pure-eco-energy.png" alt="Pure Eco Energy" />
            </picture>
          </span>
          <div>
            <strong>Wykonawcą instalacji jest Pure Eco Energy</strong>
            <p>Doświadczony instalator fotowoltaiki i magazynów energii — projekt, montaż i serwis realizujemy własną ekipą.</p>
          </div>
        </div>
        <div className="footer-bottom">
          <span>© 2026 Twój Kalkulator OZE. Wszystkie prawa zastrzeżone.
            {" · "}Strona wykonana przez <a href="https://watahamedia.com/" target="_blank" rel="noopener noreferrer" style={{ color: "inherit", textDecoration: "none", fontWeight: 700 }}>Wataha Media</a>
          </span>
          <span>
            <a href="/wiedza" style={{ color: "inherit", textDecoration: "none", fontWeight: 700 }}>Wiedza</a>
            {" · "}
            <a href="/polityka-prywatnosci" style={{ color: "inherit", textDecoration: "none" }}>Polityka prywatności</a>
            {" · "}
            <a href="#" data-cookie-settings style={{ color: "inherit", textDecoration: "none" }}>Ustawienia cookies</a>
          </span>
        </div>
      </div>
    </footer>
  );
}

Object.assign(window, { Ic, fmtPLN, fmtNum, WOJEWODZTWA, CountUp, Reveal, InfoTip, Rule, Field, validators, Lightbox, Header, Footer });
