// Quote entry — hands off to the live quote engine, which analyses the real
// roof from satellite data and produces a full proposal (panel layout, 25-year
// savings, PDF, survey booking) in ~20 seconds. Replaces the old 4-step mock
// chat flow (2026-07-14).

const { useState: useStateQ } = React;

// The live engine. One place to change when proposals.nexsol.ie goes live.
const QUOTE_ENGINE_URL = 'https://nexsol-quote-engine.vercel.app';

// Eircode normalisation: uppercase, single space between routing key (3) and unique id (4).
function normaliseEircode(raw) {
  const cleaned = (raw || '').toUpperCase().replace(/\s+/g, '');
  if (cleaned.length <= 3) return cleaned;
  return cleaned.slice(0,3) + ' ' + cleaned.slice(3,7);
}

function isEircode(raw) {
  const cleaned = (raw || '').toUpperCase().replace(/\s+/g, '');
  return /^(D6W|[A-Z]\d{2})[A-Z0-9]{4}$/.test(cleaned);
}

// Bill slider bounds mirror the engine's model config (lib/config/systems.ts).
const BILL_MIN = 50, BILL_MAX = 500, BILL_STEP = 10, BILL_DEFAULT = 180;
const ROOF_TYPES = ['slate', 'tile', 'metal'];

// Codes are FIRSTNAME-XXXX and get said aloud, texted and retyped, so rebuild
// the canonical shape from whatever the visitor gives us before looking it up.
function normaliseRefCode(raw) {
  const bare = (raw || '').toUpperCase().replace(/[^A-Z0-9]/g, '');
  return bare.length > 4 ? bare.slice(0, -4) + '-' + bare.slice(-4) : bare;
}

// A referral link is usually opened days before the quote is run, and the
// visitor rarely comes back through the same link — so the code has to outlive
// the URL. 90 days is the window the reward is honoured for.
const REF_KEY = 'nexsol_ref';
const REF_MAX_AGE_MS = 90 * 24 * 60 * 60 * 1000;

function readStoredRef() {
  try {
    const saved = JSON.parse(window.localStorage.getItem(REF_KEY) || 'null');
    if (!saved || !saved.code) return null;
    if (Date.now() - saved.at > REF_MAX_AGE_MS) { window.localStorage.removeItem(REF_KEY); return null; }
    return saved;
  } catch (e) { return null; }
}

// `at` is when the referral was first picked up, not the last visit — the 90
// days run from the click, so coming back can't quietly extend the window.
function writeStoredRef(ref, at) {
  try {
    window.localStorage.setItem(REF_KEY, JSON.stringify({ code: ref.code, name: ref.name, discount: ref.discount, at: at || Date.now() }));
  } catch (e) { /* private browsing — the code still works for this visit */ }
}

const PROGRESS_STEPS = [
  'Finding your roof…',
  'Reading the roof planes…',
  'Placing your panels…',
  'Pricing your system…',
  'Nearly there — running 25-year numbers…',
];

function WHQuoteFull({ embedded=false }) {
  const { useEffect: useEffectQ } = React;
  const siteConfig = useSiteConfig();
  const billModel = siteConfig.systems.model;
  const copy = siteConfig.content.quoteForm || {};
  const [eir, setEir] = useStateQ('');
  const [bill, setBill] = useStateQ(BILL_DEFAULT);
  const [roofType, setRoofType] = useStateQ('tile');
  const [err, setErr] = useStateQ(null);
  const [going, setGoing] = useStateQ(false);
  const [stepMsg, setStepMsg] = useStateQ(PROGRESS_STEPS[0]);
  const [referral, setReferral] = useStateQ(null); // { code, name, discount }
  const [refOpen, setRefOpen] = useStateQ(false);
  const [refCode, setRefCode] = useStateQ('');
  const [refBusy, setRefBusy] = useStateQ(false);
  const [refMsg, setRefMsg] = useStateQ(null);
  const ready = isEircode(eir);

  useEffectQ(() => {
    setBill(billModel.sliderDefaultBill || BILL_DEFAULT);
  }, [billModel.sliderDefaultBill]);

  // Referral link support: /quote/?ref=JOHN-8K2F applies the friend's discount.
  // With no ?ref= we fall back to a code this browser saved on an earlier visit,
  // and re-check it either way so the banner can't quote a discount that has
  // since changed. An invalid answer can also mean the database blinked, so a
  // saved code is never deleted on the strength of it.
  useEffectQ(() => {
    const fromUrl = new URLSearchParams(window.location.search).get('ref');
    const stored = fromUrl ? null : readStoredRef();
    const code = normaliseRefCode(fromUrl || (stored && stored.code) || '');
    if (!code) return;
    fetch('/api/referral?code=' + encodeURIComponent(code))
      .then(r => r.json())
      .then(d => {
        if (!d.valid) return;
        const applied = { code, name: d.name, discount: d.discount };
        setReferral(applied);
        writeStoredRef(applied, stored ? stored.at : Date.now());
      })
      .catch(() => { if (stored) setReferral({ code: stored.code, name: stored.name, discount: stored.discount }); });
  }, []);

  // Manual entry, for the friend who was given the code in the pub, not by link.
  const applyRefCode = async () => {
    const code = normaliseRefCode(refCode);
    if (code.length < 6) { setRefMsg("That doesn't look like a full code — it's a name and four characters, like SEAN-8K2F."); return; }
    setRefMsg(null); setRefBusy(true);
    try {
      const res = await fetch('/api/referral?code=' + encodeURIComponent(code));
      const d = await res.json();
      if (d.valid) {
        const applied = { code, name: d.name, discount: d.discount };
        setReferral(applied);
        writeStoredRef(applied);
        setRefOpen(false);
      } else {
        setRefMsg("We can't find that code. Check it with whoever sent it — your quote works fine without it.");
      }
    } catch (e) {
      setRefMsg("Couldn't check that code just now. Carry on — we'll apply it at the survey.");
    }
    setRefBusy(false);
  };

  const go = async () => {
    if (!ready) { setErr(copy.invalidEircode || "That doesn't look like a full Eircode — e.g. E45 WR88."); return; }
    setErr(null); setGoing(true);
    // Honest progress while the engine analyses (typically 5-20s, rural up to ~40s).
    let step = 0;
    setStepMsg(PROGRESS_STEPS[0]);
    const ticker = setInterval(() => {
      step = Math.min(step + 1, PROGRESS_STEPS.length - 1);
      setStepMsg(PROGRESS_STEPS[step]);
    }, 7000);
    const finish = (fn) => { clearInterval(ticker); fn(); };
    try {
      // Same-origin: /api and /p are proxied to the quote engine (vercel.json),
      // so the proposal opens under the nexsol site's own domain.
      const res = await fetch('/api/proposal', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          eircode: eir,
          monthlyBill: bill,
          roofType,
          ref: referral ? referral.code : undefined,
        }),
        signal: AbortSignal.timeout(95000),
      });
      const data = await res.json().catch(() => ({}));
      if (res.ok && data.token) { finish(() => { window.location.href = '/p/' + data.token; }); return; }
      finish(() => {
        setErr(data.error || "That took longer than it should — please try again, it usually works second time.");
        setGoing(false);
      });
    } catch (e) {
      finish(() => {
        if (e && e.name === 'TimeoutError') {
          setErr("Your roof is taking longer than usual to analyse — give it another go, or ring us and we'll do it over the phone.");
          setGoing(false);
        } else {
          // Proxy unavailable (e.g. local preview) — fall back to the engine URL.
          window.location.href = QUOTE_ENGINE_URL + '/?eircode=' + encodeURIComponent(eir.replace(/\s+/g,'')) + '&bill=' + bill + '&roof=' + roofType;
        }
      });
    }
  };

  return (
    <div style={{ background:WH.white, border:`1.5px solid ${WH.ink}`, borderRadius:16, overflow:'hidden', maxWidth:520, margin:'0 auto' }}>
      <div style={{ padding:'16px 24px', background:WH.ink, color:WH.cream, display:'flex', justifyContent:'space-between', alignItems:'center' }}>
        <span style={{ fontFamily:WH.sans, fontSize:12, fontWeight:700, letterSpacing:'0.12em', textTransform:'uppercase' }}>Instant online quotes</span>
        <span style={{ fontFamily:WH.sans, fontSize:12, fontWeight:500, color:WH.sky }}>~20 seconds</span>
      </div>

      <div style={{ padding:28, display:'flex', flexDirection:'column', gap:18 }}>
        <div style={{ fontFamily:WH.sans, fontSize:22, fontWeight:700, letterSpacing:'-0.03em', lineHeight:1.15, color:WH.ink }}>
          Your Eircode, bill and roof.<br/>We do the rest.
        </div>

        {referral && (
          <div style={{ display:'flex', gap:10, alignItems:'center', padding:'12px 14px', background:WH.sky, border:`1.5px solid ${WH.ink}`, borderRadius:12 }}>
            <span style={{ fontSize:18 }}>🎁</span>
            <span style={{ fontFamily:WH.sans, fontSize:14, fontWeight:700, color:WH.ink }}>
              {referral.name}'s code applied — €{referral.discount} off your install price.
            </span>
          </div>
        )}

        <div>
          <label style={{ display:'block', fontFamily:WH.sans, fontSize:11, fontWeight:700, letterSpacing:'0.08em', textTransform:'uppercase', color:WH.slate, marginBottom:6 }}>{copy.eircodeLabel || 'Eircode'}</label>
          <input
            value={eir}
            onChange={e=>{ setEir(normaliseEircode(e.target.value)); if (err) setErr(null); }}
            onKeyDown={e=>{ if (e.key==='Enter') go(); }}
            placeholder={copy.eircodePlaceholder || 'e.g. E45 WR88'}
            maxLength={8}
            autoComplete="postal-code"
            style={{ width:'100%', padding:'16px 18px', background:WH.cream, border:`1.5px solid ${WH.ink}`, borderRadius:12, fontFamily:WH.sans, fontSize:18, fontWeight:600, letterSpacing:'0.06em', textTransform:'uppercase', outline:'none', color:WH.ink }}
          />
          {err && <div style={{ marginTop:8, fontFamily:WH.sans, fontSize:13, fontWeight:600, color:WH.orange }}>{err}</div>}
        </div>

        <div>
          <label style={{ display:'block', fontFamily:WH.sans, fontSize:11, fontWeight:700, letterSpacing:'0.08em', textTransform:'uppercase', color:WH.slate, marginBottom:6 }}>{copy.roofLabel || 'Your roof covering'}</label>
          <div role="group" aria-label="Your roof covering" style={{ display:'grid', gridTemplateColumns:'repeat(3, 1fr)', gap:8 }}>
            {ROOF_TYPES.map(type => {
              const selected = roofType === type;
              return (
                <button
                  key={type}
                  type="button"
                  aria-pressed={selected}
                  onClick={() => setRoofType(type)}
                  style={{
                    padding:'12px 8px',
                    background:selected ? WH.ink : WH.cream,
                    color:selected ? WH.cream : WH.ink,
                    border:`1.5px solid ${WH.ink}`,
                    borderRadius:12,
                    fontFamily:WH.sans,
                    fontSize:14,
                    fontWeight:700,
                    textTransform:'capitalize',
                    cursor:'pointer',
                  }}
                >
                  {type}
                </button>
              );
            })}
          </div>
          <div style={{ marginTop:8, fontFamily:WH.sans, fontSize:12.5, color:WH.slate, lineHeight:1.45 }}>
            {copy.roofHelp || 'Installation pricing differs for slate, tile and metal roofs. Tile is pre-selected.'}
          </div>
        </div>

        <div>
          <label style={{ display:'block', fontFamily:WH.sans, fontSize:11, fontWeight:700, letterSpacing:'0.08em', textTransform:'uppercase', color:WH.slate, marginBottom:6 }}>{copy.billLabel || 'Your average monthly electricity bill'}</label>
          <div style={{ background:WH.cream, border:`1.5px solid ${WH.ink}`, borderRadius:12, padding:'16px 18px 12px' }}>
            <div style={{ fontFamily:WH.sans, fontSize:64, fontWeight:700, letterSpacing:'-0.04em', lineHeight:0.92, color:WH.ink }}>€{bill>=billModel.sliderMaxBill?`${billModel.sliderMaxBill}+`:bill}<span style={{ fontSize:18, color:WH.slate, fontWeight:500, letterSpacing:'-0.02em' }}> {copy.billSuffix || '/ month'}</span></div>
            <input type="range" min={billModel.sliderMinBill} max={billModel.sliderMaxBill} step={billModel.sliderStepEur} value={bill} onChange={e=>setBill(+e.target.value)} className="brand-range"/>
            <div style={{ display:'flex', justifyContent:'space-between', fontFamily:WH.sans, fontSize:11, fontWeight:500, color:WH.slate, marginTop:4, letterSpacing:'-0.01em' }}><span>€{billModel.sliderMinBill}</span><span>€{billModel.sliderMaxBill}+</span></div>
          </div>
          <div style={{ marginTop:8, fontFamily:WH.sans, fontSize:12.5, color:WH.slate, lineHeight:1.45 }}>
            We size the system to your bill — that's what makes the savings and payback realistic for your house.
          </div>
        </div>

        {!referral && (refOpen ? (
          <div>
            <label style={{ display:'block', fontFamily:WH.sans, fontSize:11, fontWeight:700, letterSpacing:'0.08em', textTransform:'uppercase', color:WH.slate, marginBottom:6 }}>Referral code</label>
            <div style={{ display:'flex', gap:8 }}>
              <input
                value={refCode}
                onChange={e=>{ setRefCode(e.target.value); if (refMsg) setRefMsg(null); }}
                onKeyDown={e=>{ if (e.key==='Enter') applyRefCode(); }}
                placeholder="e.g. SEAN-8K2F"
                style={{ flex:1, minWidth:0, padding:'14px 16px', background:WH.cream, border:`1.5px solid ${WH.ink}`, borderRadius:12, fontFamily:WH.sans, fontSize:16, fontWeight:600, letterSpacing:'0.04em', textTransform:'uppercase', outline:'none', color:WH.ink }}
              />
              <button onClick={applyRefCode} disabled={refBusy}
                style={{ padding:'0 18px', background:WH.sky, color:WH.ink, border:`1.5px solid ${WH.ink}`, borderRadius:12, fontFamily:WH.sans, fontSize:14, fontWeight:700, letterSpacing:'-0.01em', cursor:'pointer', whiteSpace:'nowrap' }}>
                {refBusy ? 'Checking…' : 'Apply'}
              </button>
            </div>
            {refMsg && <div style={{ marginTop:8, fontFamily:WH.sans, fontSize:13, fontWeight:600, color:WH.orange }}>{refMsg}</div>}
          </div>
        ) : (
          <button onClick={()=>setRefOpen(true)}
            style={{ alignSelf:'flex-start', background:'transparent', border:0, padding:0, fontFamily:WH.sans, fontSize:13, fontWeight:600, color:WH.slate, textDecoration:'underline', cursor:'pointer' }}>
            Have a referral code?
          </button>
        ))}

        <button
          onClick={go}
          disabled={going}
          style={{ padding:'16px', background:ready?WH.orange:WH.slate, color:ready?WH.ink:WH.cream, border:0, borderRadius:12, fontFamily:WH.sans, fontSize:16, fontWeight:700, letterSpacing:'-0.01em', cursor:ready?'pointer':'not-allowed', transition:'background .15s' }}>
          {going ? (copy.loadingLabel || stepMsg) : (copy.submitLabel || 'See my savings →')}
        </button>

        <div style={{ display:'flex', flexDirection:'column', gap:8 }}>
          {[
            'Satellite analysis of your actual roof',
            'Your panel layout, on your real roof photo',
            'Year-one and 25-year savings',
            'Book your free survey on the spot',
          ].map((t,i)=>(
            <div key={i} style={{ display:'flex', gap:10, alignItems:'flex-start', fontFamily:WH.sans, fontSize:13.5, color:WH.slate, lineHeight:1.4 }}>
              <span style={{ width:16, height:16, borderRadius:'50%', background:WH.sky, color:WH.ink, display:'flex', alignItems:'center', justifyContent:'center', fontSize:10, fontWeight:700, flexShrink:0, marginTop:1 }}>✓</span>
              {t}
            </div>
          ))}
        </div>

        <div style={{ fontFamily:WH.sans, fontSize:12, color:WH.slate, borderTop:`1px solid ${WH.ink}1A`, paddingTop:14 }}>
          {copy.reassurance || 'No phone number needed.'} Don't know your Eircode? <a href="https://finder.eircode.ie/" target="_blank" rel="noreferrer" style={{ color:WH.orange, fontWeight:600 }}>Look it up →</a>
        </div>
      </div>
      <style>{`
        .brand-range{-webkit-appearance:none;appearance:none;width:100%;height:6px;background:${WH.ink}15;border-radius:999px;outline:none;margin-top:16px;}
        .brand-range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:24px;height:24px;background:${WH.orange};border:2px solid ${WH.ink};border-radius:50%;cursor:grab;}
        .brand-range::-webkit-slider-thumb:active{cursor:grabbing;}
        .brand-range::-moz-range-thumb{width:24px;height:24px;background:${WH.orange};border:2px solid ${WH.ink};border-radius:50%;cursor:grab;}
        .brand-range::-moz-range-track{height:6px;background:${WH.ink}15;border-radius:999px;}
      `}</style>
    </div>
  );
}
