/* VillaCash — shared hooks, data, small components */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ---------- in-view ---------- */
function useInView(opts = {}) {
  const ref = useRef(null);
  const [inView, setInView] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(
      ([e]) => { if (e.isIntersecting) { setInView(true); io.disconnect(); } },
      { threshold: 0.15, rootMargin: '0px 0px -8% 0px', ...opts }
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return [ref, inView];
}

function Reveal({ as: Tag = 'div', delay = 0, className = '', children, style }) {
  const [ref, inView] = useInView();
  const d = delay ? ` d${delay}` : '';
  return (
    <Tag ref={ref} style={style} className={`reveal${d} ${inView ? 'is-in' : ''} ${className}`}>
      {children}
    </Tag>
  );
}

/* ---------- count up ---------- */
function CountUp({ to, dur = 1700, prefix = '', suffix = '', sep = true, decimals = 0 }) {
  const [ref, inView] = useInView({ threshold: 0.4 });
  const [val, setVal] = useState(0);
  useEffect(() => {
    if (!inView) return;
    let raf;
    const start = performance.now();
    const tick = (now) => {
      const p = Math.min(1, (now - start) / dur);
      const e = 1 - Math.pow(1 - p, 3);
      setVal(to * e);
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [inView]);
  const n = decimals ? val.toFixed(decimals) : Math.round(val);
  const str = sep ? Number(n).toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals }) : String(n);
  return <span ref={ref}>{prefix}{str}{suffix}</span>;
}

/* ---------- countdown to next midnight ---------- */
function useMidnightCountdown() {
  const [t, setT] = useState(() => msLeft());
  function msLeft() {
    const now = new Date();
    const end = new Date(now); end.setHours(24, 0, 0, 0);
    return end - now;
  }
  useEffect(() => {
    const id = setInterval(() => setT(msLeft()), 1000);
    return () => clearInterval(id);
  }, []);
  const s = Math.max(0, Math.floor(t / 1000));
  const hh = String(Math.floor(s / 3600)).padStart(2, '0');
  const mm = String(Math.floor((s % 3600) / 60)).padStart(2, '0');
  const ss = String(s % 60).padStart(2, '0');
  return { hh, mm, ss };
}

const fmtEuro = (n) => '€' + Number(n).toLocaleString('en-US');

/* ---------- real villa media (local copies of VillaReel assets) ---------- */
const VR = '/villacash';
function BgVideo({ src, poster, className = '' }) {
  const ref = useRef(null);
  useEffect(() => {
    const v = ref.current;
    if (!v) return;
    v.defaultMuted = true;
    v.muted = true;
    v.volume = 0;
    v.setAttribute('muted', '');
    const tryPlay = () => v.play && v.play().catch(() => {});
    tryPlay();
    v.addEventListener('canplay', tryPlay, { once: true });
  }, []);
  return (
    <video ref={ref} className={className} src={src} poster={poster}
      muted loop autoPlay playsInline preload="metadata" />
  );
}

/* ---------- data ---------- */
const VALUE_ITEMS = [
  { r: 'I',   t: 'Reels Launchpad: month one',     v: 4000,
    d: 'Ten short videos for your villa, delivered in your first 30 days. A real shoot (crew, drone, lighting, edit, music) runs €300 to €500 per clip; you get finished files ready to post on day one. After month one, you can keep adding more from €249 a month.' },
  { r: 'II',  t: 'Direct Booking Engine',        v: 3000,
    d: 'A custom website with a booking flow built for conversion. Guests pay you directly. You keep every euro instead of giving 15% to Airbnb or Booking.' },
  { r: 'III', t: 'Villa Profit Implementation',  v: 1500,
    d: 'Templates, scripts and automated guest comms that take the friction out of every reservation: pre-arrival, check-in, mid-stay, follow-up. Set it once, runs forever.' },
  { r: 'IV',  t: '5-Star Review System',         v: 500,
    d: 'The exact prompts, timing and small touches that turn a normal stay into a five-star review. Rankings move. Conversion follows.' },
  { r: 'V',   t: 'Villa Profit Multiplier',      v: 1000,
    d: 'Add-ons and upsells (private chef, transfers, late check-out, experiences) that quietly lift the average booking by a few hundred euros. The guest gets a better stay; you get the margin.' },
  { r: 'VI',  t: 'Dynamic Pricing Workshop',     v: 1000,
    d: 'How the top-earning owners actually price the year. Peak weeks at premium rates, shoulder season filled at the right number, off-season worth opening at all.' },
  { r: 'VII', t: 'Season Opening Weekend (live)', v: 500,
    d: 'One live weekend with the team to get your calendar, pricing and first reels set up before the season starts. Not recorded. Not repeated.' },
];

const MARQUEE = [
  'Stop paying OTA commissions',
  '10 villa videos in your first month',
  'Direct bookings at premium nightly rates',
  'More five-star reviews, less chasing',
  'Pricing that earns more per week',
];

const FAQS = [
  { q: 'Q.01', t: 'How fast does this get set up?',
    a: 'Most owners go live with their booking site and first reels during the opening weekend. The full system is usually running in two to three weeks. You don’t need to be technical.' },
  { q: 'Q.02', t: 'What if my villa isn’t on a major platform yet?',
    a: 'Even better. The booking site, video library and review flow work whether you’re on OTAs or not. Most owners join precisely to stop being dependent on Airbnb and Booking.' },
  { q: 'Q.03', t: 'What does my €3,999 actually cover?',
    a: 'A lifetime licence to the VillaCash system: the Reels Launchpad (your first 10 reels), the Direct Booking Engine site, the pricing playbook, the review flow and the rest of the seven systems. No renewals. You own it.' },
  { q: 'Q.04', t: 'How does the 60-day guarantee work?',
    a: 'Join, do the work, and if you’re not seeing results in 60 days, write to support@villacashsystem.com and we refund you. Everything we built together stays yours.' },
];

Object.assign(window, { useInView, Reveal, CountUp, useMidnightCountdown, fmtEuro, VR, BgVideo, VALUE_ITEMS, MARQUEE, FAQS });
