// ===========================================================================
// Triplicity · Little Stars — PRODUCTION form app (React)
// Renders the EXACT design components (KidStep1/2 + their desktop variants)
// with the real integrations wired underneath via a `ctrl` controller:
//   • Open-Meteo city autocomplete   • invisible hCaptcha
//   • field validation               • sessionStorage (chartChildInput)
//   • base64 (?bd=) handoff → result page
// The UI is the master design — this file only feeds it data + behavior.
// ===========================================================================

// kids wheel theme (same registration the design canvas uses)
window.themes = window.themes || {};
window.themes.kids = { bg:'#0E1E3A', line:'#AEB9E6', glyph:'#FBF1D6', center:'#10213E', label:'#A9B6D4', accent:'#F4D58A' };

const CC = window.CC;

// responsive variant switch
function useIsDesktop(bp = 760){
  const [d, setD] = React.useState(typeof window!=='undefined' ? window.innerWidth >= bp : true);
  React.useEffect(()=>{
    const on = ()=>setD(window.innerWidth >= bp);
    window.addEventListener('resize', on); return ()=>window.removeEventListener('resize', on);
  },[]);
  return d;
}

// invisible hCaptcha — keeps the design UI untouched (no visible widget)
function useInvisibleHCaptcha(){
  const idRef = React.useRef(null);
  const boxRef = React.useRef(null);
  const resolverRef = React.useRef(null);
  React.useEffect(()=>{
    let tries = 0;
    const t = setInterval(()=>{
      tries++;
      if (window.hcaptcha && boxRef.current && idRef.current === null){
        try {
          idRef.current = window.hcaptcha.render(boxRef.current, {
            sitekey: CC.HCAPTCHA_SITE_KEY, size: 'invisible',
            callback: (tok)=>{ const r = resolverRef.current; resolverRef.current = null; r && r(tok); },
            'error-callback': ()=>{ const r = resolverRef.current; resolverRef.current = null; r && r(null); },
            'expired-callback': ()=>{},
          });
        } catch(e){}
        clearInterval(t);
      }
      if (tries > 40) clearInterval(t);
    }, 150);
    return ()=>clearInterval(t);
  },[]);
  const execute = React.useCallback(()=> new Promise((resolve)=>{
    if (!window.hcaptcha || idRef.current === null){ resolve('nocaptcha'); return; } // degrade gracefully in preview
    resolverRef.current = resolve;
    try { window.hcaptcha.execute(idRef.current); } catch(e){ resolverRef.current = null; resolve(null); }
  }), []);
  const Box = () => <div ref={boxRef} style={{position:'absolute', width:0, height:0, overflow:'hidden'}}/>;
  return { execute, Box };
}

function ChartChildForm(){
  const isDesktop = useIsDesktop();
  const animate = true;
  const [step, setStep] = React.useState(1);
  const [error, setError] = React.useState(null);
  const [busy, setBusy] = React.useState(false);
  const [form, setForm] = React.useState({
    name:'', gender:'暫未確定', email:'', date:'', time:'12:00', timeUnknown:false,
    city:'', lat:'', lng:'', tz:'', nation:'',
  });
  const hcap = useInvisibleHCaptcha();

  const set = (k,v)=> setForm(f=>{
    const next = {...f, [k]:v};
    if (k==='timeUnknown' && v) next.time = '12:00';
    return next;
  });

  // ── city autocomplete (Open-Meteo) ───────────────────────────────────────
  const [cityResults, setCityResults] = React.useState([]);
  const [cityOpen, setCityOpen] = React.useState(false);
  const [cityIdx, setCityIdx] = React.useState(-1);
  const lastQ = React.useRef(''); const tmr = React.useRef(null);

  function onCityInput(v){
    setForm(f=>({...f, city:v, lat:'', lng:'', tz:'', nation:''}));
    if (tmr.current) clearTimeout(tmr.current);
    const q = v.trim();
    if (q.length < 2){ setCityResults([]); setCityOpen(false); return; }
    tmr.current = setTimeout(()=>{
      lastQ.current = q;
      fetch(CC.GEOCODE_URL + '?name=' + encodeURIComponent(q) + '&count=8&language=en&format=json')
        .then(r=>r.json()).then(data=>{
          if (q !== lastQ.current) return;
          const results = (data && data.results) || [];
          setCityResults(results); setCityOpen(results.length>0); setCityIdx(-1);
        }).catch(()=>{ setCityResults([]); setCityOpen(false); });
    }, 220);
  }
  function chooseCity(i){
    const it = cityResults[i]; if (!it) return;
    const label = it.name + (it.admin1 ? ', ' + it.admin1 : '') + (it.country ? ', ' + it.country : '');
    setForm(f=>({...f,
      city: label,
      lat: it.latitude, lng: it.longitude, tz: it.timezone || '', nation: it.country_code || '',
    }));
    setCityOpen(false); setCityResults([]);
  }
  function cityKeyDown(e){
    if (!cityOpen || !cityResults.length) return;
    if (e.key==='ArrowDown'){ e.preventDefault(); setCityIdx(i=>Math.min(cityResults.length-1, i+1)); }
    else if (e.key==='ArrowUp'){ e.preventDefault(); setCityIdx(i=>Math.max(0, i-1)); }
    else if (e.key==='Enter'){ if (cityIdx>=0){ e.preventDefault(); chooseCity(cityIdx); } }
    else if (e.key==='Escape'){ setCityOpen(false); }
  }
  React.useEffect(()=>{
    const close = (e)=>{ if (!e.target.closest('input')) setCityOpen(false); };
    document.addEventListener('click', close); return ()=>document.removeEventListener('click', close);
  },[]);

  // ── step navigation + submit ──────────────────────────────────────────────
  function next(){
    setError(null);
    if (!form.name.trim()) return setError(window.kt ? window.kt('請填寫孩子的稱呼。') : '請填寫孩子的稱呼。');
    if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(form.email.trim())) return setError(window.kt ? window.kt('請填寫有效的電郵地址。') : '請填寫有效的電郵地址。');
    setStep(2);
  }
  async function submit(){
    setError(null);
    if (!form.date) return setError(window.kt ? window.kt('請選擇出生日期。') : '請選擇出生日期。');
    if (!form.timeUnknown && !form.time) return setError(window.kt ? window.kt('請選擇出生時間，或點「不確定」。') : '請選擇出生時間，或點「不確定」。');
    if (!form.lat || !form.lng) return setError(window.kt ? window.kt('請從清單中選擇出生城市。') : '請從清單中選擇出生城市。');
    setBusy(true);
    let token = null;
    try { token = await hcap.execute(); } catch(e){}
    if (token === null){ setBusy(false); return setError(window.kt ? window.kt('人機驗證未通過，請再試一次。') : '人機驗證未通過，請再試一次。'); }

    const dp = form.date.split('-'); const tp = (form.timeUnknown ? '12:00' : form.time).split(':');
    const sessionId = CC.newSessionId();
    const chartData = {
      name: form.name.trim(), email: form.email.trim(),
      year:+dp[0], month:+dp[1], day:+dp[2], hour:+tp[0], minute:+tp[1],
      lat: parseFloat(form.lat), lng: parseFloat(form.lng),
      latitude: parseFloat(form.lat), longitude: parseFloat(form.lng),
      tz_str: form.tz, timezone: form.tz, city: form.city,
      nation: form.nation, country_code: form.nation,
      gender: form.gender, time_unknown: form.timeUnknown,
      session_id: sessionId, marketing_consent: 'No', hcaptcha_token: token,
    };
    try { sessionStorage.setItem(CC.SS_INPUT, JSON.stringify(chartData)); sessionStorage.removeItem(CC.SS_ADULT); } catch(e){}
    const bd = CC.encodeBD(chartData);
    window.location.href = bd ? (CC.RESULT_PATH + '?bd=' + encodeURIComponent(bd)) : CC.RESULT_PATH;
  }

  const ctrl = {
    form, set, next, submit, error, busy,
    city: {
      value: form.city, results: cityResults, open: cityOpen, activeIdx: cityIdx,
      onInput: onCityInput, choose: chooseCity, onKeyDown: cityKeyDown, setOpen: setCityOpen,
    },
  };

  const Step1 = isDesktop ? window.KidStep1Desk : window.KidStep1;
  const Step2 = isDesktop ? window.KidStep2Desk : window.KidStep2;

  return (
    <div style={{position:'relative', width:'100%', minHeight:'100dvh', height:isDesktop?'100dvh':'auto', overflow: isDesktop?'hidden':'visible'}}>
      <hcap.Box/>
      {step===1 ? <Step1 animate={animate} ctrl={ctrl}/> : <Step2 animate={animate} ctrl={ctrl}/>}
    </div>
  );
}

const KID_FORM_THEME = (function(){
  const p = window.KID_PALETTES.moonlight;
  return { pal:p, primary:p.primary, primaryDeep:p.primaryDeep, glow:p.glow, accents:p.accents,
    font:"'Baloo 2','Noto Sans TC',cursive", round:1, animate:true, wheelStyle:'traditional' };
})();

function FormBoot(){
  const [lang, setLangState] = React.useState(window.KID_LANG || 'zh');
  const setLang = React.useCallback((l)=>{
    window.kidApplyLang?.(l);
    setLangState(l);
  }, []);
  return (
    <window.KidLangCtx.Provider value={{ lang, setLang }}>
      <window.KidThemeCtx.Provider value={KID_FORM_THEME}>
        <ChartChildForm/>
      </window.KidThemeCtx.Provider>
    </window.KidLangCtx.Provider>
  );
}
ReactDOM.createRoot(document.getElementById('root')).render(<FormBoot/>);
