/* global React, ReactDOM, Henrieta, HexFrame, CardSigil */

const { useState, useMemo, useEffect, useRef } = React;
const { lifePathNumber } = window.numerology;
const HENRIETA_PROFILES = window.numerology.PROFILES;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "noc",
  "showMath": true,
  "showStars": true,
  "tone": "henrieta",
  "buzz": true
}/*EDITMODE-END*/;

const MONTHS_PL = [
  "Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec",
  "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień",
];

const CASTING_LINES = [
  "Henrieta liczy plastry…",
  "Konsultuje się z Wielką Maciorą Pasieki…",
  "Sprawdza wibracje rumianku…",
  "Trzepie skrzydłami w stronę kosmosu…",
  "Otwiera słoik z 1987 roku…",
  "Pyta królową, ale królowa drzemie…",
];

const SCEPTYK_OVERRIDE = {
  nature:
    "Numerologia nie ma żadnego oparcia w empirii. Cyfry w twojej dacie urodzenia to po prostu cyfry. Henrieta jednak uznaje, że jesteś osobą z tendencją do refleksji, bo czytasz to z własnej woli.",
  week:
    "W tym tygodniu wydarzą się rzeczy zgodne z prawdopodobieństwem warunkowym. Trochę przyjemnych, trochę nudnych, jedna lekko irytująca. Statystyka i tyle.",
  advice:
    "Pij wodę, śpij 7–9 godzin, rób trzy razy w tygodniu coś, w czym czujesz przepływ. To nie magia. To tylko najnudniejsza prawda, jaką Henrieta zna.",
};

// ============================================================
// Pole formularza
// ============================================================
function DateForm({ value, onChange, onSubmit, error }) {
  const { d, m, y } = value;
  const handle = (k) => (e) => onChange({ ...value, [k]: e.target.value });

  const canSubmit = d && m && y && /^\d{4}$/.test(y);

  return (
    <form
      className="date-form"
      onSubmit={(e) => {
        e.preventDefault();
        if (canSubmit) onSubmit();
      }}
    >
      <div className="date-field day">
        <label htmlFor="d">Dzień</label>
        <input
          id="d"
          type="number"
          min="1"
          max="31"
          inputMode="numeric"
          placeholder="—"
          value={d}
          onChange={handle("d")}
        />
      </div>
      <div className="date-field month">
        <label htmlFor="m">Miesiąc</label>
        <select id="m" value={m} onChange={handle("m")}>
          <option value="">— wybierz —</option>
          {MONTHS_PL.map((name, i) => (
            <option key={i} value={String(i + 1)}>
              {name}
            </option>
          ))}
        </select>
      </div>
      <div className="date-field year">
        <label htmlFor="y">Rok</label>
        <input
          id="y"
          type="number"
          min="1900"
          max="2099"
          inputMode="numeric"
          placeholder="rrrr"
          value={y}
          onChange={handle("y")}
        />
      </div>
    </form>
  );
}

// ============================================================
// Etap obliczania
// ============================================================
function Casting({ tickKey }) {
  const [idx, setIdx] = useState(0);
  useEffect(() => {
    const t = setInterval(
      () => setIdx((i) => (i + 1) % CASTING_LINES.length),
      900
    );
    return () => clearInterval(t);
  }, [tickKey]);

  return (
    <div className="casting">
      <div className="orb-wrap">
        <div className="orb-aura" />
        <Henrieta buzzing eyes="closed" />
      </div>
      <p className="casting-line">{CASTING_LINES[idx]}</p>
      <div className="casting-dots">
        <span className="casting-dot" />
        <span className="casting-dot" />
        <span className="casting-dot" />
        <span className="casting-dot" />
      </div>
    </div>
  );
}

// ============================================================
// Pasek pokazujący obliczenia
// ============================================================
function MathStrip({ date, number }) {
  if (!date) return null;
  const [y, m, d] = date.split("-").map(Number);
  const allDigits = `${y}${String(m).padStart(2, "0")}${String(d).padStart(2, "0")}`
    .split("")
    .map(Number);
  const sum = allDigits.reduce((s, n) => s + n, 0);
  return (
    <div className="math-strip">
      {allDigits.join(" + ")} = <strong>{sum}</strong>
      {sum !== number && (
        <>
          {" "}
          → … → <strong>{number}</strong>
        </>
      )}
      {[11, 22, 33].includes(number) && (
        <>
          {" "}
          <em style={{ color: "var(--honey-glow)", fontStyle: "italic" }}>
            (liczba mistrzowska)
          </em>
        </>
      )}
    </div>
  );
}

// ============================================================
// Wynik
// ============================================================
function Result({ number, date, onReset, tone, showMath }) {
  const profile = HENRIETA_PROFILES[number];
  if (!profile) return null;

  const useScept = tone === "sceptyk";
  const nature = useScept ? SCEPTYK_OVERRIDE.nature : profile.nature;
  const week = useScept ? SCEPTYK_OVERRIDE.week : profile.week;
  const advice = useScept ? SCEPTYK_OVERRIDE.advice : profile.advice;

  return (
    <div className="reveal">
      <div className="crest" style={{ marginBottom: 8 }}>
        <span className="crest-label">Wieszczba dla duszy</span>
      </div>

      <div className="hero-number">
        <HexFrame />
        <span className={"hero-digit" + (number > 9 ? " tiny" : "")}>
          {number}
        </span>
        <span className="hero-glyph">{profile.glyph}</span>
      </div>

      <h2 className="profile-title">{profile.title}</h2>
      <div className="profile-sub">{profile.subtitle}</div>
      <p className="profile-motto">{profile.motto}</p>

      {showMath && <MathStrip date={date} number={number} />}

      <div className="cards">
        <article className="card">
          <div className="card-eyebrow">
            <CardSigil glyph="I" />
            Twoja natura według Henriety
          </div>
          <div className="card-body">
            <p>{nature}</p>
          </div>
        </article>

        <article className="card">
          <div className="card-eyebrow">
            <CardSigil glyph="II" />
            Wieszczba na tydzień
          </div>
          <div className="card-body">
            <p>{week}</p>
          </div>
        </article>

        <article className="card">
          <div className="card-eyebrow">
            <CardSigil glyph="III" />
            Złota rada Henriety
          </div>
          <div className="card-body">
            <p>{advice}</p>
          </div>
        </article>
      </div>

      <div className="actions">
        <button className="btn-ghost" onClick={onReset}>
          ← Spytaj o inną duszę
        </button>
        <button
          className="btn-ghost"
          onClick={() => {
            if (navigator.share) {
              navigator
                .share({
                  title: "Pszczoła Henrieta",
                  text: `Moja liczba życiowa według Pszczoły Henriety to ${number} — ${profile.title}. „${profile.motto}"`,
                })
                .catch(() => {});
            } else {
              navigator.clipboard?.writeText(
                `Moja liczba życiowa to ${number} — ${profile.title}. „${profile.motto}" — wg Pszczoły Henriety`
              );
              alert("Skopiowane do schowka. Henrieta gratuluje gestu.");
            }
          }}
        >
          Udostępnij wieszczbę
        </button>
      </div>
    </div>
  );
}

// ============================================================
// Tła ozdobne
// ============================================================
function Stars({ count = 24 }) {
  const stars = useMemo(
    () =>
      Array.from({ length: count }, (_, i) => ({
        x: Math.random() * 100,
        y: Math.random() * 100,
        size: 1 + Math.random() * 2.5,
        delay: Math.random() * 4,
        dur: 2.5 + Math.random() * 3,
      })),
    [count]
  );
  return (
    <div className="stars" aria-hidden="true">
      {stars.map((s, i) => (
        <span
          key={i}
          className="star"
          style={{
            left: s.x + "%",
            top: s.y + "%",
            width: s.size + "px",
            height: s.size + "px",
            animationDelay: s.delay + "s",
            animationDuration: s.dur + "s",
          }}
        />
      ))}
    </div>
  );
}

function HoneycombPattern() {
  return (
    <svg
      className="honeycomb-pattern"
      aria-hidden="true"
      xmlns="http://www.w3.org/2000/svg"
    >
      <defs>
        <pattern
          id="hex-grid"
          width="56"
          height="48"
          patternUnits="userSpaceOnUse"
        >
          <path
            d="M28 0 L56 14 L56 34 L28 48 L0 34 L0 14 Z"
            fill="none"
            stroke="var(--hex-line)"
            strokeWidth="1"
          />
        </pattern>
      </defs>
      <rect width="100%" height="100%" fill="url(#hex-grid)" />
    </svg>
  );
}

// ============================================================
// Aplikacja
// ============================================================
const MUTE_KEY = "henrieta.muted.v1";

function App() {
  const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS);
  const [stage, setStage] = useState("idle"); // idle | casting | result
  const [form, setForm] = useState({ d: "", m: "", y: "" });
  const [date, setDate] = useState(null);
  const [number, setNumber] = useState(null);
  const [error, setError] = useState("");
  const [muted, setMuted] = useState(() => {
    try { return localStorage.getItem(MUTE_KEY) === "1"; } catch (e) { return false; }
  });
  const audioRef = useRef(null);

  // motyw na <body>
  useEffect(() => {
    const themeClasses = ["theme-sad", "theme-czarna"];
    document.body.classList.remove(...themeClasses);
    if (tweaks.theme === "sad") document.body.classList.add("theme-sad");
    if (tweaks.theme === "czarna") document.body.classList.add("theme-czarna");
  }, [tweaks.theme]);

  // muzyka tła — autoplay przy pierwszej interakcji (przeglądarki blokują wcześniej)
  useEffect(() => {
    const audio = audioRef.current;
    if (!audio) return;
    audio.volume = 0.28;
    audio.muted = muted;
    const tryPlay = () => { audio.play().catch(() => {}); };
    tryPlay();
    const onGesture = () => {
      tryPlay();
      window.removeEventListener("pointerdown", onGesture);
      window.removeEventListener("keydown", onGesture);
      window.removeEventListener("touchstart", onGesture);
    };
    window.addEventListener("pointerdown", onGesture, { once: false });
    window.addEventListener("keydown", onGesture, { once: false });
    window.addEventListener("touchstart", onGesture, { once: false });
    return () => {
      window.removeEventListener("pointerdown", onGesture);
      window.removeEventListener("keydown", onGesture);
      window.removeEventListener("touchstart", onGesture);
    };
  }, []);

  // sync muted → audio + localStorage
  useEffect(() => {
    if (audioRef.current) audioRef.current.muted = muted;
    try { localStorage.setItem(MUTE_KEY, muted ? "1" : "0"); } catch (e) {}
  }, [muted]);

  const handleAsk = () => {
    setError("");
    const d = parseInt(form.d, 10);
    const m = parseInt(form.m, 10);
    const y = parseInt(form.y, 10);
    if (!d || !m || !y) {
      setError("Henrieta potrzebuje pełnej daty. Inaczej tylko zgaduje.");
      return;
    }
    if (d < 1 || d > 31 || m < 1 || m > 12) {
      setError("Ta data wygląda jak z innego wymiaru. Spróbuj jeszcze raz.");
      return;
    }
    if (y < 1900 || y > 2099) {
      setError("Henrieta nie czyta z dat sprzed 1900 i z przyszłości po 2099. Zbyt dużo szumu.");
      return;
    }
    const iso = `${y}-${String(m).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
    const n = lifePathNumber(iso);
    if (!n) {
      setError("Coś się posypało w plastrze. Henrieta prosi spróbować ponownie.");
      return;
    }
    setDate(iso);
    setNumber(n);
    setStage("casting");
    setTimeout(() => setStage("result"), 2600);
  };

  const handleReset = () => {
    setStage("idle");
    setNumber(null);
    setError("");
    window.scrollTo({ top: 0, behavior: "smooth" });
  };

  return (
    <>
      <audio
        ref={audioRef}
        src="fairytale.mp3"
        loop
        preload="auto"
        aria-hidden="true"
      />

      <button
        type="button"
        className="mute-btn"
        onClick={() => setMuted((m) => !m)}
        aria-pressed={muted}
        aria-label={muted ? "Włącz dźwięki" : "Wycisz dźwięki"}
      >
        <span className="mute-ico" aria-hidden="true">{muted ? "🔇" : "🔊"}</span>
        <span>{muted ? "Włącz dźwięki" : "Wycisz dźwięki"}</span>
      </button>

      <div className="honeycomb-bg" />
      <HoneycombPattern />
      {tweaks.showStars && <Stars count={26} />}

      <main className="app">
        <header className="crest">
          <span className="crest-label">Pasieka Wieszczbiarska · Anno {new Date().getFullYear()}</span>
        </header>

        <h1 className="title-wordmark">Pszczoła Henrieta</h1>
        <div className="title-pszczola">numerologia z ula · od 1834 roku</div>

        {stage === "idle" && (
          <div className="stage">
            <div className="orb-wrap">
              <div className="orb-aura" />
              <Henrieta buzzIdle={tweaks.buzz} eyes="open" />
            </div>

            <div className="invocation">
              <p className="invocation-quote">
                Podaj dzień, w którym świat po raz pierwszy usłyszał twoje brzęczenie.
              </p>
              <p className="invocation-sub">
                Henrieta odczyta liczbę życiową, naturę duszy i jedną radę, która prawdopodobnie zadziała.
              </p>
            </div>

            <DateForm
              value={form}
              onChange={setForm}
              onSubmit={handleAsk}
            />

            {error && <div className="error-line">{error}</div>}

            <button className="btn-ask" onClick={handleAsk}>
              Spytaj Henriety
            </button>

            <p className="disclaimer">
              Henrieta jest pszczołą i nie ponosi odpowiedzialności za sprawdzanie się przepowiedni,
              cudze emocje ani za ewentualne nieprzewidziane spotkania z osami.
            </p>
          </div>
        )}

        {stage === "casting" && <Casting tickKey={number} />}

        {stage === "result" && number !== null && (
          <Result
            number={number}
            date={date}
            onReset={handleReset}
            tone={tweaks.tone}
            showMath={tweaks.showMath}
          />
        )}

        <div className="bee-footer">
          „Bzz." — Henrieta
        </div>
      </main>

      <window.TweaksPanel title="Tweaks · Atelier Henriety">
        <window.TweakSection title="Paleta">
          <window.TweakRadio
            label="Motyw"
            value={tweaks.theme}
            onChange={(v) => setTweak("theme", v)}
            options={[
              { value: "noc", label: "Miodowa Noc" },
              { value: "sad", label: "Cytrynowy Sad" },
              { value: "czarna", label: "Czarna Wróżba" },
            ]}
          />
        </window.TweakSection>

        <window.TweakSection title="Atmosfera">
          <window.TweakToggle
            label="Migocące gwiazdy"
            value={tweaks.showStars}
            onChange={(v) => setTweak("showStars", v)}
          />
          <window.TweakToggle
            label="Henrieta brzęczy"
            value={tweaks.buzz}
            onChange={(v) => setTweak("buzz", v)}
          />
        </window.TweakSection>

        <window.TweakSection title="Wieszczba">
          <window.TweakRadio
            label="Ton"
            value={tweaks.tone}
            onChange={(v) => setTweak("tone", v)}
            options={[
              { value: "henrieta", label: "Henrieta" },
              { value: "sceptyk", label: "Sceptyk" },
            ]}
          />
          <window.TweakToggle
            label="Pokaż obliczenia"
            value={tweaks.showMath}
            onChange={(v) => setTweak("showMath", v)}
          />
        </window.TweakSection>
      </window.TweaksPanel>
    </>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
