/* global React, ReactDOM, Icon, CustomCursor, Nav, HomePage, ServicesPage, RentalsPage, ReferencePage, AboutPage, ContactPage, PrivacyPage,
   FeedbackPage, CrewOnboardingPage, ConsignorPortalPage, QuotesAdminPage, TweaksPanel, useTweaks, TweakSection, TweakRadio, TweakToggle, WORK, slugForWork */
const { useState, useEffect } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "heroVariant": "reel",
  "customCursor": false,
  "waveDividers": false
}/*EDITMODE-END*/;

const PAGES = ['home', 'services', 'rentals', 'about', 'contact', 'privacy'];
// 'contact' is kept for backward-compat — visitors landing on the
// legacy /rentals/contact URL are silently redirected to /rentals/about
// in parseLocation below.
const RENTALS_SUB_PAGES = ['equipment', 'about', 'contact', 'open-account', 'careers', 'consignments', 'account-update'];

// Default location shape so every parseLocation return-path stays in sync.
const EMPTY_LOC = { page: 'home', workSlug: null, rentalsSection: null, referenceToken: null, consignmentToken: null };

// Path-based routing. Productions live at /work/:slug and are rendered as a
// modal over the home page, so { page: 'home', workSlug: '...' } is a valid
// state. Rentals has nested sub-routes /rentals/<sub> for equipment, faqs,
// contact, open-account, consignments (admin). /reference/<token> is the
// referee response form linked from emails sent during the open-account
// flow. /consignments/<token> is the read-only consignor portal — a
// per-consignor signed link they receive by email.
const parseLocation = () => {
  const path = (window.location.pathname || '/').replace(/\/+$/, '') || '/';
  if (path === '/') return { ...EMPTY_LOC };
  const m = path.match(/^\/work\/([^/]+)$/);
  if (m) return { ...EMPTY_LOC, workSlug: m[1] };
  const r = path.match(/^\/rentals\/([^/]+)$/);
  if (r) {
    // Legacy /rentals/contact → /rentals/about. Rewrite the URL bar
    // so the back button doesn't bounce them onto the old path.
    let sub = RENTALS_SUB_PAGES.includes(r[1]) ? r[1] : null;
    if (sub === 'contact') {
      try { window.history.replaceState(null, '', '/rentals/about'); } catch (e) { /* */ }
      sub = 'about';
    }
    return { ...EMPTY_LOC, page: 'rentals', rentalsSection: sub };
  }
  const ref = path.match(/^\/reference\/(.+)$/);
  if (ref) return { ...EMPTY_LOC, page: 'reference', referenceToken: ref[1] };
  // /consignments/<token> — direct token-gated portal access. Long
  // URL-safe HMAC-signed token; matches `.+` (base64url chars include
  // `-` and `_`).
  // /consignments (no token) — session-gated portal access; the
  // consignor signs in at /rentals/consignments first.
  const cons = path.match(/^\/consignments\/(.+)$/);
  if (cons) return { ...EMPTY_LOC, page: 'consignor-portal', consignmentToken: cons[1] };
  if (path === '/consignments') return { ...EMPTY_LOC, page: 'consignor-portal' };
  // /crew/onboard — semi-hidden crew roster signup. Only this one
  // sub-path is recognised today; anything else under /crew/* falls
  // through to home.
  if (path === '/crew/onboard') return { ...EMPTY_LOC, page: 'crew' };
  // /emails — internal reference page showing every applicant-facing
  // email the site sends, rendered with sample data. noindex.
  if (path === '/emails') return { ...EMPTY_LOC, page: 'emails' };
  // /prep-tech — Prep Tech HUB. Public landing with two cards:
  // "Apply" (new techs) and "Portal" (existing techs).
  // /prep-tech/portal — the magic-link-gated staff portal itself.
  // Old URL `/rentals/kit-tech-portal` permanent-redirects to
  // /prep-tech/portal via vercel.json.
  if (path === '/prep-tech') return { ...EMPTY_LOC, page: 'prep-tech' };
  if (path === '/prep-tech/portal') return { ...EMPTY_LOC, page: 'prep-tech-portal' };
  // /quotes — operator picker for the quote system. Password-gated.
  // /quotes/<token> is rewritten to /api/quotes/serve in vercel.json so
  // the SPA never sees it; only the bare /quotes path reaches React.
  if (path === '/quotes') return { ...EMPTY_LOC, page: 'quotes-admin' };
  if (path === '/feedback') return { ...EMPTY_LOC, page: 'feedback' };
  const seg = path.replace(/^\//, '');
  if (PAGES.includes(seg)) return { ...EMPTY_LOC, page: seg };
  return { ...EMPTY_LOC };
};

const PAGE_META = {
  home:     { title: 'Valley Films — Detail driven works for brands & agencies', desc: 'Boutique production company in Acton, West London. Commercials, brand videos, social content and live events — high-budget craft delivered by a small, senior team.' },
  services: { title: 'Services — Valley Films', desc: 'Commercials, brand videos, social content and live events. Four ways we help brands and agencies tell their story.' },
  about:    { title: 'About — Valley Films', desc: 'A small team obsessive about the craft. Founded in 2018, Valley Films is built on the conviction that commercial work deserves the same rigour as documentary.' },
  rentals:  { title: 'Valley Rentals — Studio kit, ready when you are', desc: 'Cinema cameras, prime lenses, lighting, grip and audio kit for hire from our Acton, West London studio. Hand-checked, prep included.' },
  'rentals/equipment':    { title: 'Equipment — Valley Rentals',    desc: 'Browse the live rental shelf. Cameras, lenses, lighting, grip, audio and packages — book by date.' },
  'rentals/about':        { title: 'About — Valley Rentals',        desc: 'Where to find us, how to reach us, and the things worth knowing before you book. Acton, West London.' },
  'rentals/open-account': { title: 'Open Account — Valley Rentals', desc: 'Open a Valley Rentals account once and skip verification on every future booking. Five minutes to apply.' },
  'rentals/careers':      { title: 'Careers — Valley Rentals',      desc: 'Open roles at Valley Rentals. Currently hiring: Kit Prep Technician. Apply in five minutes.' },
  'prep-tech': { title: 'Prep Tech — Valley Rentals', desc: 'Apply for the Kit Prep Technician role, or sign in to the team portal.' },
  'prep-tech-portal': { title: 'Prep Tech Portal — Valley Rentals', desc: 'Sign-in portal for Valley Rentals kit-prep technicians and staff.', noindex: true },
  'quotes-admin': { title: 'Quotes — Valley Films', desc: 'Internal operator dashboard for building and editing client quotes.', noindex: true },
  'rentals/consignments': { title: 'Consignments — Valley Rentals',  desc: 'Internal area for managing equipment consignment accounts.', noindex: true },
  'consignor-portal':     { title: 'Your consignment account — Valley Rentals', desc: 'Private view of your consigned kit, balance and rental activity.', noindex: true },
  reference: { title: 'Trade reference — Valley Rentals', desc: 'Submit a short trade reference for a Valley Rentals account applicant.' },
  crew:     { title: 'Crew — Valley Films', desc: 'Join the Valley Films freelance crew roster.', noindex: true },
  feedback: { title: 'Feedback — Valley Films', desc: 'Leave feedback for Valley Films after your project.', noindex: true },
  emails:   { title: 'Email templates — Valley Films', desc: 'Internal reference for every transactional email the site sends.', noindex: true },
  contact:  { title: 'Contact — Valley Films', desc: 'Tell us about your project. We respond within one business day with thoughts, references and an honest sense of fit.' },
  privacy:  { title: 'Privacy — Valley Films', desc: 'Privacy notice for valley.film — what we collect, what we don\'t, and how to reach us.' },
};

const ORIGIN = 'https://valley.film';

const pathFor = (loc) => {
  if (loc.workSlug) return `/work/${loc.workSlug}`;
  if (loc.page === 'rentals' && loc.rentalsSection) return `/rentals/${loc.rentalsSection}`;
  return loc.page === 'home' ? '/' : `/${loc.page}`;
};

const setMeta = (loc) => {
  let title, desc;
  if (loc.workSlug && Array.isArray(WORK)) {
    const w = WORK.find((x) => slugForWork(x) === loc.workSlug);
    if (w) {
      title = `${w.title} — ${w.client} · Valley Films`;
      desc = w.description || `${w.client} — ${w.title}. Made by Valley Films.`;
    }
  }
  let noindex = false;
  if (!title) {
    const key = (loc.page === 'rentals' && loc.rentalsSection)
      ? `rentals/${loc.rentalsSection}`
      : loc.page;
    const m = PAGE_META[key] || PAGE_META[loc.page] || PAGE_META.home;
    title = m.title;
    desc = m.desc;
    noindex = !!m.noindex;
  }
  if (typeof document !== 'undefined') {
    document.title = title;
    const setTag = (selector, attr, value) => {
      const el = document.querySelector(selector);
      if (el) el.setAttribute(attr, value);
    };
    const url = ORIGIN + pathFor(loc);
    setTag('meta[name="description"]', 'content', desc);
    setTag('meta[property="og:title"]', 'content', title);
    setTag('meta[property="og:description"]', 'content', desc);
    setTag('meta[name="twitter:title"]', 'content', title);
    setTag('meta[name="twitter:description"]', 'content', desc);
    setTag('link[rel="canonical"]', 'href', url);
    setTag('meta[property="og:url"]', 'content', url);
    setTag('meta[name="robots"]', 'content', noindex ? 'noindex, nofollow' : 'index, follow');
  }
};

// Tweaks panel is a dev/design tool — only render in localhost or with ?tweaks=1.
const isTweaksEnabled = () => {
  if (typeof window === 'undefined') return false;
  const host = window.location.hostname;
  if (host === 'localhost' || host === '127.0.0.1' || host.endsWith('.local')) return true;
  return /[?&]tweaks=1\b/.test(window.location.search);
};

function App() {
  const [loc, setLoc] = useState(parseLocation);
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const tweaksEnabled = isTweaksEnabled();
  const { page, workSlug, rentalsSection, referenceToken, consignmentToken } = loc;

  // Imperative navigation. Accepts a page name ('about'), a path ('/about'),
  // or a work path ('/work/the-good-fight'). Anchor `<a href="/x">` clicks
  // are handled separately by the click delegate below.
  const goto = (target) => {
    const url = target === 'home'
      ? '/'
      : target.startsWith('/') ? target : `/${target}`;
    // /games/ is a separate static app, not a SPA route. Do a real
    // navigation so the browser actually loads the games HTML instead
    // of pushState'ing into a path the React router doesn't know.
    if (url === '/games' || url === '/games/' || url.startsWith('/games/')) {
      window.location.href = url;
      return;
    }
    if (window.location.pathname === url) {
      window.scrollTo({ top: 0, behavior: 'instant' });
      return;
    }
    window.history.pushState(null, '', url);
    setLoc(parseLocation());
    // Notify everything else listening for navigation — the floating
    // search bar (FloatingRentalsBar) and any other component that
    // watches popstate to derive route-specific behaviour. Without
    // this, internal-link navigation updates the URL silently and
    // those listeners stay stale (e.g. the mini-search popup leaking
    // onto /rentals/equipment because isEquipment was set when the
    // bar first mounted on the landing page).
    window.dispatchEvent(new PopStateEvent('popstate'));
    window.scrollTo({ top: 0, behavior: 'instant' });
  };

  // Browser back/forward, plus our own pushState calls when we manually
  // dispatch popstate (we don't, but keeping it general).
  useEffect(() => {
    const onPop = () => {
      setLoc(parseLocation());
      document.body.style.overflow = '';
    };
    window.addEventListener('popstate', onPop);
    return () => window.removeEventListener('popstate', onPop);
  }, []);

  // Migrate legacy hash URLs (#/about) → clean paths (/about) on first paint
  // so old shared links and bookmarks still land correctly.
  useEffect(() => {
    const m = window.location.hash.match(/^#\/?(.+)$/);
    if (m && m[1]) {
      window.history.replaceState(null, '', '/' + m[1]);
      setLoc(parseLocation());
    }
  }, []);

  // Global click delegate: any internal `<a href="/...">` click navigates
  // via pushState instead of a full reload. Modifier keys, target=_blank,
  // mailto:, http://, and protocol-relative URLs all pass through.
  useEffect(() => {
    const onClick = (e) => {
      if (e.defaultPrevented || e.button !== 0) return;
      if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
      const a = e.target.closest && e.target.closest('a');
      if (!a) return;
      if (a.target && a.target !== '' && a.target !== '_self') return;
      const href = a.getAttribute('href');
      if (!href || !href.startsWith('/') || href.startsWith('//')) return;
      e.preventDefault();
      goto(href);
    };
    document.addEventListener('click', onClick);
    return () => document.removeEventListener('click', onClick);
    // goto is stable enough — re-binding every render is cheap and avoids
    // stale closures pointing at an old setLoc.
  });

  useEffect(() => {
    document.body.classList.toggle('has-custom-cursor', !!tweaks.customCursor);
  }, [tweaks.customCursor]);

  useEffect(() => {
    document.body.classList.toggle('has-wave-dividers', !!tweaks.waveDividers);
  }, [tweaks.waveDividers]);

  useEffect(() => {
    // Rentals chrome + light body background. Includes the Prep Tech
    // hub at /prep-tech (page === 'prep-tech') so the body doesn't
    // show through with the dark Films night-canvas behind the nav
    // bar. The portal at /prep-tech/portal handles its own chrome via
    // is-rentals-portal below and doesn't need this.
    document.body.classList.toggle('is-rentals-page', page === 'rentals' || page === 'consignor-portal' || page === 'prep-tech');
    // Equipment page gets its own class so the floating search/cart
    // can centre itself at the bottom of the viewport and the page
    // can render its category-chip strip just above it.
    document.body.classList.toggle('is-rentals-equipment', page === 'rentals' && rentalsSection === 'equipment');
    // About, Open Account, Careers and Consignments pages don't need
    // the full search affordance — collapse the floating cluster to a
    // compact icon-only pair on the right edge of the viewport.
    // Hovering it expands back to the regular full-width form.
    document.body.classList.toggle(
      'is-rentals-compact',
      page === 'consignor-portal' || (page === 'rentals' && (rentalsSection === 'about' || rentalsSection === 'open-account' || rentalsSection === 'careers' || rentalsSection === 'consignments' || rentalsSection === 'account-update'))
    );
    // Prep Tech portal renders its own chrome (top bar + tab strip) and
    // has no shopping affordance — this class hides the standard rentals
    // nav and floating cart bar via kit-tech-portal.css. The hub page
    // (page === 'prep-tech') is a normal rentals-chrome page and is
    // EXCLUDED here so the standard nav + footer show through.
    document.body.classList.toggle('is-rentals-portal', page === 'prep-tech-portal');
  }, [page, rentalsSection]);

  useEffect(() => {
    setMeta(loc);
  }, [page, workSlug, rentalsSection]);

  let Page = HomePage;
  if (page === 'services')         Page = ServicesPage;
  if (page === 'rentals')          Page = RentalsPage;
  if (page === 'about')            Page = AboutPage;
  if (page === 'contact')          Page = ContactPage;
  if (page === 'privacy')          Page = PrivacyPage;
  if (page === 'reference')        Page = ReferencePage;
  if (page === 'crew')             Page = CrewOnboardingPage;
  if (page === 'consignor-portal') Page = ConsignorPortalPage;
  if (page === 'emails')           Page = EmailTemplatesPage;
  if (page === 'prep-tech')        Page = PrepTechHubPage;
  if (page === 'prep-tech-portal') Page = KitTechPortalPage;
  if (page === 'quotes-admin')     Page = QuotesAdminPage;
  if (page === 'feedback')         Page = FeedbackPage;

  return (
    <React.Fragment>
      {tweaks.customCursor && <CustomCursor/>}
      <Nav page={page} isRentals={page === 'rentals' || page === 'reference' || page === 'consignor-portal' || page === 'prep-tech'} rentalsSection={rentalsSection}/>
      <Page onGoto={goto} heroVariant={tweaks.heroVariant} workSlug={workSlug} rentalsSection={rentalsSection} referenceToken={referenceToken} consignmentToken={consignmentToken}/>
      {/* Power-user keyboard shortcuts (`?` to open). No visible UI. */}
      <KeyboardShortcuts goto={goto} />

      {tweaksEnabled && (
        <TweaksPanel>
          <TweakSection label="Hero variant"/>
          <TweakRadio
            label="Opening"
            value={tweaks.heroVariant}
            options={[
              { value: 'marquee', label: 'Marquee' },
              { value: 'stacked', label: 'Stacked' },
              { value: 'reel',    label: 'Reel' },
            ]}
            onChange={(v) => setTweak('heroVariant', v)}
          />
          <TweakSection label="Interaction"/>
          <TweakToggle
            label="Custom cursor"
            value={!!tweaks.customCursor}
            onChange={(v) => setTweak('customCursor', v)}
          />
          <TweakToggle
            label="Wave dividers"
            value={!!tweaks.waveDividers}
            onChange={(v) => setTweak('waveDividers', v)}
          />
        </TweaksPanel>
      )}
    </React.Fragment>
  );
}

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