// ===== Agenda bij de datumbalk ==========================================================
// De pijlen blijven staan, want een dag vooruit is een klik. Wie naar een dag over drie weken moet, klikt
// nu eenentwintig keer. Deze knop opent een maandkalender en springt er in een keer heen.
//
// EEN VALKUIL DIE HIER EERDER GELD KOSTTE: een absoluut geplaatst paneel BINNEN een element met
// `overflow:auto` of `hidden` wordt stil afgeknipt, zonder foutmelding en met een correcte DOM. De wikkel
// hieronder staat daarom op `position:relative` en draagt zelf GEEN overflow-regel, en de hoogte van het
// paneel is in de browser nagemeten in plaats van alleen de aanwezigheid vastgesteld.
const WEEKDAGEN = ["ma","di","wo","do","vr","za","zo"];

function Agenda({datum,onKies,onSluit}){
  // De cursor is de dag die de toetsenbordfocus heeft. Hij begint op de gekozen dag en bepaalt ook welke
  // maand er staat, zodat pijlen over een maandgrens vanzelf doorbladeren.
  const [cursor,setCursor]=useState(datum);
  const raster=React.useRef(null);
  useEffect(()=>{ const el=raster.current&&raster.current.querySelector('[data-focus="ja"]'); if(el) el.focus(); },[cursor]);
  const c=new Date(cursor+"T12:00:00");
  const eerste=new Date(c.getFullYear(),c.getMonth(),1,12);
  const start=new Date(eerste); start.setDate(1-((eerste.getDay()+6)%7)); // week begint op maandag
  const dagen=[]; for(let i=0;i<42;i++){ const d=new Date(start); d.setDate(start.getDate()+i); dagen.push(d); }
  const vandaag=iso(new Date());
  function schuif(dagenErbij,maandenErbij){
    const d=new Date(cursor+"T12:00:00");
    if(maandenErbij) d.setMonth(d.getMonth()+maandenErbij); else d.setDate(d.getDate()+dagenErbij);
    setCursor(iso(d));
  }
  function toets(e){
    if(e.key==="Escape"){ e.preventDefault(); onSluit(); return; }
    if(e.key==="ArrowLeft"){ e.preventDefault(); schuif(-1); return; }
    if(e.key==="ArrowRight"){ e.preventDefault(); schuif(1); return; }
    if(e.key==="ArrowUp"){ e.preventDefault(); schuif(-7); return; }
    if(e.key==="ArrowDown"){ e.preventDefault(); schuif(7); return; }
    if(e.key==="PageUp"){ e.preventDefault(); schuif(0,-1); return; }
    if(e.key==="PageDown"){ e.preventDefault(); schuif(0,1); return; }
  }
  const maandnaam=c.toLocaleDateString("nl-NL",{month:"long",year:"numeric"});
  return (<div className="agenda" role="dialog" aria-label="Kies een dag" onKeyDown={toets}>
    <div className="agenda-kop">
      <button className="agenda-pijl" onClick={()=>schuif(0,-1)} aria-label="Vorige maand">‹</button>
      <div className="agenda-maand">{maandnaam}</div>
      <button className="agenda-pijl" onClick={()=>schuif(0,1)} aria-label="Volgende maand">›</button>
    </div>
    <div className="agenda-weekdagen" aria-hidden="true">{WEEKDAGEN.map(d=><span key={d}>{d}</span>)}</div>
    <div className="agenda-raster" ref={raster}>
      {dagen.map(d=>{ const s=iso(d); const buiten=d.getMonth()!==c.getMonth();
        const isCursor=s===cursor;
        return (<button key={s} type="button"
          className={"agenda-dag"+(buiten?" buiten":"")+(s===vandaag?" vandaag":"")+(s===datum?" gekozen":"")}
          data-dag={s} data-focus={isCursor?"ja":"nee"} tabIndex={isCursor?0:-1}
          aria-current={s===datum?"date":undefined}
          onFocus={()=>{ if(!isCursor) setCursor(s); }}
          onClick={()=>onKies(s)}>{d.getDate()}</button>);})}
    </div>
    <p className="agenda-bij">Kies een dag met de pijltjes, Escape sluit.</p>
  </div>);
}

function Agendaknop({datum,onKies}){
  const [open,setOpen]=useState(false);
  const knop=React.useRef(null);
  function sluit(){ setOpen(false); if(knop.current) knop.current.focus(); }
  return (<div className="agendawikkel">
    <button ref={knop} className="agendaknop" aria-haspopup="dialog" aria-expanded={open?"true":"false"}
      onClick={()=>setOpen(!open)}>Agenda</button>
    {open && <div className="agenda-scrim" onClick={sluit}/>}
    {open && <Agenda datum={datum} onKies={d=>{ onKies(d); sluit(); }} onSluit={sluit}/>}
  </div>);
}
// ========================================================================================

// ===== De dag en het scherm staan in de URL ============================================
// WAAROM. Gemeten op 12 augustus 2026: sta je op de tee sheet van 9 september en ververs je de pagina,
// dan sta je weer op de tee sheet van vandaag. Hetzelfde geldt voor de terugknop van de browser, die
// je regelrecht de app uit stuurt. Aan een balie waar iemand per ongeluk F5 drukt is dat het kwijtraken
// van je plek, en tijdens een demo is het een gat in het verhaal.
// De gastvoorkant zet zijn dag al in de URL (?dag=). De balie deed dat niet. Nu wel, met dezelfde naam.
const SCHERMEN = ["teesheet","dagstaat","zoeken","wachtlijst","rapportage","kaarthouders","recras","recraskoppeling",
                  "dagbeheer","seizoenen","sluiting","tarieven","types","wachtwoord","kiosk","clubhuis"];
function uitUrl(){
  const p = new URLSearchParams(location.search);
  const s = p.get("scherm");
  const d = p.get("dag");
  return {
    scherm: SCHERMEN.indexOf(s)>=0 ? s : "teesheet",
    // Alleen een datum in de vorm jjjj-mm-dd wordt overgenomen. Alles anders valt terug op vandaag,
    // zodat een verminkte URL geen leeg scherm oplevert maar gewoon de dag van vandaag.
    datum: /^\d{4}-\d{2}-\d{2}$/.test(d||"") ? d : iso(new Date())
  };
}
function naarUrl(scherm,datum,vervang){
  const p = new URLSearchParams(location.search);
  p.set("scherm",scherm); p.set("dag",datum);
  const url = location.pathname+"?"+p.toString();
  if(vervang) history.replaceState({scherm,datum},"",url); else history.pushState({scherm,datum},"",url);
}
// ========================================================================================

function Balie(){
  const start = uitUrl();
  const [banen,setBanen]=useState([]); const [baan,setBaan]=useState(null);
  const [datum,setDatum]=useState(start.datum); const [types,setTypes]=useState([]); const [houders,setHouders]=useState([]);
  const [scherm,setScherm]=useState(start.scherm); const [drawer,setDrawer]=useState(false);
  const [melding,setMelding]=useState(null); const [f,setF]=useState(null);
  const [inrichtingOpen,setInrichtingOpen]=useState(false);
  const toon=m=>{ setMelding(m); setTimeout(()=>setMelding(null),2600); };
  const herlaadHouders=useCallback(async()=>{ const l=await db.from("leden").select("id,naam").order("naam"); if(l.data) setHouders(l.data); },[]);
  useEffect(()=>{ (async()=>{
    const b=await db.from("banen").select("*").eq("actief",true).order("naam");
    const t=await db.from("spelerstypes").select("*").eq("actief",true).order("code");
    if(b.data&&b.data.length){ setBanen(b.data); setBaan(b.data[0].id); } else setF("Geen banen gevonden.");
    if(t.data) setTypes(t.data); herlaadHouders();
  })(); },[herlaadHouders]);
  // De URL loopt mee met wat er op het scherm staat. Een dagwissel VERVANGT de regel in de
  // geschiedenis in plaats van er een bij te zetten: anders moet je na twintig keer op de pijl
  // drukken twintig keer terug om de app uit te komen. Een SCHERMwissel zet er wel een bij, want
  // daar wil je met de terugknop juist naar het vorige scherm.
  useEffect(()=>{ naarUrl(scherm,datum,true); },[datum]);   // eslint-disable-line
  useEffect(()=>{
    function terug(){ const s=uitUrl(); setScherm(s.scherm); setDatum(s.datum); }
    window.addEventListener("popstate",terug);
    return ()=>window.removeEventListener("popstate",terug);
  },[]);
  function verschuif(d){ const x=new Date(datum+"T12:00:00"); x.setDate(x.getDate()+d); setDatum(iso(x)); }
  const titel={teesheet:"Tee sheet",dagstaat:"Dagstaat",wachtlijst:"Wachtlijst",rapportage:"Rapportage",seizoenen:"Seizoenen",sluiting:"Sluitingsdagen",tarieven:"Tarieven",kaarthouders:"Kaarthouders",types:"Spelerstypes",zoeken:"Reservering opzoeken",dagbeheer:"Dag inrichten",wachtwoord:"Wachtwoord",recras:"Bedrijfsboeking (nagebootst)",kiosk:"Aanmelden aan de bar",clubhuis:"Clubhuisscherm"}[scherm];
  // ===== Wat er achter het wachtwoord zit ==============================================
  // Eén wachtwoord, één keer vragen per sessie, daarna open tot uitloggen of herladen.
  //
  // Let op de vorm van deze lijst: het slot hangt aan SCHERMNAMEN en niet aan het kopje waaronder een
  // scherm in het menu staat. Rapportage stond eerst bewust onder Dagelijks (achter het slot, maar op
  // de plek waar het werk qua indeling thuishoorde). Op verzoek van Roy (21 aug 2026) staat het
  // menu-item nu bij Inrichting, omdat niet elke baliemedewerker de omzet hoeft te zien. Dat is puur
  // een verplaatsing in het menu: het wachtwoordslot verandert hierdoor niet, want dat hangt hierboven
  // toch al aan de schermnaam en niet aan het kopje.
  //
  // Rapportage staat erbij op verzoek van de opdrachtgever: daar staat de omzet, en die hoeft niet
  // voor iedereen achter de balie in beeld te staan.
  // Kaarthouders en verkoop staat er met opzet NIET bij: de balie moet een kaarthouder gewoon kunnen
  // toevoegen. Kijken en boeken blijft ook vrij: tee sheet, dagstaat, opzoeken en wachtlijst.
  const ACHTER_SLOT = ["dagbeheer","seizoenen","sluiting","tarieven","types","wachtwoord","rapportage"];
  const achterSlot = ACHTER_SLOT.indexOf(scherm) >= 0 && !inrichtingOpen;
  function ga(s){ setScherm(s); setDrawer(false); naarUrl(s,datum,false); }
  // Dag inrichten hoort ook bij de datumbalk: je richt altijd EEN dag in, en zonder die balk zou je
  // niet kunnen zien of kiezen welke dag dat is.
  const metDatum = scherm==="teesheet"||scherm==="dagstaat"||scherm==="dagbeheer";
  // Kiosk-modus verbergt de hele balienavigatie: geen drawer, geen kop met menuknop, geen
  // datumkiezer. Dat is de kern van punt 5 uit de werklijst: dit scherm moet er zelfstandig staan,
  // niet als een tabblad binnen de balie dat een gast ook zou kunnen wegklikken naar iets anders.
  if(scherm==="kiosk"){
    return (<div>
      {f && <div className="fout">{f}</div>}
      {!f && <Kiosk banen={banen} onTerug={()=>ga("teesheet")}/>}
    </div>);
  }
  // Het clubhuisscherm gaat om dezelfde reden door dit gat als de kiosk: het hoort op een tv in het
  // clubhuis zelfstandig te staan, zonder menuknop, zonder datumbalk en zonder iets wat je kunt
  // bedienen. Er is bewust ook GEEN terugknop zoals de kiosk die heeft: dit scherm hangt hoog aan
  // een muur, en wie terug wil naar de balie herlaadt de pagina zonder ?scherm=clubhuis.
  if(scherm==="clubhuis"){
    return (<div>
      {f && <div className="fout">{f}</div>}
      {!f && <Clubhuis banen={banen}/>}
    </div>);
  }
  return (<div>
    {/* Het logo brengt je terug naar de tee sheet. Dat is wat iedereen van een logo linksboven
        verwacht, en het was hier een dood element. Het is een echte knop, dus hij werkt ook met het
        toetsenbord en heeft een aanwijsstand. */}
    <div className="top"><div className="top-in">
      {/* Lockup nabouw van Daniels header (klanten/up-events/daniel-layout-20260821/03-admin-login.jpeg
          en 02-tee-sheet-met-legenda.jpeg), 22 augustus 2026 avond: UP, een dunne scheidingslijn,
          en daaronder GOLF WEESP / PREMIUM BOOKING. Vervangt de losse tekst "UPgolf". */}
      <button className="brand" onClick={()=>ga("teesheet")} title="Terug naar de tee sheet">
        <span className="brand-up">UP</span>
        <span className="brand-scheiding" aria-hidden="true"></span>
        <span className="brand-tekst">
          <span className="brand-naam">Golf Weesp</span>
          <span className="brand-sub">Premium booking</span>
        </span>
      </button>
      <button className="menuknop" onClick={()=>setDrawer(true)}>{titel} ≡</button></div></div>
    {drawer && <div className="drawer-scrim" onClick={()=>setDrawer(false)}/>}
    {drawer && <div className="drawer"><button className="drawer-sluit" onClick={()=>setDrawer(false)}>✕</button>
      <h4>Dagelijks</h4>
      <button className={"drawer-item"+(scherm==="teesheet"?" aan":"")} onClick={()=>ga("teesheet")}>Tee sheet</button>
      <button className={"drawer-item"+(scherm==="dagstaat"?" aan":"")} onClick={()=>ga("dagstaat")}>Dagstaat</button>
      <button className={"drawer-item"+(scherm==="zoeken"?" aan":"")} onClick={()=>ga("zoeken")}>Reservering opzoeken</button>
      {/* Wachtlijst is uit het menu gehaald op verzoek van Roy (27 augustus 2026); UP zag er
          op 21 augustus weinig in zolang de bezetting ver van vol zit. Het scherm zelf bestaat nog
          en is via de URL te bereiken, dus terugzetten is een regel werk. */}
      <button className={"drawer-item"+(scherm==="kaarthouders"?" aan":"")} onClick={()=>ga("kaarthouders")}>Kaarthouders &amp; verkoop</button>
      {/* Eigen kopje: kiosk-modus is geen dagelijkse balieschermwissel maar een aparte stand die de
          navigatie verbergt zodra hij openstaat. `ga` zet ook meteen de URL, maar dat maakt niets uit
          voor "niet thuis op te roepen": de kiosk-modus vraagt nog altijd de balie-inlogsessie, die
          een gast thuis niet heeft. */}
      <h4>Aan de bar</h4>
      <button className="drawer-item" onClick={()=>ga("kiosk")}>Aanmelden aan de bar</button>
      {/* Zelfde kopje, want het hoort bij dezelfde plek: het scherm dat in het clubhuis blijft
          draaien. Openen op de tv, daarna niets meer aanraken. */}
      <button className="drawer-item" onClick={()=>ga("clubhuis")}>Tee sheet op het clubhuisscherm</button>
      {/* Eigen kopje, en met opzet niet onder Dagelijks: dit is een DEMO-scherm dat een koppeling
          nabootst en geen werkhandeling aan de balie. Het woord nagebootst staat al in het menu,
          zodat niemand het per ongeluk voor echt werk aanziet. */}
      <h4>Demo</h4>
      <button className={"drawer-item"+(scherm==="recraskoppeling"?" aan":"")} onClick={()=>ga("recraskoppeling")}>Recras-koppeling (testomgeving)</button>
      <button className={"drawer-item"+(scherm==="recras"?" aan":"")} onClick={()=>ga("recras")}>Bedrijfsboeking via Recras (nagebootst)</button>
      <h4>Inrichting</h4>
      {/* Rapportage is hierheen verplaatst op verzoek van Roy (21 aug 2026): niet iedere
          baliemedewerker hoeft de omzet te zien, dus staat hij nu bij Inrichting in plaats van
          Dagelijks. Het wachtwoordslot hangt aan de SCHERMNAAM (zie ACHTER_SLOT hierboven) en niet
          aan het menukopje, dus deze verplaatsing verandert niets aan de bestaande beveiliging. */}
      <button className={"drawer-item"+(scherm==="rapportage"?" aan":"")} onClick={()=>ga("rapportage")}>Rapportage</button>
      <button className={"drawer-item"+(scherm==="dagbeheer"?" aan":"")} onClick={()=>ga("dagbeheer")}>Dag inrichten</button>
      <button className={"drawer-item"+(scherm==="seizoenen"?" aan":"")} onClick={()=>ga("seizoenen")}>Seizoenen</button>
      <button className={"drawer-item"+(scherm==="sluiting"?" aan":"")} onClick={()=>ga("sluiting")}>Sluitingsdagen</button>
      <button className={"drawer-item"+(scherm==="tarieven"?" aan":"")} onClick={()=>ga("tarieven")}>Tarieven</button>
      <button className={"drawer-item"+(scherm==="types"?" aan":"")} onClick={()=>ga("types")}>Spelerstypes</button>
      <button className={"drawer-item"+(scherm==="wachtwoord"?" aan":"")} onClick={()=>ga("wachtwoord")}>Wachtwoord</button>
      {/* Uitloggen sluit ook de sleutel. Dat is een nettigheid en geen grendel: de harde grens blijft
          middernacht in de database, want een browser die vastloopt roept niets meer aan. */}
      <h4>Account</h4><button className="drawer-item" onClick={async()=>{ try{ await db.rpc("sluit_sleutel"); }catch(e){} db.auth.signOut(); }}>Uitloggen</button>
    </div>}
    <main>
      {f && <div className="fout">{f}</div>}
      {!f && metDatum && <div className="datumnav">
        <button className="pijl" onClick={()=>verschuif(-1)}>‹</button>
        <div className="lbl">{langDat(datum)}</div>
        <button className="pijl" onClick={()=>verschuif(1)}>›</button>
        <Agendaknop datum={datum} onKies={setDatum}/>
        <button className="vandaag" onClick={()=>setDatum(iso(new Date()))}>Vandaag</button></div>}
      {!f && banen.length>1 && metDatum && <select value={baan||""} onChange={e=>setBaan(e.target.value)} style={{marginBottom:12}}>{banen.map(b=><option key={b.id} value={b.id}>{b.naam}</option>)}</select>}
      {/* De uitleg staat boven ELK scherm (verzoek Roy 27 augustus): werkschermen dichtgeklapt
          achter een knop, instelschermen open. Teksten en gedrag: UITLEG en UitlegBlok in data.js. */}
      {!f && !achterSlot && <UitlegBlok scherm={scherm}/>}
      {!f && scherm==="teesheet" && <TeeSheet baan={baan} datum={datum} types={types} houders={houders} toon={toon} herlaadHouders={herlaadHouders}/>}
      {!f && scherm==="dagstaat" && <Dagstaat baan={baan} datum={datum} toon={toon}/>}
      {/* De uitleg staat boven het scherm en niet erin, zodat de teksten op een plek staan en de
          schermen zelf onaangeraakt blijven. Achter het slot tonen wij hem niet: dan staat er uitleg
          bij een scherm dat je nog niet ziet. */}

      {!f && achterSlot && <InrichtingSlot scherm={scherm} onOpen={()=>setInrichtingOpen(true)}/>}
      {!f && scherm==="zoeken" && <Zoeken/>}
      {!f && scherm==="recraskoppeling" && <RecrasKoppeling toon={toon}/>}
      {!f && scherm==="recras" && <RecrasSimulatie baan={baan} toon={toon}/>}
      {!f && !achterSlot && scherm==="wachtwoord" && <Wachtwoord toon={toon}/>}
      {!f && !achterSlot && scherm==="dagbeheer" && <DagBeheer baan={baan} datum={datum} toon={toon}/>}
      {!f && scherm==="wachtlijst" && <Wachtlijst baan={baan} toon={toon}/>}
      {!f && !achterSlot && scherm==="rapportage" && <Rapportage baan={baan} toon={toon}/>}
      {!f && !achterSlot && scherm==="seizoenen" && <Seizoenen baan={baan} toon={toon}/>}
      {!f && !achterSlot && scherm==="sluiting" && <Sluiting baan={baan} toon={toon}/>}
      {!f && !achterSlot && scherm==="tarieven" && <Tarieven baan={baan} toon={toon}/>}
      {!f && scherm==="kaarthouders" && <Kaarthouders toon={toon}/>}
      {!f && !achterSlot && scherm==="types" && <Types toon={toon}/>}
    </main>
    {melding && <div className="melding">{melding}</div>}
  </div>);
}

function App(){
  const [sessie,setSessie]=useState(undefined);
  useEffect(()=>{ db.auth.getSession().then(r=>setSessie(r.data.session));
    const s=db.auth.onAuthStateChange((_e,ses)=>setSessie(ses)); return ()=>s.data.subscription.unsubscribe(); },[]);
  if(sessie===undefined) return <div className="laden" style={{paddingTop:"42vh"}}>Even geduld…</div>;
  return sessie ? <Balie/> : <Poort/>;
}
ReactDOM.createRoot(document.getElementById("root")).render(<Vangnet><App/></Vangnet>);
