/* global React */
// The Gamekeeper's Cottage — Cottage details
const { useState, useEffect, useRef } = React;
const NS_C = window.GamekeepersCottageDesignSystem_070bc7;
const { Button, Badge, Rating, Eyebrow, Card, Amenity } = NS_C;
const Photo = window.GKPhoto;
const MiniCalendar = window.GKMiniCalendar;
const useShell = window.GKuseShell;
const useReviews = window.GKuseReviews;
const reviewStats = window.GKreviewStats;
const reviewMonth = window.GKreviewMonth;
const useRates = window.GKuseRates;
const useAvailability = window.GKuseAvailability;
const quoteStay = window.GKquoteStay;
const stayAvailability = window.GKstayAvailability;
const RateGuide = window.GKRateGuide;
const AvailabilityNote = window.GKAvailabilityNote;
const visibleRatePeriods = window.GKvisibleRatePeriods;
const IMG = window.GK_IMG;
const C = window.GKContact;

const ALL_PHOTOS = [
  { src: IMG.exterior1, label: 'The cottage' }, { src: IMG.living1, label: 'Sitting room' },
  { src: IMG.kitchen, label: 'Kitchen' }, { src: IMG.dining, label: 'Dining room' },
  { src: IMG.doubleRoom, label: 'Double bedroom' }, { src: IMG.twinRoom, label: 'Twin bedroom' },
  { src: IMG.singleRoom, label: 'Single bedroom' }, { src: IMG.bathroom, label: 'Bathroom' },
  { src: IMG.garden2, label: 'The garden' }, { src: IMG.pond, label: 'The pond' },
  { src: IMG.woodDen, label: 'Wood den' }, { src: IMG.deer, label: 'Wildlife' },
];

// Gallery photos — read from assets/gallery.json (Decap-editable) on the live host;
// fall back to the embedded snapshot, then the built-in list. The "View all N photos"
// counter follows whatever this returns.
let _galleryCache = null, _galleryPromise = null;
function loadGallery() {
  if (_galleryCache) return Promise.resolve(_galleryCache);
  if (_galleryPromise) return _galleryPromise;
  _galleryPromise = (async () => {
    try {
      const res = await fetch('assets/gallery.json', { cache: 'no-store' });
      if (res.ok) { const d = await res.json(); if (d && Array.isArray(d.photos) && d.photos.length) { _galleryCache = d.photos; return _galleryCache; } }
    } catch (e) { /* fall through */ }
    if (window.GK_GALLERY && Array.isArray(window.GK_GALLERY.photos) && window.GK_GALLERY.photos.length) { _galleryCache = window.GK_GALLERY.photos; return _galleryCache; }
    _galleryCache = ALL_PHOTOS;
    return _galleryCache;
  })();
  return _galleryPromise;
}
function useGallery() {
  const [photos, setPhotos] = useState(_galleryCache || ALL_PHOTOS);
  useEffect(() => { let live = true; loadGallery().then(p => { if (live) setPhotos(p); }); return () => { live = false; }; }, []);
  return photos;
}

function KeyFacts() {
  const facts = [['users', 'Sleeps 5'], ['bed-double', '3 bedrooms'], ['bath', '1 bathroom'], ['trees', '4 acres of wood'], ['paw-print', 'No pets']];
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: '12px 28px', marginTop: 18 }}>
      {facts.map(([ic, l]) => (
        <span key={l} style={{ display: 'inline-flex', alignItems: 'center', gap: 8, color: 'var(--text-body)', fontSize: 15.5, fontWeight: 500 }}>
          <i data-lucide={ic} style={{ width: 18, height: 18, color: 'var(--color-primary)' }}></i>{l}
        </span>
      ))}
    </div>
  );
}

function GalleryBand() {
  const { openLightbox } = useShell();
  const photos = useGallery();
  const stats = reviewStats(useReviews());
  return (
    <section style={{ paddingTop: 40 }}>
      <div className="container">
        <a href="explore" style={{ textDecoration: 'none' }}><Eyebrow>The Cottage · near Southwold</Eyebrow></a>
        <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 20, flexWrap: 'wrap', margin: '12px 0 4px' }}>
          <h1 className="h1" style={{ flex: '1 1 auto', minWidth: 0 }}>The Gamekeeper's Cottage</h1>
          {stats.count > 0 && <span style={{ flexShrink: 0 }}><Rating value={stats.average} count={stats.count} /></span>}
        </div>
        <KeyFacts />
        {photos.length > 0 && (
          <div className="gk-photos" style={{ position: 'relative', display: 'grid', gridTemplateColumns: '2fr 1fr 1fr', gridTemplateRows: '210px 210px', gap: 12, marginTop: 24 }}>
            <div style={{ gridColumn: '1', gridRow: 'span 2' }}><Photo src={photos[0].src} ratio="auto" radius={14} style={{ height: '100%', aspectRatio: 'auto' }} onClick={() => openLightbox(photos, 0)} /></div>
            {photos.slice(1, 5).map((p, idx) => (
              <Photo key={idx} src={p.src} ratio="auto" radius={14} style={{ height: '100%', aspectRatio: 'auto' }} onClick={() => openLightbox(photos, idx + 1)} />
            ))}
            <Button variant="on-dark" size="md" onClick={() => openLightbox(photos, 0)} style={{ position: 'absolute', bottom: 16, right: 16 }}>
              <i data-lucide="images" style={{ width: 18, height: 18 }}></i> View all {photos.length} photos
            </Button>
          </div>
        )}
      </div>
    </section>
  );
}

const _plusDays = (n) => { const d = new Date(); d.setDate(d.getDate() + n); return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0'); };
function BookCard() {
  const { openBooking } = useShell();
  const [bar, setBar] = useState({ arrive: _plusDays(21), depart: _plusDays(28), guests: '4' });
  const set = (k) => (e) => setBar((b) => ({ ...b, [k]: e.target.value }));
  const todayISO = _plusDays(0);
  const onArrive = (e) => { const v = e.target.value; setBar((b) => { const next = { ...b, arrive: v }; if (v && (!b.depart || b.depart < v)) next.depart = v; return next; }); };
  return (
    <Card padding="md" className="bookcard">
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
        <span style={{ fontFamily: 'var(--font-display)', fontSize: 34, fontWeight: 600, color: 'var(--text-strong)' }}>£140</span>
        <span className="muted">per night</span>
      </div>
      <p className="muted" style={{ fontSize: 14, margin: '4px 0 16px' }}>Breaks of 3 nights or more · weekly stays £588–£900</p>
      <div className="gk-stack" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginBottom: 10 }}>
        <label className="gk-field"><span className="gk-field__label">Arrival</span><input className="gk-input" type="date" min={todayISO} value={bar.arrive} onChange={onArrive} /></label>
        <label className="gk-field"><span className="gk-field__label">Departure</span><input className="gk-input" type="date" min={todayISO} value={bar.depart} onChange={set('depart')} /></label>
      </div>
      <label className="gk-field" style={{ marginBottom: 14 }}><span className="gk-field__label">Guests</span><input className="gk-input" type="number" min="1" max="5" value={bar.guests} onChange={set('guests')} /></label>
      <Button variant="primary" size="lg" fullWidth onClick={() => openBooking(bar)}>Check rates &amp; reserve</Button>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8, marginTop: 12, color: 'var(--text-muted)', fontSize: 14 }}>
        <i data-lucide="shield-check" style={{ width: 16, height: 16, color: 'var(--color-primary)' }}></i> No deposit taken at this stage
      </div>
      <hr className="divider" style={{ margin: '16px 0' }} />
      <a className="chip-link" href={'tel:' + C.PHONE.replace(/\s/g, '')} style={{ justifyContent: 'center', width: '100%' }}>
        <i data-lucide="phone" style={{ width: 16, height: 16 }}></i> Or call Nick on {C.PHONE}
      </a>
    </Card>
  );
}

function Highlights() {
  const items = [
    ['trees', 'Set in a 100-acre wood', 'Total seclusion, with four acres of private woodland attached'],
    ['flame', 'Log burner & cosy living', 'A proper sitting room with views over the garden'],
    ['bird', 'Birdwatching from the windows', 'Feeders bring nuthatches, woodpeckers, deer and owls'],
  ];
  return (
    <div style={{ display: 'grid', gap: 18 }}>
      {items.map(([ic, t, d]) => (
        <div key={t} style={{ display: 'flex', gap: 16, alignItems: 'flex-start' }}>
          <span style={{ width: 44, height: 44, flex: 'none', borderRadius: 999, background: 'var(--accent-fern)', color: 'var(--color-primary)', display: 'grid', placeItems: 'center' }}><i data-lucide={ic} style={{ width: 21, height: 21 }}></i></span>
          <div><b style={{ fontFamily: 'var(--font-display)', fontSize: 18, color: 'var(--text-strong)' }}>{t}</b><p className="muted" style={{ margin: '2px 0 0', fontSize: 15.5 }}>{d}</p></div>
        </div>
      ))}
    </div>
  );
}

function VideoTour() {
  return (
    <div>
      <h2 className="h3" style={{ marginBottom: 16 }}>Take a look around</h2>
      <div style={{ position: 'relative', width: '100%', paddingTop: '56.25%', borderRadius: 'var(--radius-lg)', overflow: 'hidden', background: '#000' }}>
        <iframe
          src={ytEmbed('X0KnW_cV6CY', 45)}
          title="A tour of Gamekeeper's Cottage"
          loading="lazy"
          allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
          allowFullScreen
          style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', border: 0 }}
        ></iframe>
      </div>
    </div>
  );
}

// Bedroom data — read from assets/bedrooms.json (which Decap CMS edits) on the live
// host; fall back to the embedded window.GK_BEDROOMS for local file:// previews.
let _bedroomsCache = null, _bedroomsPromise = null;
function loadBedrooms() {
  if (_bedroomsCache) return Promise.resolve(_bedroomsCache);
  if (_bedroomsPromise) return _bedroomsPromise;
  _bedroomsPromise = (async () => {
    try {
      const res = await fetch('assets/bedrooms.json', { cache: 'no-store' });
      if (res.ok) {
        const data = await res.json();
        if (data && Array.isArray(data.bedrooms)) { _bedroomsCache = data.bedrooms; return _bedroomsCache; }
      }
    } catch (e) { /* fall through */ }
    if (window.GK_BEDROOMS && Array.isArray(window.GK_BEDROOMS.bedrooms)) { _bedroomsCache = window.GK_BEDROOMS.bedrooms; return _bedroomsCache; }
    _bedroomsCache = [];
    return _bedroomsCache;
  })();
  return _bedroomsPromise;
}
function useBedrooms() {
  const [rooms, setRooms] = useState(_bedroomsCache || []);
  useEffect(() => { let live = true; loadBedrooms().then(r => { if (live) setRooms(r); }); return () => { live = false; }; }, []);
  return rooms;
}

// Pull a YouTube video ID from a full URL (youtu.be/ID, watch?v=ID, embed/ID,
// shorts/ID) or accept a bare ID.
function ytId(s) {
  if (!s) return '';
  const m = String(s).match(/(?:youtu\.be\/|[?&]v=|embed\/|shorts\/)([A-Za-z0-9_-]{6,})/);
  return m ? m[1] : (/^[A-Za-z0-9_-]{6,}$/.test(String(s).trim()) ? String(s).trim() : '');
}
// Build an embed URL that autoplays muted and loops (browsers only allow autoplay
// when muted; loop needs playlist=<id>). playsinline keeps it inline on mobile.
function ytEmbed(id, start) {
  return 'https://www.youtube-nocookie.com/embed/' + id +
    '?rel=0&autoplay=1&mute=1&loop=1&playsinline=1&playlist=' + id +
    (start ? '&start=' + start : '');
}

function BedroomModal({ room, onClose }) {
  const [active, setActive] = useState(0);
  const dialogRef = useRef(null);
  useEffect(() => {
    const prev = document.activeElement;
    if (dialogRef.current) dialogRef.current.focus();
    const onKey = (e) => e.key === 'Escape' && onClose();
    window.addEventListener('keydown', onKey);
    if (window.lucide) window.lucide.createIcons();
    return () => { window.removeEventListener('keydown', onKey); if (prev && prev.focus) prev.focus(); };
  }, [onClose, active]);
  if (!room) return null;
  const photos = room.photos || [];
  const vid = ytId(room.video);
  // Photos and the video form a single gallery; the video is a slide marked with a
  // play badge and autoplays (muted, looping) when selected.
  const media = photos.map((src) => ({ type: 'image', src }));
  if (vid) media.push({ type: 'video', id: vid, thumb: 'https://img.youtube.com/vi/' + vid + '/hqdefault.jpg' });
  const cur = media[active] || media[0];
  const pick = (i) => setActive(i);
  const facts = [
    ['bed-double', room.bed],
    ['users', room.sleeps ? 'Sleeps ' + room.sleeps : null],
    ['home', room.location],
    ['bath', room.bathroom],
  ].filter(([, v]) => v);
  return (
    <div className="overlay" onClick={onClose}>
      <div className="dialog" ref={dialogRef} tabIndex={-1} role="dialog" aria-modal="true" aria-label={room.name}
        style={{ position: 'relative', maxWidth: 820, width: '100%', maxHeight: '90vh', overflowY: 'auto', outline: 'none' }}
        onClick={(e) => e.stopPropagation()}>
        <button className="dialog__close" onClick={onClose} aria-label="Close"><i data-lucide="x" style={{ width: 20, height: 20 }}></i></button>
        <div style={{ padding: '30px 32px' }}>
          <Eyebrow>Sleeping accommodation</Eyebrow>
          <h2 className="h3" style={{ margin: '10px 0 18px' }}>{room.name}</h2>
          {media.length > 0 && (
            <div>
              <div style={{ borderRadius: 'var(--radius-lg)', overflow: 'hidden', background: '#000' }}>
                {cur.type === 'image' ? (
                  <img src={cur.src} alt={room.name + ' photo'} loading="lazy"
                    style={{ display: 'block', width: '100%', aspectRatio: '3 / 2', objectFit: 'cover' }} />
                ) : (
                  <div style={{ position: 'relative', width: '100%', paddingTop: '56.25%' }}>
                    <iframe
                      src={ytEmbed(cur.id)}
                      title={room.name + ' video'}
                      allow="autoplay; encrypted-media; picture-in-picture; web-share"
                      allowFullScreen
                      style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', border: 0 }}
                    ></iframe>
                  </div>
                )}
              </div>
              {media.length > 1 && (
                <div style={{ display: 'flex', gap: 8, marginTop: 8, flexWrap: 'wrap' }}>
                  {media.map((m, i) => (
                    <button key={i} onClick={() => pick(i)} aria-label={m.type === 'video' ? 'Room video' : 'Photo ' + (i + 1)}
                      style={{ position: 'relative', padding: 0, border: i === active ? '2px solid var(--color-primary)' : '2px solid transparent', borderRadius: 8, overflow: 'hidden', cursor: 'pointer', background: 'none', lineHeight: 0 }}>
                      <img src={m.type === 'image' ? m.src : m.thumb} alt=""
                        onError={m.type === 'video' ? (e) => { e.currentTarget.onerror = null; if (photos[0]) e.currentTarget.src = photos[0]; } : undefined}
                        style={{ width: 72, height: 54, objectFit: 'cover', display: 'block' }} />
                      {m.type === 'video' && (
                        <span style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center' }}>
                          <span style={{ width: 26, height: 26, borderRadius: 999, background: 'rgba(0,0,0,0.6)', display: 'grid', placeItems: 'center' }}>
                            <i data-lucide="play" style={{ width: 13, height: 13, color: '#fff' }}></i>
                          </span>
                        </span>
                      )}
                    </button>
                  ))}
                </div>
              )}
            </div>
          )}
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px 26px', margin: '20px 0 0' }}>
            {facts.map(([ic, v]) => (
              <span key={v} style={{ display: 'inline-flex', alignItems: 'center', gap: 8, color: 'var(--text-body)', fontSize: 15, fontWeight: 500 }}>
                <i data-lucide={ic} style={{ width: 18, height: 18, color: 'var(--color-primary)' }}></i>{v}
              </span>
            ))}
          </div>
          {room.features && room.features.length > 0 && (
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, marginTop: 16 }}>
              {room.features.map((f) => <Badge key={f} tone="sage">{f}</Badge>)}
            </div>
          )}
          {room.details && (
            <p style={{ lineHeight: 1.7, margin: '18px 0 0', color: 'var(--text-body)' }}>{room.details}</p>
          )}
        </div>
      </div>
    </div>
  );
}

function Sleeping() {
  const rooms = useBedrooms();
  const [open, setOpen] = useState(null);
  return (
    <div>
      <h2 className="h3" style={{ marginBottom: 16 }}>Sleeping accommodation</h2>
      <div className="grid grid-3">
        {rooms.map((room, i) => (
          <button key={room.name} onClick={() => setOpen(i)}
            style={{ display: 'block', textAlign: 'left', padding: 0, border: 'none', background: 'none', cursor: 'pointer', width: '100%' }}
            aria-label={'View photos and details for ' + room.name}>
            <div style={{ position: 'relative' }}>
              <Photo src={(room.photos && room.photos[0]) || ''} ratio="4 / 3" radius={12} />
              {room.photos && room.photos.length > 1 && (
                <span style={{ position: 'absolute', right: 8, bottom: 8, display: 'inline-flex', alignItems: 'center', gap: 5, background: 'rgba(0,0,0,0.6)', color: '#fff', fontSize: 12.5, padding: '4px 8px', borderRadius: 999 }}>
                  <i data-lucide="images" style={{ width: 14, height: 14 }}></i>{room.photos.length}
                </span>
              )}
            </div>
            <div style={{ marginTop: 10 }}>
              <b style={{ color: 'var(--text-strong)' }}>{room.name}</b>
              <div className="muted" style={{ fontSize: 14 }}>{room.summary}</div>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, marginTop: 6, color: 'var(--color-primary)', fontSize: 13.5, fontWeight: 600 }}>
                View photos &amp; details <i data-lucide="arrow-right" style={{ width: 14, height: 14 }}></i>
              </span>
            </div>
          </button>
        ))}
      </div>
      <p className="muted" style={{ fontSize: 14.5, marginTop: 14 }}>Sleeps 5 in three bedrooms (a double and a twin upstairs, a single downstairs), with one bathroom. A cot and baby bath are available on request.</p>
      {open !== null && rooms[open] && <BedroomModal room={rooms[open]} onClose={() => setOpen(null)} />}
    </div>
  );
}

// Full amenities list — read from assets/amenities.json (Decap-editable) on the
// live host; fall back to embedded window.GK_AMENITIES for local file:// previews.
let _amenCache = null, _amenPromise = null;
function loadAmenities() {
  if (_amenCache) return Promise.resolve(_amenCache);
  if (_amenPromise) return _amenPromise;
  _amenPromise = (async () => {
    try {
      const res = await fetch('assets/amenities.json', { cache: 'no-store' });
      if (res.ok) { const d = await res.json(); if (d && Array.isArray(d.groups)) { _amenCache = d.groups; return _amenCache; } }
    } catch (e) { /* fall through */ }
    if (window.GK_AMENITIES && Array.isArray(window.GK_AMENITIES.groups)) { _amenCache = window.GK_AMENITIES.groups; return _amenCache; }
    _amenCache = [];
    return _amenCache;
  })();
  return _amenPromise;
}
function useAmenities() {
  const [groups, setGroups] = useState(_amenCache || []);
  useEffect(() => { let live = true; loadAmenities().then(g => { if (live) setGroups(g); }); return () => { live = false; }; }, []);
  return groups;
}

function AmenitiesModal({ groups, onClose }) {
  const dialogRef = useRef(null);
  useEffect(() => {
    const prev = document.activeElement;
    if (dialogRef.current) dialogRef.current.focus();
    const onKey = (e) => e.key === 'Escape' && onClose();
    window.addEventListener('keydown', onKey);
    if (window.lucide) window.lucide.createIcons();
    return () => { window.removeEventListener('keydown', onKey); if (prev && prev.focus) prev.focus(); };
  }, [onClose, groups]);
  return (
    <div className="overlay" onClick={onClose}>
      <div className="dialog" ref={dialogRef} tabIndex={-1} role="dialog" aria-modal="true" aria-label="What this place offers"
        style={{ position: 'relative', maxWidth: 820, width: '100%', maxHeight: '90vh', overflowY: 'auto', outline: 'none' }}
        onClick={(e) => e.stopPropagation()}>
        <button className="dialog__close" onClick={onClose} aria-label="Close"><i data-lucide="x" style={{ width: 20, height: 20 }}></i></button>
        <div style={{ padding: '30px 32px' }}>
          <Eyebrow>Amenities &amp; services</Eyebrow>
          <h2 className="h3" style={{ margin: '10px 0 22px' }}>What this place offers</h2>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: '26px 32px' }}>
            {groups.map((g) => (
              <div key={g.title}>
                <h3 style={{ fontSize: 13, textTransform: 'uppercase', letterSpacing: '0.06em', color: 'var(--color-primary)', margin: '0 0 10px' }}>{g.title}</h3>
                <ul style={{ listStyle: 'none', padding: 0, margin: 0, display: 'grid', gap: 7 }}>
                  {(g.items || []).map((it) => (
                    <li key={it} style={{ display: 'flex', alignItems: 'flex-start', gap: 8, fontSize: 14.5, color: 'var(--text-body)', lineHeight: 1.4 }}>
                      <i data-lucide="check" style={{ width: 16, height: 16, color: 'var(--color-primary)', flex: '0 0 auto', marginTop: 2 }}></i>{it}
                    </li>
                  ))}
                </ul>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

function Offers() {
  const items = [
    ['Full kitchen', 'utensils-crossed', 'Hob, oven, grill, dishwasher & washing machine'],
    ['Log burner', 'flame', 'Logs provided through the cooler months'],
    ['Free parking', 'square-parking', 'Space for up to three vehicles'],
    ['Wi-Fi included', 'wifi', 'Typically ~45 Mb/sec; the dining room doubles as an office'],
    ['Separate dining room', 'utensils', 'Seats six (or five plus a high chair)'],
    ['Private garden & woodland', 'trees', 'Four acres of woodland to roam'],
    ['Smart TV & books', 'tv', 'For quiet evenings by the fire'],
    ['Security cameras', 'cctv', 'Covering the parking area, never the garden'],
  ];
  const groups = useAmenities();
  const [open, setOpen] = useState(false);
  return (
    <div>
      <h2 className="h3" style={{ marginBottom: 20 }}>What this place offers</h2>
      <div className="gk-stack" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '22px 32px' }}>
        {items.map(([l, ic, d]) => <Amenity key={l} icon={ic} label={l} detail={d} />)}
      </div>
      {groups.length > 0 && (
        <div style={{ marginTop: 22 }}>
          <Button variant="secondary" size="md" onClick={() => setOpen(true)}>View all amenities</Button>
        </div>
      )}
      {open && <AmenitiesModal groups={groups} onClose={() => setOpen(false)} />}
    </div>
  );
}

function Availability() {
  const { openBooking } = useShell();
  const [sel, setSel] = useState({ arrive: '', depart: '' });
  const rates = useRates();
  const avail = useAvailability();
  const quote = quoteStay(sel.arrive, sel.depart, rates);
  const dateError = sel.arrive && sel.depart && sel.depart < sel.arrive;
  const stayAvail = dateError ? null : stayAvailability(sel.arrive, sel.depart, avail);
  useEffect(() => { if (window.lucide) window.lucide.createIcons(); }, [stayAvail, sel.arrive, sel.depart]);
  const pick = (iso) => {
    setSel((s) => (!s.arrive || (s.arrive && s.depart)) ? { arrive: iso, depart: '' }
      : (iso > s.arrive ? { ...s, depart: iso } : { arrive: iso, depart: '' }));
  };
  const fmt = (iso) => iso ? new Date(iso + 'T00:00:00').toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric' }) : '';
  return (
    <section className="section section--soft">
      <div className="container" style={{ textAlign: 'center' }}>
        <div style={{ display: 'flex', justifyContent: 'center' }}><Eyebrow>Availability</Eyebrow></div>
        <h2 className="h2" style={{ margin: '14px 0 8px' }}>Find your dates</h2>
        <p className="muted" style={{ margin: '0 auto 24px', maxWidth: 460 }}>Pick your arrival, then your departure, to see the price and whether the cottage is free.</p>
        <Card padding="md" style={{ display: 'inline-block', textAlign: 'left', maxWidth: 760, width: '100%' }}>
          <MiniCalendar months={2} selStart={sel.arrive} selEnd={sel.depart} onPick={pick} />
          {(sel.arrive || sel.depart) && (
            <div style={{ marginTop: 18, display: 'grid', gap: 10, borderTop: '1px solid var(--border-soft)', paddingTop: 16 }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
                <span style={{ color: 'var(--text-strong)', fontWeight: 600, fontSize: 15 }}>
                  {fmt(sel.arrive) || 'Pick arrival'}{sel.arrive ? (sel.depart ? '  →  ' + fmt(sel.depart) : '  →  pick departure') : ''}
                </span>
                <button onClick={() => setSel({ arrive: '', depart: '' })} style={{ background: 'none', border: 'none', color: 'var(--color-primary)', cursor: 'pointer', fontSize: 13.5, fontWeight: 600 }}>Clear</button>
              </div>
              {dateError && <div role="alert" style={{ background: '#fbeae6', color: '#9f3d2e', borderRadius: 'var(--radius-sm)', padding: '9px 12px', fontSize: 13.5 }}>Your departure date is before your arrival date — please pick a later departure.</div>}
              <AvailabilityNote status={stayAvail} quote={quote} />
              <RateGuide quote={quote} rates={rates} />
            </div>
          )}
        </Card>
        <div style={{ marginTop: 26 }}>
          <Button variant="primary" size="lg" onClick={() => openBooking(sel.arrive ? { arrive: sel.arrive, depart: sel.depart } : undefined)}>Check rates &amp; reserve</Button>
        </div>
      </div>
    </section>
  );
}

function ReviewsStrip() {
  const seed = [
    ['One of the loveliest places we have ever stayed — cosy and characterful, with a stunning garden and an abundance of woodland wildlife.', 'JP', 'Jan 2026', 5],
    ['Such a beautiful, secluded location. We all loved it — just how life should be.', 'Mark Rawlinson', 'Sep 2025', 5],
    ['We saw deer, buzzard and woodpeckers in the wood. I couldn’t recommend it more.', 'William Ripper', 'Apr 2025', 5],
  ];
  const live = useReviews();
  const stats = reviewStats(live);
  const liveQuotes = (live || []).map((r) => [r.body, r.name, reviewMonth(r.date), r.rating || 5]);
  const shown = (liveQuotes.length ? liveQuotes : seed).slice(0, 3);
  return (
    <section className="section">
      <div className="container">
        <div style={{ display: 'flex', alignItems: 'flex-end', gap: 16, marginBottom: 28, flexWrap: 'wrap' }}>
          <div style={{ flex: '1 1 auto', minWidth: 0 }}><Eyebrow>Guest reviews</Eyebrow><h2 className="h2" style={{ margin: '14px 0 0' }}>Loved by our guests</h2></div>
          {stats.count > 0 && <span style={{ flexShrink: 0 }}><Rating value={stats.average} count={stats.count} /></span>}
        </div>
        <div className="grid grid-3">
          {shown.map(([q, who, when, rating], i) => (
            <Card key={i + who} padding="md"><Rating value={rating} showValue={false} /><p style={{ fontFamily: 'var(--font-display)', fontSize: 17.5, lineHeight: 1.55, color: 'var(--text-strong)', margin: '14px 0 16px' }}>“{q}”</p><div style={{ fontSize: 14, color: 'var(--text-muted)' }}><b style={{ color: 'var(--text-strong)' }}>{who}</b>{when ? ' · ' + when : ''}</div></Card>
          ))}
        </div>
        <div style={{ marginTop: 26 }}><Button variant="secondary" size="md" as="a" href="reviews">{stats.count > 0 ? 'Read all ' + stats.count + ' reviews' : 'Read our reviews'}</Button></div>
      </div>
    </section>
  );
}

function MapNearby() {
  const nearby = [
    ['uploads/The-Eels-Foot-Inn.webp', 'the-eels-foot-inn-in-suffolk', 'The Eels Foot Inn', 'A characterful country pub near Minsmere'],
    ['uploads/https___www.southwoldpier.co_.uk_.webp', 'southwold-pier', 'Southwold Pier', 'The classic seaside pier, 20 minutes away'],
    ['uploads/sole-bay-fish-company.webp', 'solebay-fish-company-southwold', 'Solebay Fish Company', 'Fresh-off-the-boat seafood in Southwold'],
  ];
  return (
    <section className="section section--soft">
      <div className="container">
        <Eyebrow>Where you'll be staying</Eyebrow>
        <h2 className="h2" style={{ margin: '14px 0 22px' }}>The Wood, Brampton — near Beccles & Southwold</h2>
        <div style={{ borderRadius: 'var(--radius-lg)', overflow: 'hidden', border: '1px solid var(--border-soft)', boxShadow: 'var(--shadow-sm)' }}>
          <iframe title="Map" width="100%" height="380" style={{ border: 0, display: 'block' }} loading="lazy"
            src="https://www.openstreetmap.org/export/embed.html?bbox=1.40%2C52.34%2C1.66%2C52.46&layer=mapnik&marker=52.398%2C1.531"></iframe>
        </div>
        <p className="muted" style={{ fontSize: 14.5, marginTop: 12 }}>The exact location is shared once your stay is confirmed. The cottage sits down a private drive, completely surrounded by woodland.</p>
        <h3 className="h3" style={{ fontSize: 'var(--fs-h4)', margin: '40px 0 18px' }}>Places to visit nearby</h3>
        <div className="grid grid-3">
          {nearby.map(([src, slug, t, d]) => (
            <a key={t} href={'attraction?slug=' + slug} style={{ textDecoration: 'none' }}><Card interactive><Photo src={src} ratio="16 / 10" /><div style={{ padding: 'var(--space-5)' }}><b style={{ fontFamily: 'var(--font-display)', fontSize: 18, color: 'var(--text-strong)' }}>{t}</b><p className="muted" style={{ margin: '4px 0 0', fontSize: 15 }}>{d}</p></div></Card></a>
          ))}
        </div>
      </div>
    </section>
  );
}

function AboutNick() {
  const { openBooking } = useShell();
  return (
    <section className="section">
      <div className="container gk-stack" style={{ display: 'grid', gridTemplateColumns: '0.8fr 1.2fr', gap: 48, alignItems: 'center' }}>
        <Photo src={IMG.garden3} ratio="4 / 5" radius="var(--radius-lg)" />
        <div>
          <Eyebrow>Your hosts</Eyebrow>
          <h2 className="h2" style={{ margin: '14px 0 16px' }}>Hi, I'm Nick — the owner</h2>
          <p style={{ lineHeight: 1.75, margin: '0 0 14px' }}>This was my family home as a teenager, and we look after the cottage ourselves. We keep it more like a home than a rental, and we love sharing the wood with our guests. Please don't hesitate to get in touch — I'll gladly answer any questions before you book.</p>
          <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', marginTop: 8 }}>
            <Button variant="primary" size="md" onClick={openBooking}>Check rates &amp; reserve</Button>
            <Button variant="secondary" size="md" as="a" href="contact">Contact us</Button>
          </div>
        </div>
      </div>
    </section>
  );
}

function RateCardModal({ rates, onClose }) {
  const dialogRef = useRef(null);
  useEffect(() => {
    const prev = document.activeElement;
    if (dialogRef.current) dialogRef.current.focus();
    const onKey = (e) => e.key === 'Escape' && onClose();
    window.addEventListener('keydown', onKey);
    if (window.lucide) window.lucide.createIcons();
    return () => { window.removeEventListener('keydown', onKey); if (prev && prev.focus) prev.focus(); };
  }, [onClose]);
  const avail = useAvailability();
  const cur = (rates && rates.currency) || '£';
  const periods = visibleRatePeriods ? visibleRatePeriods(rates, avail) : ((rates && rates.periods) || []);
  const price = (p) => (p.available === false || p.price == null) ? 'On request' : cur + Number(p.price).toLocaleString('en-GB') + (p.unit === 'stay' ? '' : '/week');
  return (
    <div className="overlay" onClick={onClose}>
      <div className="dialog" ref={dialogRef} tabIndex={-1} role="dialog" aria-modal="true" aria-label="Full rate card"
        style={{ position: 'relative', maxWidth: 620, width: '100%', maxHeight: '90vh', overflowY: 'auto', outline: 'none' }}
        onClick={(e) => e.stopPropagation()}>
        <button className="dialog__close" onClick={onClose} aria-label="Close"><i data-lucide="x" style={{ width: 20, height: 20 }}></i></button>
        <div style={{ padding: '30px 32px' }}>
          <Eyebrow>Pricing</Eyebrow>
          <h2 className="h3" style={{ margin: '10px 0 8px' }}>Full rate card</h2>
          {rates && rates.intro && <p className="muted" style={{ fontSize: 13.5, margin: '0 0 16px', lineHeight: 1.6 }}>{rates.intro}</p>}
          <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>
            {periods.map((p, i) => (
              <li key={i} style={{ display: 'flex', justifyContent: 'space-between', gap: 16, padding: '10px 0', borderBottom: '1px solid var(--border-soft)', fontSize: 14.5 }}>
                <span style={{ color: 'var(--text-body)' }}>{p.label}</span>
                <b style={{ fontFamily: 'var(--font-display)', color: p.available === false ? 'var(--text-muted)' : 'var(--text-strong)', whiteSpace: 'nowrap' }}>{price(p)}</b>
              </li>
            ))}
          </ul>
        </div>
      </div>
    </div>
  );
}

function Pricing() {
  const rates = useRates();
  const [open, setOpen] = useState(false);
  const rows = [
    ['Short breaks (3+ nights)', 'From £140 per night'],
    ['Low season week', '£588 per week'],
    ['Mid season week', '£686 per week'],
    ['High season week', '£900 per week'],
    ['Christmas & New Year', 'On request'],
  ];
  return (
    <section className="section section--soft">
      <div className="container container--narrow">
        <Eyebrow>Pricing</Eyebrow>
        <h2 className="h2" style={{ margin: '14px 0 8px' }}>Pricing information</h2>
        <p className="muted" style={{ marginBottom: 22 }}>Prices are for the whole cottage, sleeping up to five. A minimum of three nights applies. Linen, towels, Wi-Fi and parking are all included.</p>
        <Card padding="none">
          {rows.map(([a, b], i) => (
            <div key={a} className="ratestrip-row" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 16, padding: '16px 24px', borderTop: i ? '1px solid var(--border-soft)' : 'none' }}>
              <span style={{ color: 'var(--text-body)' }}>{a}</span>
              <b style={{ fontFamily: 'var(--font-display)', color: 'var(--text-strong)', textAlign: 'right', whiteSpace: 'nowrap' }}>{b}</b>
            </div>
          ))}
        </Card>
        {rates && rates.periods && rates.periods.length > 0 && (
          <div style={{ marginTop: 16 }}>
            <button onClick={() => setOpen(true)} style={{ background: 'none', border: 'none', padding: 0, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6, color: 'var(--color-primary)', fontSize: 14.5, fontWeight: 600 }}>
              See the full rate card <i data-lucide="arrow-right" style={{ width: 15, height: 15 }}></i>
            </button>
          </div>
        )}
      </div>
      {open && <RateCardModal rates={rates} onClose={() => setOpen(false)} />}
    </section>
  );
}

// Guest-info panels — read from assets/guestinfo.json (Decap-editable) on the live
// host; fall back to embedded window.GK_GUESTINFO for local file:// previews.
let _giCache = null, _giPromise = null;
function loadGuestInfo() {
  if (_giCache) return Promise.resolve(_giCache);
  if (_giPromise) return _giPromise;
  _giPromise = (async () => {
    try {
      const res = await fetch('assets/guestinfo.json', { cache: 'no-store' });
      if (res.ok) { const d = await res.json(); if (d && Array.isArray(d.panels)) { _giCache = d.panels; return _giCache; } }
    } catch (e) { /* fall through */ }
    if (window.GK_GUESTINFO && Array.isArray(window.GK_GUESTINFO.panels)) { _giCache = window.GK_GUESTINFO.panels; return _giCache; }
    _giCache = [];
    return _giCache;
  })();
  return _giPromise;
}
function useGuestInfo() {
  const [panels, setPanels] = useState(_giCache || []);
  useEffect(() => { let live = true; loadGuestInfo().then(p => { if (live) setPanels(p); }); return () => { live = false; }; }, []);
  return panels;
}

function InfoModal({ panel, onClose }) {
  const dialogRef = useRef(null);
  useEffect(() => {
    const prev = document.activeElement;
    if (dialogRef.current) dialogRef.current.focus();
    const onKey = (e) => e.key === 'Escape' && onClose();
    window.addEventListener('keydown', onKey);
    if (window.lucide) window.lucide.createIcons();
    return () => { window.removeEventListener('keydown', onKey); if (prev && prev.focus) prev.focus(); };
  }, [onClose, panel]);
  if (!panel) return null;
  return (
    <div className="overlay" onClick={onClose}>
      <div className="dialog" ref={dialogRef} tabIndex={-1} role="dialog" aria-modal="true" aria-label={panel.title}
        style={{ position: 'relative', maxWidth: 640, width: '100%', maxHeight: '90vh', overflowY: 'auto', outline: 'none' }}
        onClick={(e) => e.stopPropagation()}>
        <button className="dialog__close" onClick={onClose} aria-label="Close"><i data-lucide="x" style={{ width: 20, height: 20 }}></i></button>
        <div style={{ padding: '30px 32px' }}>
          <Eyebrow>Good to know</Eyebrow>
          <h2 className="h3" style={{ margin: '10px 0 10px' }}>{panel.title}</h2>
          {panel.intro && <p className="muted" style={{ margin: '0 0 20px', lineHeight: 1.6 }}>{panel.intro}</p>}
          {(panel.groups || []).map((g, gi) => (
            <div key={gi} style={{ marginBottom: 18 }}>
              {g.heading && <h3 style={{ fontSize: 13, textTransform: 'uppercase', letterSpacing: '0.06em', color: 'var(--color-primary)', margin: '0 0 10px' }}>{g.heading}</h3>}
              <ul style={{ listStyle: 'none', padding: 0, margin: 0, display: 'grid', gap: 8 }}>
                {(g.items || []).map((it, ii) => (
                  <li key={ii} style={{ display: 'flex', alignItems: 'flex-start', gap: 9, fontSize: 15, color: 'var(--text-body)', lineHeight: 1.5 }}>
                    <i data-lucide="check" style={{ width: 17, height: 17, color: 'var(--color-primary)', flex: '0 0 auto', marginTop: 2 }}></i>{it}
                  </li>
                ))}
              </ul>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function GuestInfo() {
  const panels = useGuestInfo();
  const [open, setOpen] = useState(null);
  useEffect(() => { if (window.lucide) window.lucide.createIcons(); }, [panels, open]);
  if (!panels.length) return null;
  return (
    <section className="section">
      <div className="container">
        <Eyebrow>Good to know</Eyebrow>
        <h2 className="h2" style={{ margin: '14px 0 28px' }}>Guest information</h2>
        <div className="grid grid-3">
          {panels.map((p, i) => (
            <Card key={p.key || i} padding="md">
              <span style={{ width: 44, height: 44, borderRadius: 999, background: 'var(--accent-fern)', color: 'var(--color-primary)', display: 'grid', placeItems: 'center', marginBottom: 14 }}><i data-lucide={p.icon || 'info'} style={{ width: 21, height: 21 }}></i></span>
              <h3 className="h3" style={{ fontSize: 'var(--fs-h4)', marginBottom: 8 }}>{p.title}</h3>
              {p.teaser && <p className="muted" style={{ margin: '0 0 12px', fontSize: 15 }}>{p.teaser}</p>}
              {Array.isArray(p.highlights) && p.highlights.length > 0 && (
                <ul style={{ listStyle: 'none', padding: 0, margin: '0 0 14px', display: 'grid', gap: 7 }}>
                  {p.highlights.slice(0, 3).map((h, hi) => (
                    <li key={hi} style={{ display: 'flex', alignItems: 'flex-start', gap: 8, fontSize: 14.5, color: 'var(--text-body)', lineHeight: 1.45 }}>
                      <i data-lucide="check" style={{ width: 16, height: 16, color: 'var(--color-primary)', flex: '0 0 auto', marginTop: 2 }}></i>{h}
                    </li>
                  ))}
                </ul>
              )}
              <button onClick={() => setOpen(i)} style={{ background: 'none', border: 'none', padding: 0, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6, color: 'var(--color-primary)', fontSize: 14.5, fontWeight: 600 }}>
                View details <i data-lucide="arrow-right" style={{ width: 15, height: 15 }}></i>
              </button>
            </Card>
          ))}
        </div>
      </div>
      {open !== null && panels[open] && <InfoModal panel={panels[open]} onClose={() => setOpen(null)} />}
    </section>
  );
}

function CottageContent() {
  return (
    <React.Fragment>
      <GalleryBand />
      <section className="section--tight" style={{ paddingTop: 48 }}>
        <div className="container gk-stack" style={{ display: 'grid', gridTemplateColumns: 'minmax(0,1fr) 360px', gap: 56, alignItems: 'start' }}>
          <div style={{ display: 'grid', gap: 44 }}>
            <div>
              <h2 className="h3" style={{ marginBottom: 14 }}>A cosy woodland home, all to yourselves</h2>
              <p style={{ lineHeight: 1.75, margin: '0 0 14px' }}>The original Gamekeeper's Cottage sits in the middle of a hundred-acre wood, in a wonderfully secluded position with four acres of private woodland attached. It's warm, homely and full of character — and for the length of your stay, the wood is yours.</p>
              <p style={{ lineHeight: 1.75, margin: 0 }}>Inside there's a well-equipped kitchen, a cosy sitting room with a log burner and a separate dining room. Outside, a generous garden gives way to woodland walks, with feeders that bring deer, pheasants, owls and woodpeckers close to the windows.</p>
            </div>
            <Highlights />
            <hr className="divider" />
            <VideoTour />
            <hr className="divider" />
            <Sleeping />
            <hr className="divider" />
            <Offers />
          </div>
          <BookCard />
        </div>
      </section>
      <Availability />
      <ReviewsStrip />
      <MapNearby />
      <AboutNick />
      <Pricing />
      <GuestInfo />
    </React.Fragment>
  );
}

window.GKmount('cottage', CottageContent);
