/* Casa Laudieri — main app */

const { useState: useAppState, useEffect: useAppEffect } = React;

/* Map our internal apartment ids → Smoobu apartment ids.
   Fill these in from the Smoobu dashboard to preselect an apartment in the
   booking tool. Left empty = booking tool opens showing all apartments. */
const SMOOBU_APT_IDS = {
  plose: 3341847,
  koenigsanger: 3341852,
  jochtal: 3341857
};

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "bone",
  "typeset": "serif-display",
  "language": "en",
  "mapLat": 46.71362,
  "mapLng": 11.65426
} /*EDITMODE-END*/;

/* ---------------- URL routing ----------------
   Each page maps to a clean path. The area detail pages live under
   /area/<item-id> (e.g. /area/hiking). Home is the root "/".
   vercel.json rewrites every path to index.html so these resolve on deploy. */
const PATH_BY_PAGE = {
  home: '/',
  apartments: '/apartments',
  area: '/area',
  story: '/story',
  contact: '/visit',
  'find-us': '/findus',
  faq: '/faq',
  'house-manual': '/manual',
  vouchers: '/vouchers',
  press: '/press',
  imprint: '/imprint',
  privacy: '/privacy',
  cookies: '/cookies',
  terms: '/terms',
  booked: '/booked'
};
const PAGE_BY_PATH = {};
Object.keys(PATH_BY_PAGE).forEach((p) => {PAGE_BY_PATH[PATH_BY_PAGE[p]] = p;});
PAGE_BY_PATH['/home'] = 'home'; // accept /home as an alias for root

const LANGS = ['en', 'it', 'de'];
const DEFAULT_LANG = 'en';

/* Parse /<lang>/<page...> — e.g. /de/faq, /it/area/hiking, /en (home).
   A missing or unknown leading segment falls back to the default language. */
function parseRoute() {
  let path = window.location.pathname || '/';
  if (path.length > 1 && path.endsWith('/')) path = path.slice(0, -1);
  const segs = path.split('/').filter(Boolean);
  let lang = DEFAULT_LANG;
  if (segs.length && LANGS.indexOf(segs[0]) !== -1) lang = segs.shift();
  let page = 'home',areaId = null;
  if (segs[0] === 'area' && segs[1]) {
    page = 'area-detail';
    areaId = decodeURIComponent(segs.slice(1).join('/'));
  } else {
    const rest = '/' + segs.join('/');
    page = PAGE_BY_PATH[rest === '/' ? '/' : rest] || 'home';
  }
  return { lang, page, areaId };
}

function pathForState(lang, page, areaItem) {
  const sub = page === 'area-detail' && areaItem ? '/area/' + areaItem.id : PATH_BY_PAGE[page] || '/';
  const base = '/' + (lang || DEFAULT_LANG);
  return sub === '/' ? base : base + sub;
}

function App() {
  const [tw, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const initialRoute = parseRoute();
  const [page, setPage] = useAppState(initialRoute.page);
  const [lang, setLang] = useAppState(initialRoute.lang);
  const [openAptModal, setOpenAptModal] = useAppState(null);
  const [bookingDates, setBookingDates] = useAppState(null);
  const [areaItem, setAreaItem] = useAppState(initialRoute.areaId ? { id: initialRoute.areaId } : null);
  const [smoobuOpen, setSmoobuOpen] = useAppState(false);
  const [smoobuParams, setSmoobuParams] = useAppState(null);

  /* Any link pointing off casalaudieri.com opens in a new tab, so a visitor
     never loses the site. Applied after each render rather than per-link, so
     links added later (including by hand) are covered automatically.
     rel="noopener noreferrer" is required with target="_blank": without it the
     opened page can reach back into this one via window.opener. */
  useAppEffect(() => {
    const here = window.location.hostname;
    document.querySelectorAll('a[href]').forEach((el) => {
      const href = el.getAttribute('href') || '';
      if (!/^https?:/i.test(href)) return; // relative, mailto:, tel: stay put
      let host = '';
      try { host = new URL(href, window.location.href).hostname; } catch (e) { return; }
      if (!host || host === here || host.endsWith('casalaudieri.com')) return;
      el.setAttribute('target', '_blank');
      el.setAttribute('rel', 'noopener noreferrer');
    });
  }, [page, lang, areaItem]);

  // Persist the URL-chosen language into the tweak store on load.
  useAppEffect(() => {if (tw.language !== lang) setTweak('language', lang);}, [lang]);

  // Keep the URL in sync with language + page (pushState, no reload).
  useAppEffect(() => {
    const path = pathForState(lang, page, areaItem);
    if (window.location.pathname !== path) {
      window.history.pushState({ lang, page, areaId: areaItem && areaItem.id }, '', path);
    }
  }, [lang, page, areaItem]);

  // Keep <html lang> and the document title in sync for SEO and accessibility.
  useAppEffect(() => {
    document.documentElement.lang = lang || DEFAULT_LANG;
    const SITE = 'Casa Laudieri';
    let section = '';
    if (page === 'area-detail' && areaItem) {
      const it = t.area && t.area.items.find((x) => x.id === areaItem.id);
      section = it && it.t;
    } else {
      const map = {
        home: t.hero && t.hero.tagline, apartments: t.apartments && t.apartments.title,
        area: t.area && t.area.title, story: t.story && t.story.title,
        contact: t.contact && t.contact.title, 'find-us': t.findus && t.findus.title,
        faq: t.faq && t.faq.title, imprint: t.imprint && t.imprint.title,
        privacy: t.privacy && t.privacy.title, cookies: t.cookies && t.cookies.title,
        terms: t.terms && t.terms.title, 'house-manual': t.housemanual && t.housemanual.title,
        vouchers: t.vouchers && t.vouchers.title, press: t.presspage && t.presspage.title
      };
      section = map[page];
    }
    section = (section || '').replace(/[.\s]+$/, '');
    document.title = page === 'home' || !section ? SITE + ' · Apartments in Brixen, South Tyrol' : section + ' · ' + SITE;

    // ----- Per-route SEO meta (description, canonical, Open Graph, Twitter) -----
    const setMeta = (sel, attr, val) => {
      let el = document.head.querySelector(sel);
      if (!el) {
        el = document.createElement('meta');
        const m = sel.match(/\[(name|property)="([^"]+)"\]/);
        if (m) el.setAttribute(m[1], m[2]);
        document.head.appendChild(el);
      }
      el.setAttribute(attr, val);
    };
    // Description: prefer the page's own lede/intro, fall back to the site default.
    let desc = '';
    if (page === 'area-detail' && areaItem) {
      const it = t.area && t.area.items.find((x) => x.id === areaItem.id);
      desc = it && it.detail && it.detail.intro || it && it.d || '';
    } else {
      const ledeMap = {
        home: t.hero && t.hero.sub, apartments: t.apartments && t.apartments.lede,
        area: t.area && t.area.lede, story: t.story && t.story.lede,
        contact: t.contact && t.contact.lede, faq: t.faq && t.faq.lede,
        terms: t.terms && t.terms.lede, privacy: t.privacy && t.privacy.lede,
        cookies: t.cookies && t.cookies.lede, imprint: t.imprint && t.imprint.lede,
        vouchers: t.vouchers && t.vouchers.lede, press: t.presspage && t.presspage.lede,
        'house-manual': t.housemanual && t.housemanual.lede, 'find-us': t.findus && t.findus.lede
      };
      desc = ledeMap[page] || '';
    }
    const SITE_DESC = 'Casa Laudieri. Three apartments in a quietly restored Jugendstil house in the old quarter of Brixen (Bressanone), South Tyrol, at the foot of the Plose and the Dolomites.';
    desc = (desc || SITE_DESC).replace(/\s+/g, ' ').trim();
    if (desc.length > 300) desc = desc.slice(0, 297).trim() + '…';

    const canonical = 'https://www.casalaudieri.com' + pathForState(lang, page, areaItem);
    const ogLocale = lang === 'it' ? 'it_IT' : lang === 'de' ? 'de_DE' : 'en_GB';

    setMeta('meta[name="description"]', 'content', desc);
    setMeta('meta[property="og:title"]', 'content', document.title);
    setMeta('meta[property="og:description"]', 'content', desc);
    setMeta('meta[property="og:url"]', 'content', canonical);
    setMeta('meta[property="og:locale"]', 'content', ogLocale);
    setMeta('meta[name="twitter:title"]', 'content', document.title);
    setMeta('meta[name="twitter:description"]', 'content', desc);

    let link = document.head.querySelector('link[rel="canonical"]');
    if (!link) {link = document.createElement('link');link.setAttribute('rel', 'canonical');document.head.appendChild(link);}
    link.setAttribute('href', canonical);

    // ----- Per-route structured data (FAQPage / Apartment) -----
    // Injected as one JSON-LD <script>; regenerated on each route change and read
    // by Google when it renders the page. Content comes from content.js, so all
    // three languages stay in sync automatically.
    let ld = document.head.querySelector('script#route-jsonld');
    const setLd = (obj) => {
      if (!obj) { if (ld) { ld.remove(); } return; }
      if (!ld) {
        ld = document.createElement('script');
        ld.type = 'application/ld+json';
        ld.id = 'route-jsonld';
        document.head.appendChild(ld);
      }
      ld.textContent = JSON.stringify(obj);
    };
    const ORIGIN = 'https://www.casalaudieri.com';
    const num = (s) => { const m = String(s == null ? '' : s).match(/\d+/); return m ? parseInt(m[0], 10) : undefined; };
    const range = (s) => { const m = String(s == null ? '' : s).match(/(\d+)\D+(\d+)/); return m ? { min: +m[1], max: +m[2] } : null; };

    if (page === 'faq' && t.faq && Array.isArray(t.faq.items)) {
      setLd({
        '@context': 'https://schema.org',
        '@type': 'FAQPage',
        inLanguage: lang || DEFAULT_LANG,
        mainEntity: t.faq.items.filter((it) => it && it.q).map((it) => ({
          '@type': 'Question',
          name: it.q,
          acceptedAnswer: { '@type': 'Answer', text: String(it.a || '').replace(/\s+/g, ' ').trim() }
        }))
      });
    } else if (page === 'apartments' && t.apartments && Array.isArray(t.apartments.list)) {
      const IMG = { plose: 'apt-plose.jpg', koenigsanger: 'apt-koenigsanger.jpg', jochtal: 'apt-jochtal.jpg' };
      setLd({
        '@context': 'https://schema.org',
        '@graph': t.apartments.list.map((a) => {
          const occ = range(a.sleeps);
          const size = num(a.size);
          const price = num(a.price);
          const node = {
            '@type': 'Apartment',
            name: a.name,
            description: String(a.desc || '').replace(/\s+/g, ' ').trim(),
            inLanguage: lang || DEFAULT_LANG,
            url: canonical,
            containedInPlace: { '@id': ORIGIN + '/#lodging' }
          };
          if (IMG[a.id]) node.image = ORIGIN + '/' + IMG[a.id];
          const beds = num(a.bedrooms); if (beds != null) node.numberOfBedrooms = beds;
          if (occ) node.occupancy = { '@type': 'QuantitativeValue', minValue: occ.min, maxValue: occ.max };
          if (size != null) node.floorSize = { '@type': 'QuantitativeValue', value: size, unitCode: 'MTK' };
          if (Array.isArray(a.amenities)) node.amenityFeature = a.amenities.map((n) => ({ '@type': 'LocationFeatureSpecification', name: n, value: true }));
          if (price != null) node.potentialAction = {
            '@type': 'ReserveAction',
            target: ORIGIN + pathForState(lang, 'contact', null),
            priceSpecification: { '@type': 'PriceSpecification', minPrice: price, priceCurrency: 'EUR' }
          };
          return node;
        })
      });
    } else if (page === 'area-detail' && areaItem && t.area) {
      /* Matches the visible trail on the page, which Google requires. */
      const it = t.area.items.find((x) => x.id === areaItem.id);
      setLd(it ? {
        '@context': 'https://schema.org',
        '@type': 'BreadcrumbList',
        itemListElement: [
          { '@type': 'ListItem', position: 1, name: t.nav.home, item: ORIGIN + pathForState(lang, 'home', null) },
          { '@type': 'ListItem', position: 2, name: t.nav.area, item: ORIGIN + pathForState(lang, 'area', null) },
          { '@type': 'ListItem', position: 3, name: it.t, item: canonical }
        ]
      } : null);
    } else if (page === 'home' && t.reviews && Array.isArray(t.reviews.items)) {
      /* Review schema. Google requires reviews to be genuine, attributed and
         visible on the same page — these are, and they render in section 04.
         No aggregateRating: Google only shows stars for one where the count is
         verifiable, and inventing one risks a manual penalty. */
      const revs = t.reviews.items.filter((r) => r && r.q && r.name);
      setLd(revs.length ? {
        '@context': 'https://schema.org',
        '@type': 'LodgingBusiness',
        '@id': ORIGIN + '/#lodging',
        name: 'Casa Laudieri',
        url: canonical,
        review: revs.map((r) => ({
          '@type': 'Review',
          reviewBody: String(r.q).replace(/\s+/g, ' ').trim(),
          author: { '@type': 'Person', name: r.name },
          itemReviewed: { '@type': 'Apartment', name: r.from || 'Casa Laudieri' },
          reviewRating: {
            '@type': 'Rating',
            ratingValue: String(r.stars || '').replace(/[^⋆★]/g, '').length || 5,
            bestRating: 5,
            worstRating: 1
          }
        }))
      } : null);
    } else {
      setLd(null);
    }
  }, [lang, page, areaItem, t]);

  // Respond to browser back/forward.
  useAppEffect(() => {
    window.history.replaceState({ lang, page, areaId: areaItem && areaItem.id }, '', pathForState(lang, page, areaItem));
    const onPop = () => {
      const r = parseRoute();
      setLang(r.lang);
      setPage(r.page);
      setAreaItem(r.areaId ? { id: r.areaId } : null);
    };
    window.addEventListener('popstate', onPop);
    return () => window.removeEventListener('popstate', onPop);
  }, []);


  useAppEffect(() => {
    document.documentElement.setAttribute('data-palette', tw.palette || 'bone');
    document.documentElement.setAttribute('data-type', tw.typeset || 'serif-display');
  }, [tw.palette, tw.typeset]);

  useAppEffect(() => {
    if (window.location.hash === '#newsletter') {
      setTimeout(() => {
        const el = document.getElementById('newsletter');
        if (el) {
          const y = el.getBoundingClientRect().top + window.pageYOffset - 120;
          window.scrollTo({ top: y, behavior: 'smooth' });
        }
      }, 300);
    } else {
      window.scrollTo(0, 0);
    }
  }, [page]);

  const t = window.CONTENT[lang] || window.CONTENT.en;

  const changeLang = (l) => {
    setLang(l);
    setTweak('language', l);
  };

  const openApt = (apt) => setOpenAptModal(apt);
  const openAreaItem = (item) => {
    // Use the id to look up the current-language version of the item so it
    // stays translated when the user switches language mid-flow.
    setAreaItem(item);
    setPage('area-detail');
  };
  // Open the live Smoobu booking tool. Accepts either an apartment id string,
  // or a full selection object { apt, checkin, checkout, guests } from the
  // booking bar — the dates/guests are forwarded into the Smoobu iframe URL.
  const openSmoobu = (opts) => {
    const sel = typeof opts === 'string' ? { apt: opts } : opts || {};
    setSmoobuParams({
      apartmentId: sel.apt && sel.apt !== 'any' ? SMOOBU_APT_IDS[sel.apt] || null : null,
      arrival: sel.checkin || null,
      departure: sel.checkout || null,
      adults: sel.guests || null
    });
    setSmoobuOpen(true);
  };
  const onBook = (dates) => openSmoobu(dates || {});

  const onHero = page === 'home';

  const SKIP = { en: 'Skip to content', it: 'Vai al contenuto', de: 'Zum Inhalt springen' };

  return (
    <>
      <a className="skip-link" href="#main">{SKIP[lang] || SKIP.en}</a>
      <Nav page={page === 'area-detail' ? 'area' : page} setPage={setPage} lang={lang} setLang={changeLang} t={t} onHero={onHero} onBook={() => openSmoobu({})} />
      <div id="main" tabIndex={-1}></div>

      {page === 'home' && <HomePage t={t} lang={lang} setPage={setPage} openApt={openApt} onBook={onBook} openAreaItem={openAreaItem} />}
      {page === 'apartments' && <ApartmentsPage t={t} openApt={openApt} onBook={onBook} />}
      {page === 'area' && <AreaPage t={t} openAreaItem={openAreaItem} />}
      {page === 'area-detail' && <AreaDetailPage t={t} item={areaItem && t.area.items.find((it) => it.id === areaItem.id)} onBack={() => setPage('area')} lang={lang} setPage={setPage} />}
      {page === 'story' && <StoryPage t={t} />}
      {page === 'contact' && <ContactPage t={t} tw={tw} setTweak={setTweak} setPage={setPage} lang={lang} />}
      {page === 'find-us' && <FindUsPage t={t} tw={tw} setTweak={setTweak} onBack={() => setPage('home')} />}
      {page === 'faq' && <FaqPage t={t} onBack={() => setPage('home')} />}
      {page === 'imprint' && <LegalPage pageData={t.imprint} onBack={() => setPage('home')} backLabel={t.findus?.back} />}
      {page === 'privacy' && <LegalPage pageData={t.privacy} onBack={() => setPage('home')} backLabel={t.findus?.back} />}
      {page === 'cookies' && <LegalPage pageData={t.cookies} onBack={() => setPage('home')} backLabel={t.findus?.back} />}
      {page === 'terms' && <LegalPage pageData={t.terms} onBack={() => setPage('home')} backLabel={t.findus?.back} />}
      {page === 'house-manual' && <LegalPage pageData={t.housemanual} onBack={() => setPage('home')} backLabel={t.findus?.back} />}
      {page === 'vouchers' && <LegalPage pageData={t.vouchers} onBack={() => setPage('home')} backLabel={t.findus?.back} />}
      {page === 'press' && <LegalPage pageData={t.presspage} onBack={() => setPage('home')} backLabel={t.findus?.back} />}
      {page === 'booked' && <BookedPage t={t} setPage={setPage} />}

      <Footer t={t} setPage={setPage} lang={lang} />

      <CookieBanner t={t} setPage={setPage} lang={lang} />

      <ApartmentModal apt={openAptModal} lang={lang} t={t} open={!!openAptModal} onClose={() => setOpenAptModal(null)} onReserve={(apt) => {setOpenAptModal(null);openSmoobu(apt && apt.id);}} />

      <SmoobuModal open={smoobuOpen} onClose={() => setSmoobuOpen(false)} lang={lang} t={t} params={smoobuParams} />

      <CasaTweaks tw={tw} setTweak={setTweak} setLang={setLang} />
    </>);

}

function CasaTweaks({ tw, setTweak, setLang }) {
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="Palette">
        <TweakColor
          label="Mood"
          value={tw.palette === 'bone' ? ['#FAF6EF', '#6B5544', '#2A2622'] :
          tw.palette === 'stone' ? ['#EFEDE8', '#4D5358', '#232628'] :
          tw.palette === 'forest' ? ['#ECEAE2', '#3B4A3B', '#1E2620'] :
          ['#1A1714', '#D4B896', '#F0E9DC']}
          options={[
          ['#FAF6EF', '#6B5544', '#2A2622'],
          ['#EFEDE8', '#4D5358', '#232628'],
          ['#ECEAE2', '#3B4A3B', '#1E2620'],
          ['#1A1714', '#D4B896', '#F0E9DC']]
          }
          onChange={(v) => {
            const map = {
              '#faf6ef': 'bone',
              '#efede8': 'stone',
              '#eceae2': 'forest',
              '#1a1714': 'ink'
            };
            const hero = String(v[0]).toLowerCase();
            setTweak('palette', map[hero] || 'bone');
          }} />
        
      </TweakSection>

      <TweakSection label="Typography">
        <TweakRadio
          label="Pairing"
          value={tw.typeset}
          onChange={(v) => setTweak('typeset', v)}
          options={[
          { value: 'serif-display', label: 'Mix' },
          { value: 'all-serif', label: 'Serif' },
          { value: 'modern-sans', label: 'Sans' }]
          } />
        
      </TweakSection>

      <TweakSection label="Language">
        <TweakRadio
          label="Locale"
          value={tw.language}
          onChange={(v) => {setTweak('language', v);setLang(v);}}
          options={[
          { value: 'en', label: 'EN' },
          { value: 'it', label: 'IT' },
          { value: 'de', label: 'DE' }]
          } />
        
      </TweakSection>

      <TweakSection label="Map pin">
        <TweakNumber
          label="Lat"
          value={tw.mapLat}
          step={0.0001}
          min={-90}
          max={90}
          unit="°"
          onChange={(v) => setTweak('mapLat', v)} />
        
        <TweakNumber
          label="Lng"
          value={tw.mapLng}
          step={0.0001}
          min={-180}
          max={180}
          unit="°"
          onChange={(v) => setTweak('mapLng', v)} />
        
        <div style={{ fontSize: 13, opacity: 0.55, marginTop: 4, lineHeight: 1.4 }}>
          Or drag the pin on the Visit page. It saves automatically.
        </div>
      </TweakSection>
    </TweaksPanel>);

}

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