// Main Currency Converter app
const { useState, useEffect, useRef, useMemo, useCallback } = React;

function App() {
  const [from, setFrom] = useState("USD");
  const [to, setTo] = useState("EUR");
  const [amount, setAmount] = useState("100");
  const [activeInput, setActiveInput] = useState("from"); // which side user is typing in
  const [rate, setRate] = useState(null);
  const [series, setSeries] = useState([]);
  const [loadingRate, setLoadingRate] = useState(false);
  const [loadingChart, setLoadingChart] = useState(false);
  const [lastUpdated, setLastUpdated] = useState(null);
  const [error, setError] = useState(null);
  const [swapCount, setSwapCount] = useState(0);
  const [revealing, setRevealing] = useState(false);
  const [burstId, setBurstId] = useState(0);     // dramatic arrival burst
  const [copiedKey, setCopiedKey] = useState(null); // quick-cell copy feedback
  const [phase, setPhase] = useState(0); // 0..3 progressive disclosure
  const [timeframe, setTimeframe] = useState("1M"); // 1W, 1M, 3M, 1Y, 5Y

  // Progressive disclosure on mount
  useEffect(() => {
    const t1 = setTimeout(() => setPhase(1), 80);
    const t2 = setTimeout(() => setPhase(2), 320);
    const t3 = setTimeout(() => setPhase(3), 640);
    return () => { clearTimeout(t1); clearTimeout(t2); clearTimeout(t3); };
  }, []);

  // Fetch current rate whenever from/to changes
  // Uses open.er-api.com (free, ~160 currencies, no key) with Frankfurter fallback
  useEffect(() => {
    if (from === to) { setRate(1); return; }
    let cancelled = false;
    setLoadingRate(true);
    setError(null);

    const tryFrankfurter = () =>
      fetch(`https://api.frankfurter.dev/v1/latest?base=${from}&symbols=${to}`)
        .then(r => r.ok ? r.json() : Promise.reject(new Error("Rate fetch failed")))
        .then(j => {
          if (cancelled) return;
          const r = j.rates?.[to];
          if (typeof r !== "number") throw new Error("No rate returned");
          setRate(r);
          setLastUpdated(new Date());
        });

    fetch(`https://open.er-api.com/v6/latest/${from}`)
      .then(r => r.ok ? r.json() : Promise.reject(new Error("Rate fetch failed")))
      .then(j => {
        if (cancelled) return;
        if (j.result !== "success" || !j.rates || typeof j.rates[to] !== "number") {
          throw new Error("Rate unavailable");
        }
        setRate(j.rates[to]);
        const ts = j.time_last_update_unix ? new Date(j.time_last_update_unix * 1000) : new Date();
        setLastUpdated(ts);
      })
      .catch(() => tryFrankfurter().catch(err => {
        if (!cancelled) setError(err.message);
      }))
      .finally(() => { if (!cancelled) setLoadingRate(false); });

    return () => { cancelled = true; };
  }, [from, to]);

  // Historical series — only available for ECB-tracked currencies
  const histAvailable = window.FRANKFURTER_CODES.has(from) && window.FRANKFURTER_CODES.has(to);
  useEffect(() => {
    if (from === to) { setSeries([]); return; }
    if (!histAvailable) { setSeries([]); setLoadingChart(false); return; }
    let cancelled = false;
    setLoadingChart(true);
    const days = { "1W": 7, "1M": 30, "3M": 90, "1Y": 365, "5Y": 365 * 5 }[timeframe] || 30;
    const end = new Date();
    const start = new Date(end.getTime() - days * 24 * 60 * 60 * 1000);
    const fmt = d => d.toISOString().slice(0, 10);
    fetch(`https://api.frankfurter.dev/v1/${fmt(start)}..${fmt(end)}?base=${from}&symbols=${to}`)
      .then(r => r.ok ? r.json() : Promise.reject(new Error("History fetch failed")))
      .then(j => {
        if (cancelled) return;
        const rates = j.rates || {};
        let arr = Object.keys(rates).sort().map(date => ({
          date,
          value: rates[date][to],
        })).filter(d => typeof d.value === "number");
        if (arr.length > 260) {
          const step = Math.ceil(arr.length / 260);
          arr = arr.filter((_, i) => i % step === 0 || i === arr.length - 1);
        }
        setSeries(arr);
      })
      .catch(() => { if (!cancelled) setSeries([]); })
      .finally(() => { if (!cancelled) setLoadingChart(false); });
    return () => { cancelled = true; };
  }, [from, to, timeframe, histAvailable]);

  // Compute the OTHER side's value based on active input + rate
  const round2 = (n) => (Math.round((Number(n) || 0) * 100) / 100).toString();

  // Reversed (user typing in `to`, want from value)
  const [reverseAmount, setReverseAmount] = useState("");

  // When rate changes, sync the inactive side (rounded to 2 decimals)
  useEffect(() => {
    if (rate == null) return;
    if (activeInput === "from") {
      setReverseAmount(round2((parseFloat(amount) || 0) * rate));
    } else {
      setAmount(round2((parseFloat(reverseAmount) || 0) / rate));
    }
    // eslint-disable-next-line
  }, [rate]);

  const amountNum = parseFloat(amount) || 0;
  const reverseNum = parseFloat(reverseAmount) || 0;

  const swap = () => {
    if (navigator.vibrate) navigator.vibrate([10, 30, 10]);
    setSwapCount(c => c + 1);
    setRevealing(true);
    setTimeout(() => setRevealing(false), 900);
    setFrom(to);
    setTo(from);
    setAmount(reverseAmount);
    setReverseAmount(amount);
    setActiveInput(activeInput === "from" ? "to" : "from");
  };

  const fromCur = window.CURRENCY_BY_CODE[from];
  const toCur = window.CURRENCY_BY_CODE[to];

  // Live updated indicator pulse + processing reveal + arrival burst whenever rate refreshes
  const [pulse, setPulse] = useState(0);
  useEffect(() => {
    if (rate == null) return;
    setPulse(p => p + 1);
    setRevealing(true);
    setBurstId(b => b + 1);
    if (navigator.vibrate) navigator.vibrate(6);
    const t = setTimeout(() => setRevealing(false), 900);
    return () => clearTimeout(t);
  }, [rate]);

  // Temperature / trend (drives ambient tint)
  const trendDelta = useMemo(() => {
    if (!series || series.length < 2) return 0;
    const first = series[0].value, last = series[series.length - 1].value;
    if (!first) return 0;
    return (last - first) / first;
  }, [series]);
  const trendClass = trendDelta > 0.001 ? "warm" : trendDelta < -0.001 ? "cool" : "neutral";

  // Copy a quick-cell value to clipboard with cinematic feedback
  const copyQuick = (key, text) => {
    if (navigator.clipboard) navigator.clipboard.writeText(text).catch(() => {});
    if (navigator.vibrate) navigator.vibrate([6, 20, 6]);
    setCopiedKey(key);
    setTimeout(() => setCopiedKey(c => (c === key ? null : c)), 1400);
  };

  return (
    <>
      <AmbientBackground trend={trendDelta} />

      <div className={`app phase-up-to-${phase} trend-${trendClass}`} data-revealing={revealing}>
        <header className="topbar">
          <div className="hero">
            <h1 className="hero__title">
              Real-Time <span className="hero__title-accent">Currency Converter</span>
            </h1>
            <p className="hero__sub">
              Live exchange rates across <strong>30+ currencies</strong> — powered by the European Central Bank.
              Convert instantly in both directions. Free, accurate, and updated every business day.
            </p>
          </div>

          <div className="status">
            <div className="status__item">
              <span className={`live-dot ${error ? "err" : "ok"}`}></span>
              <span className="status__label">{error ? "ERROR" : "MARKET LIVE"}</span>
            </div>
            <div className="status__sep"></div>
            <div className="status__item">
              <span className="status__label muted">UPDATED</span>
              <span className="status__val">
                {lastUpdated
                  ? lastUpdated.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" })
                  : "—"}
              </span>
            </div>
            <div className="status__sep"></div>
            <div className="status__item">
              <span className="status__label muted">SRC</span>
              <span className="status__val">FRANKFURTER · ECB</span>
            </div>
          </div>
        </header>

        <main className="converter">
          <div className="converter__pair">
            {/* FROM */}
            <div className="pair-col">
              <CurrencySelector
                value={from}
                onChange={setFrom}
                label="YOU PAY"
                accent="cyan"
                otherCode={to}
              />
              <div className="amount-card" data-active={activeInput === "from"}>
                <div className="liquid-spec"></div>
                <div className="liquid-edge"></div>
                <div className="liquid-sweep"></div>
                <div className="amount-card__top">
                  <span className="amount-card__symbol">{fromCur.symbol}</span>
                  <div className="amount-card__input amount-card__input--display">
                    {activeInput === "from" ? (
                      <input
                        className="amount-card__input-raw"
                        type="text"
                        inputMode="decimal"
                        value={amount}
                        onChange={(e) => {
                          const v = e.target.value.replace(/[^\d.]/g, "");
                          setAmount(v);
                          setActiveInput("from");
                          if (rate != null) setReverseAmount(round2((parseFloat(v) || 0) * rate));
                        }}
                        placeholder="0.00"
                      />
                    ) : (
                      <button
                        className="amount-card__input-raw amount-card__display-btn"
                        onClick={() => setActiveInput("from")}
                        tabIndex={0}
                      >
                        <NumberTicker value={amountNum} decimals={2}/>
                      </button>
                    )}
                  </div>
                </div>
                <div className="amount-card__glow"></div>
              </div>
            </div>

            {/* SWAP */}
            <button className="swap-btn" onClick={swap} aria-label="Swap currencies">
              <div className="swap-btn__ring"></div>
              <div className="swap-btn__ring swap-btn__ring--2"></div>
              <div className="swap-btn__ring swap-btn__ring--3"></div>
              <div className="swap-btn__glass"></div>
              {/* Arrival burst — re-keyed so animation restarts each time */}
              <div key={`burst-${burstId}`} className="swap-btn__burst" aria-hidden></div>
              <div key={`burst2-${burstId}`} className="swap-btn__burst swap-btn__burst--2" aria-hidden></div>
              <svg viewBox="0 0 24 24" width="22" height="22" style={{ transform: `rotate(${swapCount * 180}deg)` }}>
                <path d="M7 7h10M7 7l3-3M7 7l3 3" stroke="currentColor" strokeWidth="1.8" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
                <path d="M17 17H7M17 17l-3 3M17 17l-3-3" stroke="currentColor" strokeWidth="1.8" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
              </svg>
            </button>

            {/* TO */}
            <div className="pair-col">
              <CurrencySelector
                value={to}
                onChange={setTo}
                label="YOU GET"
                accent="amber"
                otherCode={from}
              />
              <div className="amount-card amount-card--to" data-active={activeInput === "to"}>
                <div className="liquid-spec"></div>
                <div className="liquid-edge"></div>
                <div className="liquid-sweep"></div>
                <div className="amount-card__top">
                  <span className="amount-card__symbol">{toCur.symbol}</span>
                  <div className="amount-card__input amount-card__input--display">
                    {activeInput === "to" ? (
                      <input
                        className="amount-card__input-raw"
                        type="text"
                        inputMode="decimal"
                        value={reverseAmount}
                        onChange={(e) => {
                          const v = e.target.value.replace(/[^\d.]/g, "");
                          setReverseAmount(v);
                          setActiveInput("to");
                          if (rate != null && rate !== 0) setAmount(round2((parseFloat(v) || 0) / rate));
                        }}
                        placeholder="0.00"
                      />
                    ) : (
                      <button
                        className="amount-card__input-raw amount-card__display-btn"
                        onClick={() => setActiveInput("to")}
                        tabIndex={0}
                      >
                        <NumberTicker value={reverseNum} decimals={2}/>
                      </button>
                    )}
                  </div>
                </div>
                <div className="amount-card__glow amount-card__glow--to"></div>
              </div>
            </div>
          </div>

          {/* Rate readout */}
          <div className="rate-bar">
            <div className="rate-bar__main">
              <span className="rate-bar__label">EXCHANGE RATE</span>
              <span className="rate-bar__eq">
                <span className="rate-bar__one">1 {from}</span>
                <span className="rate-bar__arrow">=</span>
                <span className="rate-bar__val">
                  {rate != null ? <NumberTicker value={rate} decimals={6}/> : "—"} {to}
                </span>
                <InfoTip label="Mid-market rate">
                  This is the <strong>mid-market exchange rate</strong> — the rate banks use between themselves. It's sourced from the European Central Bank and refreshed every business day.
                </InfoTip>
              </span>
            </div>
            <div className="rate-bar__inverse">
              <span className="rate-bar__label muted">INVERSE</span>
              <span className="rate-bar__inv-val">
                1 {to} = {rate ? (1 / rate).toFixed(6) : "—"} {from}
              </span>
            </div>
          </div>

          {/* Quick preset chips — tap to set the amount.
              Lives above the chart so users can frame the conversion
              before the history visualization. */}
          <div className="quick-presets">
            <div className="quick-presets__label">
              <span className="quick-presets__dot"></span>
              Quick amounts <span className="quick-presets__hint">— tap to set</span>
              <InfoTip label="How these work">
                Click any chip to instantly set the <strong>amount</strong> on the left side. The converted value updates with a live animation.
              </InfoTip>
            </div>
            <div className="quick-presets__chips">
              {[1, 10, 100, 1000, 10000].map((n, i) => {
                const isActive = parseFloat(amount) === n && activeInput === "from";
                const previewText = rate
                  ? `${toCur.symbol}${(n * rate).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
                  : "—";
                const labelShort = n >= 1000 ? `${n / 1000}K` : `${n}`;
                return (
                  <button
                    key={n}
                    type="button"
                    className={`chip ${isActive ? "chip--active" : ""}`}
                    style={{ animationDelay: `${i * 70}ms` }}
                    onClick={() => {
                      setAmount(String(n));
                      setActiveInput("from");
                      if (rate != null) setReverseAmount(round2(n * rate));
                      setBurstId(b => b + 1);
                      if (navigator.vibrate) navigator.vibrate([6, 25, 6]);
                    }}
                  >
                    <span className="chip__sym">{fromCur.symbol}</span>
                    <span className="chip__num">{labelShort}</span>
                    <span className="chip__preview">≈ {previewText}</span>
                    <span className="chip__ripple"></span>
                  </button>
                );
              })}
            </div>
          </div>

          {/* Chart */}
          <div className="chart-card">
            <div className="liquid-spec"></div>
            <div className="liquid-edge"></div>
            <Sparkline
              series={series}
              loading={loadingChart}
              from={from}
              to={to}
              timeframe={timeframe}
              histAvailable={histAvailable}
              onTimeframeChange={(t) => {
                if (navigator.vibrate) navigator.vibrate(5);
                setTimeframe(t);
              }}
            />
          </div>

          {/* Bridges the converter back to the site's visa flow — clicking
              the button opens ClearForTravel with origin + destination
              auto-populated from the currently picked currencies. */}
          <div className="apply-cta">
            <div className="apply-cta__copy">
              <div className="apply-cta__eyebrow">
                <span className="apply-cta__eyebrow-dot"></span>
                Travel-ready in minutes
              </div>
              <div className="apply-cta__title">
                Going from {fromCur.name} to {toCur.name}?
              </div>
              <div className="apply-cta__sub">
                Get your visa, eVisa, or entry authorization sorted before you fly.
                Skip the embassy queue — apply online in a few steps.
              </div>
            </div>
            <a
              href={`https://www.clearfortravel.com/?origin=${(fromCur.country || "").toUpperCase()}&destination=${(toCur.country || "").toUpperCase()}&purpose=TOURISM&utm_source=needtravelvisa&utm_medium=currency_converter`}
              target="_blank"
              rel="noopener"
              className="apply-cta__btn"
            >
              Start My Application
              <svg className="apply-cta__arrow" width="14" height="14" viewBox="0 0 14 14" aria-hidden>
                <path d="M3 7h8M7 3l4 4-4 4" stroke="currentColor" strokeWidth="1.8" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
              </svg>
            </a>
          </div>
        </main>

        <footer className="footer">
          <span>RATES SOURCED FROM EUROPEAN CENTRAL BANK VIA FRANKFURTER.DEV</span>
          <span>NO API KEY · NO TRACKING · UPDATED EACH BUSINESS DAY ~16:00 CET</span>
        </footer>
      </div>
    </>
  );
}

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