/* global React, BrainMark, Wordmark, TrackerView, I, StepHead, CheckRow, NavFooter, Field */
const { useState, useRef, useEffect, useLayoutEffect } = React;

/* ---------- tiny helpers ---------- */
// render **bold** within text
function fmt(text) {
  const parts = text.split(/(\*\*[^*]+\*\*)/g);
  return parts.map((p, i) =>
    p.startsWith('**') && p.endsWith('**')
      ? <strong key={i} style={{ fontWeight: 600 }}>{p.slice(2, -2)}</strong>
      : <React.Fragment key={i}>{p}</React.Fragment>
  );
}
const uid = () => Math.random().toString(36).slice(2);

function readPosDraft(key) {
  try { return JSON.parse(localStorage.getItem(key) || 'null'); } catch { return null; }
}

function hasMeaningfulDraftValue(key, value) {
  if (!value || typeof value !== 'object') return Boolean(value);
  if (key === 'bevri_pos_app_v1') {
    return Boolean(
      (value.phase && value.phase !== 'welcome') ||
      (Array.isArray(value.messages) && value.messages.length > 0) ||
      value.intent
    );
  }
  // Loan-detail drafts: the agreements gate writes consent into these keys
  // before the section is ever visited, so consent alone (or an operator
  // dual-written address) must not count as loan-details progress.
  if (key === 'bevri_purchase_v1' || key === 'bevri_refinance_v1') {
    const d = value.data || {};
    return Boolean(
      d.price || d.value || d.buying || d.use || d.currentUse || d.futureUse ||
      d.ptype || d.mainGoal || d.initGoal || d.hasAgent != null || d.currentBalance
    );
  }
  return Object.keys(value).length > 0;
}

function stageFromSavedDraft(savedApp) {
  if (savedApp?.phase && savedApp.phase !== 'welcome') return savedApp.phase;
  // Furthest-progress-first; borrower now precedes the loan-details flows.
  const stageKeys = [
    ['bevri_questions_v1', 'questions'],
    ['bevri_credit_v1', 'credit'],
    ['bevri_reo_v1', 'realestate'],
    ['bevri_assets_v1', 'assets'],
    ['bevri_income_v1', 'employment'],
    ['bevri_refinance_v1', 'refinance'],
    ['bevri_purchase_v1', 'purchase'],
    ['bevri_borrower_v1', 'borrower'],
  ];
  for (const [key, phase] of stageKeys) {
    if (hasMeaningfulDraftValue(key, readPosDraft(key))) return phase;
  }
  return savedApp?.phase || 'welcome';
}

function savedLoanDraftMeta(savedApp) {
  const keys = window.BevriPosStorage?.baseKeys || [
    'bevri_purchase_v1', 'bevri_refinance_v1', 'bevri_borrower_v1', 'bevri_income_v1',
    'bevri_assets_v1', 'bevri_reo_v1', 'bevri_credit_v1', 'bevri_questions_v1', 'bevri_documents_v1', 'bevri_pos_app_v1',
  ];
  const hasDraft = keys.some(key => hasMeaningfulDraftValue(key, readPosDraft(key)));
  return { hasDraft, phase: stageFromSavedDraft(savedApp), loanId: window.BevriPosStorage?.loanId || '' };
}

// Data-derived section completion (submitted-aware island): sections filled
// by chat or document auto-fill look complete in the rail even when their
// flow was never walked. Union-ed with the visited-flow completedStages.
const POS_DECLARATION_KEYS = ['occupyPrimary','priorOwnership','sellerRel','undisclosed','otherMortgage','newCredit','priorityLien','coSigner','judgments','fedDebt','lawsuit','deedInLieu','shortSale','foreclosure','bankruptcy'];

function deriveCompletedStagesFromData() {
  const done = [];
  try {
    const num = v => { const n = Number(String(v ?? '').replace(/[$,\s]/g, '')); return Number.isFinite(n) ? n : 0; };
    const purchase = readPosDraft('bevri_purchase_v1')?.data || {};
    const refinance = readPosDraft('bevri_refinance_v1')?.data || {};
    if (num(purchase.price) > 0 || num(refinance.value) > 0 || num(refinance.currentBalance) > 0) done.push('loan');
    const b = readPosDraft('bevri_borrower_v1')?.data || {};
    if (b?.name?.first && b?.name?.last && (b.email || b.phone)) done.push('borrower');
    // A record only counts once it carries an amount (same rule as the
    // submit gate), so the rail and the required checklist never disagree.
    const incomeHasAmt = rec => rec && (num(rec.salaryAmt) > 0 || (num(rec.hourlyRate) > 0 && num(rec.hoursWeek) > 0) || num(rec.incomeAfterExp) > 0 || num(rec.retAmount) > 0 || num(rec.monthlyAmt) > 0);
    const incomes = readPosDraft('bevri_income_v1')?.incomes || {};
    if (Object.values(incomes).some(list => Array.isArray(list) && list.some(incomeHasAmt))) done.push('employment');
    const assetHasAmt = rec => rec && (num(rec.balance) > 0 || num(rec.giftValue) > 0 || num(rec.otherValue) > 0);
    const assets = readPosDraft('bevri_assets_v1')?.assets || {};
    if (Object.values(assets).some(list => Array.isArray(list) && list.some(assetHasAmt))) done.push('assets');
    const props = readPosDraft('bevri_reo_v1')?.properties || {};
    if (Object.values(props).some(list => Array.isArray(list) && list.length > 0)) done.push('reo');
    const answers = readPosDraft('bevri_questions_v1')?.answers || {};
    const primaryAnswers = answers.primary || {};
    const answered = POS_DECLARATION_KEYS.filter(k => primaryAnswers[k] === 'yes' || primaryAnswers[k] === 'no').length;
    if (primaryAnswers.complete === true || answered >= POS_DECLARATION_KEYS.length) done.push('questions');
    if (window.__bevriLoanStatus && window.__bevriLoanStatus.submitted) done.push('review');
  } catch {}
  return done;
}

/* ---------- icons ---------- */
const IconPurchase = ({ s = 26 }) => (
  <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
       strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
    <path d="M3 11.5 12 4l9 7.5" />
    <path d="M5 10.5V20h14v-9.5" />
    <path d="M10 20v-5h4v5" />
  </svg>
);
const IconRefi = ({ s = 26 }) => (
  <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
       strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
    <path d="M20 7a8 8 0 0 0-14.3-3" />
    <path d="M4 17a8 8 0 0 0 14.3 3" />
    <path d="M16.5 4H20v3.5" />
    <path d="M7.5 20H4v-3.5" />
  </svg>
);
const IconSend = ({ s = 18 }) => (
  <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
       strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <path d="M12 19V5" /><path d="m6 11 6-6 6 6" />
  </svg>
);
const IconPlus = ({ s = 18 }) => (
  <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
       strokeWidth="1.8" strokeLinecap="round"><path d="M12 5v14M5 12h14" /></svg>
);

/* ---------- AI reply logic (canned for now) ---------- */
function aiReplyFor(text) {
  const t = text.toLowerCase();
  if (/purchase|buy|buying|new home|home/.test(t) && !/refi|refinance/.test(t)) {
    return {
      text: "Congratulations on taking the first step toward a new home. To tailor your options, I'll ask a few quick questions. It takes about **3 minutes**, and nothing impacts your credit yet. Ready to begin?",
      quick: ["Let's begin", "What will I need?"],
    };
  }
  if (/refi|refinance|lower|rate|cash out|equity/.test(t)) {
    return {
      text: "Smart move. Refinancing could **lower your monthly payment** or let you tap your home's equity. Let's see what you qualify for. I just need a few details. Ready?",
      quick: ["Let's begin", "How much could I save?"],
    };
  }
  if (/begin|let's go|start|ready|yes/.test(t)) {
    return {
      text: "Perfect. I'm setting up your application now. We'll pick up right here on the next step.",
      quick: [],
    };
  }
  return {
    text: "Happy to help with that. To point you in the right direction: are you looking to **purchase** a new home, or **refinance** an existing loan?",
    quick: ["Purchase", "Refinance"],
  };
}

/* ---- identity-first gate helpers ---- */
const igDigits = s => (s || '').replace(/[^\d]/g, '');
const igEmailOk = e => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e || '');
const igPhoneOk = p => igDigits(p).length === 10;
const igFmtPhone = s => {
  const d = igDigits(s).slice(0, 10);
  if (d.length > 6) return `(${d.slice(0,3)}) ${d.slice(3,6)}-${d.slice(6)}`;
  if (d.length > 3) return `(${d.slice(0,3)}) ${d.slice(3)}`;
  return d ? `(${d}` : '';
};

/** True when the borrower draft already carries a full identity (name + reachable contact). */
function identityDraftComplete() {
  try {
    const d = readPosDraft('bevri_borrower_v1')?.data || {};
    return Boolean(d.name?.first?.trim() && d.name?.last?.trim() && igEmailOk(d.email) && igPhoneOk(d.phone));
  } catch { return false; }
}

/**
 * Identity-first capture (Court/Chelle feedback, 2026-08-19): the very first
 * screen after choosing a loan type asks name, email, and phone; otherwise we
 * lose abandoning borrowers as leads. Writes straight into the borrower draft
 * (bevri_borrower_v1), so autosave syncs it, the bridge links the Borrower
 * contact, and the lead appears in the LO's pipeline from screen one. Borrower
 * Info skips its now pre-filled name/contact steps. Full agreements follow on
 * the next screen; this screen carries a light privacy-policy disclosure.
 */
function IdentityGate({ onBack, onContinue }) {
  const KEY = 'bevri_borrower_v1';
  const [form, setForm] = useState(() => {
    const d = readPosDraft(KEY)?.data || {};
    return { first: d.name?.first || '', last: d.name?.last || '', email: d.email || '', phone: d.phone || '' };
  });
  const [touched, setTouched] = useState(false);
  const valid = form.first.trim() && form.last.trim() && igEmailOk(form.email) && igPhoneOk(form.phone);

  const persist = () => {
    try {
      const saved = readPosDraft(KEY) || {};
      const data = saved.data && typeof saved.data === 'object' ? saved.data : {};
      localStorage.setItem(KEY, JSON.stringify({
        ...saved,
        data: {
          ...data,
          name: { ...(data.name || {}), first: form.first.trim(), last: form.last.trim() },
          email: form.email.trim(),
          phone: form.phone,
        },
      }));
    } catch {}
  };
  const submit = () => {
    if (!valid) { setTouched(true); return; }
    persist();
    onContinue();
  };

  return (
    <main className="flow"><div className="flow-col">
      <div className="step step-anim">
        <StepHead title="First, tell us about you"
          sub="Just your name and the best way to reach you. Your progress saves from this very first step, so you can pick up anytime, on any device." />
        <div className="field-row">
          <Field label="First name" value={form.first} onChange={v => setForm(f => ({ ...f, first: v }))}
            placeholder="Jane" error={touched && !form.first.trim() ? 'Required' : ''} />
          <Field label="Last name" value={form.last} onChange={v => setForm(f => ({ ...f, last: v }))}
            placeholder="Doe" error={touched && !form.last.trim() ? 'Required' : ''} />
        </div>
        <Field label="Email" type="email" value={form.email} onChange={v => setForm(f => ({ ...f, email: v }))}
          placeholder="jane@example.com" error={touched && !igEmailOk(form.email) ? 'Enter a valid email' : ''} />
        <Field label="Mobile phone" inputMode="numeric" value={form.phone} onChange={v => setForm(f => ({ ...f, phone: igFmtPhone(v) }))}
          placeholder="(555) 123-4567" error={touched && !igPhoneOk(form.phone) ? 'Enter a 10-digit phone number' : ''} />
        <p className="ig-privacy">
          Your information is private and only used for your application. By continuing you agree to
          Bevri's <a className="agree-link" href="/privacy" target="_blank" rel="noopener noreferrer">Privacy Policy</a>.
        </p>
        <NavFooter onBack={onBack} onNext={submit} nextLabel="Continue" nextDisabled={!valid} />
      </div>
    </div></main>
  );
}

/**
 * Legal consent gate, shown right after the identity screen and before the
 * rest of the application. Consent is stored in the SAME draft keys the
 * flows always used (bevri_purchase_v1/bevri_refinance_v1 data.agree), so
 * storage, the LOS bridge, and the operator see no new shape; the flows skip
 * their own agreement steps when consent already exists.
 */
function AgreementsGate({ loanType, onBack, onContinue }) {
  const KEY = loanType === 'refinance' ? 'bevri_refinance_v1' : 'bevri_purchase_v1';
  const [agree, setAgree] = useState(() => {
    const saved = readPosDraft(KEY);
    return { electronic: false, privacy: false, origination: false, ...((saved && saved.data && saved.data.agree) || {}) };
  });
  const persist = next => {
    setAgree(next);
    try {
      const saved = readPosDraft(KEY) || {};
      localStorage.setItem(KEY, JSON.stringify({ ...saved, data: { ...(saved.data || {}), agree: next } }));
    } catch {}
  };
  const tgl = k => persist({ ...agree, [k]: !agree[k] });
  const all = agree.electronic && agree.privacy && agree.origination;
  return (
    <main className="flow"><div className="flow-col">
      <div className="step step-anim">
        <StepHead title="Let's get started"
          sub="Please review and agree to the following before we continue. Tap a title to read the full document." />
        <div className="sum-card">
          <div className="agree-list">
            <CheckRow checked={agree.electronic} onToggle={() => tgl('electronic')}>
              I have read and agree to the <a className="agree-link" href="/terms" target="_blank" rel="noopener noreferrer" onClick={e => e.stopPropagation()}>Electronic Communication Agreement</a>.
            </CheckRow>
            <CheckRow checked={agree.privacy} onToggle={() => tgl('privacy')}>
              I have read and agree to Bevri's <a className="agree-link" href="/privacy" target="_blank" rel="noopener noreferrer" onClick={e => e.stopPropagation()}>Privacy Policy</a>.
            </CheckRow>
            <CheckRow checked={agree.origination} onToggle={() => tgl('origination')}>
              I have read and agree to Bevri's <a className="agree-link" href="/terms" target="_blank" rel="noopener noreferrer" onClick={e => e.stopPropagation()}>Mortgage Loan Origination Agreement</a>.
            </CheckRow>
          </div>
        </div>
        <NavFooter onBack={onBack} onNext={onContinue} nextLabel="Confirm and Continue" nextDisabled={!all} />
      </div>
    </div></main>
  );
}

/* ===================================================================== */
function App() {
  const savedApp = (() => { try { return JSON.parse(localStorage.getItem('bevri_pos_app_v1')); } catch { return null; } })();
  const [draftMeta] = useState(() => savedLoanDraftMeta(savedApp));
  const hasSavedLoanDraft = draftMeta.hasDraft;
  const _phaseOrder = { borrower: 1, purchase: 2, refinance: 2, employment: 3, assets: 4, realestate: 5, reo: 5, credit: 6, questions: 7, review: 8 };
  const overallPct = draftMeta.phase ? Math.round(((_phaseOrder[draftMeta.phase] || 0) / 8) * 100) : 0;
  const [phase, setPhase] = useState(savedApp?.phase || 'welcome'); // welcome | chat | purchase
  const [messages, setMessages] = useState(savedApp?.messages || []);
  const [typing, setTyping] = useState(false);
  const [draft, setDraft] = useState('');
  const [intent, setIntent] = useState(savedApp?.intent || null); // purchase | refinance
  const [borrowerFrom, setBorrowerFrom] = useState(savedApp?.borrowerFrom || 'purchase'); // which flow led into Borrower Info
  const [editingFromReview, setEditingFromReview] = useState(false);
  const [flowProg, setFlowProg] = useState(savedApp?.flowProg || { fill: 0, stepTitle: '' }); // within-stage progress reported by flows
  const [completedStages, setCompletedStages] = useState(savedApp?.completedStages || []);
  // Re-derive data-based completion when chat or auto-fill writes fields.
  const [dataTick, setDataTick] = useState(0);
  useEffect(() => {
    const bump = () => setDataTick(t => t + 1);
    window.addEventListener('bevri:fields-autofilled', bump);
    return () => window.removeEventListener('bevri:fields-autofilled', bump);
  }, []);
  void dataTick;
  const effectiveCompletedStages = Array.from(new Set([...(completedStages || []), ...deriveCompletedStagesFromData()]));
  const [confirmNewOpen, setConfirmNewOpen] = useState(false);
  const [signupOpen, setSignupOpen] = useState(false);
  const threadRef = useRef(null);
  const taRef = useRef(null);

  // keep resumable app-shell state scoped to the current loanId/draft token
  useEffect(() => {
    try { localStorage.setItem('bevri_pos_app_v1', JSON.stringify({ phase, messages, intent, borrowerFrom, flowProg, completedStages })); } catch {}
  }, [phase, messages, intent, borrowerFrom, flowProg, completedStages]);

  // Let welcome/chat screens open SignUpNudge via the same event AppShell uses.
  useEffect(() => {
    const openSignup = () => setSignupOpen(true);
    window.addEventListener('bevri:signup-open', openSignup);
    return () => window.removeEventListener('bevri:signup-open', openSignup);
  }, []);

  // A returning borrower with a SUBMITTED application lands on the tracker,
  // not back in the draft flow. Runs once on boot; any failure (offline,
  // unsubmitted, no loan yet) leaves today's behavior untouched.
  useEffect(() => {
    let alive = true;
    const check = window.fetchPosLoanStatus ? window.fetchPosLoanStatus() : Promise.resolve(null);
    check.then(d => {
      if (alive && d && d.success && d.submitted) setPhase('tracker');
    }).catch(() => {});
    return () => { alive = false; };
    // eslint-disable-next-line
  }, []);

  // auto-grow textarea
  useLayoutEffect(() => {
    const el = taRef.current;
    if (!el) return;
    el.style.height = 'auto';
    el.style.height = Math.min(el.scrollHeight, 180) + 'px';
  }, [draft]);

  // keep thread scrolled to bottom
  useEffect(() => {
    const el = threadRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [messages, typing]);

  // The operator (chat) can move the borrower to a section via a go_to_step tool.
  useEffect(() => {
    const onNav = e => {
      const step = e && e.detail && e.detail.step;
      if (!step) return;
      const map = { loan: borrowerFrom, purchase: 'purchase', refinance: 'refinance', borrower: 'borrower', employment: 'employment', assets: 'assets', realestate: 'realestate', reo: 'realestate', credit: 'credit', questions: 'questions', review: 'review' };
      const target = map[step];
      if (target) { setPhase(target); setFlowProg({ fill: 0, stepTitle: '' }); }
    };
    window.addEventListener('bevri:pos-navigate', onNav);
    return () => window.removeEventListener('bevri:pos-navigate', onNav);
  }, [borrowerFrom]);

  function pushAI(reply) {
    setTyping(false);
    setMessages(m => [...m, { id: uid(), role: 'ai', ...reply }]);
  }

  function instantReplyFor(clean, priorMessages) {
    const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
    const timeout = controller ? setTimeout(() => controller.abort(), 4500) : null;
    return fetch('/api/pos/intake/instant-reply', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        message: clean,
        source: 'pos-fresh-welcome',
        messages: priorMessages.map(m => ({ role: m.role === 'ai' ? 'assistant' : m.role, text: m.text, id: m.id })),
      }),
      signal: controller?.signal,
    })
      .then(r => r.ok ? r.json() : Promise.reject(new Error('instant operator unavailable')))
      .then(data => ({ text: data.text, quick: data.quick }))
      .catch(() => aiReplyFor(clean))
      .finally(() => { if (timeout) clearTimeout(timeout); });
  }

  function send(text) {
    const clean = text.trim();
    if (!clean) return;
    setDraft('');
    const t = clean.toLowerCase();
    if (/purchase|buy|buying|new home/.test(t)) setIntent('purchase');
    else if (/refi|refinance/.test(t)) setIntent('refinance');

    const priorMessages = messages;
    const nextMessages = [...priorMessages];
    if (priorMessages.length === 0) {
      nextMessages.push({ id: uid(), role: 'ai', text: "Let's get started. How can I help you today?", greeting: true });
    }
    nextMessages.push({ id: uid(), role: 'user', text: clean });
    setMessages(nextMessages);
    setPhase('chat');
    setTyping(true);
    instantReplyFor(clean, priorMessages).then(pushAI);
  }

  const onKeyDown = e => {
    if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(draft); }
  };

  function reset() {
    if (window.BevriPosStorage?.reset) return window.BevriPosStorage.reset();
    setMessages([]); setPhase('welcome'); setDraft(''); setTyping(false); setIntent(null); setCompletedStages([]);
    try { localStorage.removeItem('bevri_purchase_v1'); localStorage.removeItem('bevri_refinance_v1'); localStorage.removeItem('bevri_borrower_v1'); localStorage.removeItem('bevri_income_v1'); localStorage.removeItem('bevri_assets_v1'); localStorage.removeItem('bevri_reo_v1'); localStorage.removeItem('bevri_credit_v1'); localStorage.removeItem('bevri_questions_v1'); localStorage.removeItem('bevri_documents_v1'); localStorage.removeItem('bevri_pos_app_v1'); localStorage.removeItem('bevri_chat_v1'); } catch {}
  }
  function confirmStartNew() {
    setConfirmNewOpen(true);
  }
  function doReset() {
    setConfirmNewOpen(false);
    reset();
    window.dispatchEvent(new CustomEvent('bevri:toast', { detail: { message: 'Application cleared. Ready to start fresh', kind: '' } }));
  }
  function resumeSavedDraft() {
    if (savedApp?.borrowerFrom) setBorrowerFrom(savedApp.borrowerFrom);
    setFlowProg(savedApp?.flowProg || { fill: 0, stepTitle: '' });
    setPhase(draftMeta.phase || 'welcome');
  }
  const markComplete = id => setCompletedStages(prev => prev.includes(id) ? prev : [...prev, id]);
  // Borrower-first order (exec decision 2026-08-06): intent choice ->
  // agreements -> Borrower Info -> Purchase/Refinance Info -> Employment.
  // Identity-first: name/email/phone are the first screens after the loan
  // type choice (skipped when the draft already has them, e.g. on resume).
  const enterPurchase = () => { setIntent('purchase'); setBorrowerFrom('purchase'); setPhase(identityDraftComplete() ? 'agreements' : 'identity'); };
  const enterRefinance = () => { setIntent('refinance'); setBorrowerFrom('refinance'); setPhase(identityDraftComplete() ? 'agreements' : 'identity'); };
  const exitPurchase = () => setPhase('welcome');
  const enterBorrower = () => { setPhase('borrower'); setFlowProg({ fill: 0, stepTitle: '' }); };
  const enterLoanDetails = () => { markComplete('borrower'); setPhase(borrowerFrom === 'refinance' ? 'refinance' : 'purchase'); setFlowProg({ fill: 0, stepTitle: '' }); };
  const enterEmployment = () => { markComplete('loan'); setPhase('employment'); setFlowProg({ fill: 0, stepTitle: '' }); };
  const enterAssets = () => { markComplete('employment'); setPhase('assets'); setFlowProg({ fill: 0, stepTitle: '' }); };
  const enterRealEstate = () => { markComplete('assets'); setPhase('realestate'); setFlowProg({ fill: 0, stepTitle: '' }); };
  const enterCredit = () => { markComplete('reo'); setPhase('credit'); setFlowProg({ fill: 0, stepTitle: '' }); };
  const enterQuestions = () => { markComplete('credit'); setPhase('questions'); setFlowProg({ fill: 0, stepTitle: '' }); };
  const enterReview = () => { markComplete('questions'); setPhase('review'); setEditingFromReview(false); setFlowProg({ fill: 95, stepTitle: 'review' }); };
  const editFromReview = stage => { setEditingFromReview(true); setPhase(stage === 'loan' ? borrowerFrom : stage); };
  const returnToReview = () => { setEditingFromReview(false); setPhase('review'); const el = document.querySelector('.flow'); if (el) el.scrollTop = 0; };
  // While editing from final review, finishing a section returns to Review &
  // Submit instead of advancing the whole application pipeline.
  const sectionContinue = advance => () => { if (editingFromReview) return returnToReview(); advance(); };
  function handleQuick(q) {
    if (/^(Purchase|Buying a home|Buy a home)$/i.test(q)) return enterPurchase();
    if (/^(Refinance|Refinancing)$/i.test(q)) return enterRefinance();
    if (q === 'Check what I qualify for') return enterPurchase();
    if (q === "Let's begin" && intent === 'purchase') return enterPurchase();
    if (q === "Let's begin" && intent === 'refinance') return enterRefinance();
    send(q);
  }

  // ---- application shell state ----
  const isFlow = phase === 'identity' || phase === 'agreements' || phase === 'purchase' || phase === 'refinance' || phase === 'borrower' || phase === 'employment' || phase === 'assets' || phase === 'realestate' || phase === 'credit' || phase === 'questions' || phase === 'review' || phase === 'tracker';
  const loanTypeOf = (phase === 'identity' || phase === 'agreements' || phase === 'borrower' || phase === 'employment' || phase === 'assets' || phase === 'realestate' || phase === 'credit' || phase === 'questions' || phase === 'review') ? borrowerFrom : (phase === 'refinance' ? 'refinance' : 'purchase');
  const stageOf = phase === 'tracker' ? 'review' : phase === 'review' ? 'review' : (phase === 'questions' ? 'questions' : (phase === 'credit' ? 'credit' : (phase === 'realestate' ? 'reo' : (phase === 'assets' ? 'assets' : (phase === 'employment' ? 'employment' : (phase === 'borrower' || phase === 'identity' || phase === 'agreements' ? 'borrower' : 'loan'))))));
  function handleStageClick(id) {
    if (id === 'loan') setPhase(loanTypeOf);
    else if (id === 'borrower') setPhase('borrower');
    else if (id === 'employment') setPhase('employment');
    else if (id === 'assets') setPhase('assets');
    else if (id === 'reo') setPhase('realestate');
    else if (id === 'credit') setPhase('credit');
    else if (id === 'questions') setPhase('questions');
    else if (id === 'review') setPhase('review');
  }

  if (isFlow) {
    return (
      <div className="app">
        <CircuitBg />
        <AppShell loanType={loanTypeOf} currentStage={stageOf} stageFill={flowProg.fill}
          onStageClick={handleStageClick} onHome={exitPurchase} onExit={exitPurchase}
          completedStages={effectiveCompletedStages}
          chatContext={{ stepTitle: flowProg.stepTitle }}>
          {editingFromReview && phase !== 'review' && (
            <div className="review-banner">
              You're editing from final review.
              <button onClick={returnToReview}>Return to Review →</button>
            </div>
          )}
          {phase === 'identity' &&
            <IdentityGate onBack={exitPurchase} onContinue={() => setPhase('agreements')} />}
          {phase === 'agreements' &&
            <AgreementsGate loanType={borrowerFrom} onBack={() => setPhase('identity')} onContinue={enterBorrower} />}
          {phase === 'borrower' &&
            <BorrowerInfo loanType={borrowerFrom}
              onBack={() => setPhase('agreements')}
              onContinue={sectionContinue(enterLoanDetails)}
              onProgress={setFlowProg} />}
          {phase === 'purchase' &&
            <PurchaseFlow onExit={() => setPhase('borrower')} onContinue={sectionContinue(enterEmployment)} onProgress={setFlowProg} />}
          {phase === 'refinance' &&
            <RefinanceFlow onExit={() => setPhase('borrower')} onContinue={sectionContinue(enterEmployment)} onProgress={setFlowProg} />}
          {phase === 'employment' &&
            <EmploymentIncome loanType={borrowerFrom}
              onBack={() => setPhase(borrowerFrom)}
              onContinue={sectionContinue(enterAssets)}
              onProgress={setFlowProg} />}
          {phase === 'assets' &&
            <AssetsSection loanType={borrowerFrom}
              onBack={() => setPhase('employment')}
              onContinue={sectionContinue(enterRealEstate)}
              onProgress={setFlowProg} />}
          {phase === 'realestate' &&
            <RealEstateOwned loanType={borrowerFrom}
              onBack={() => setPhase('assets')}
              onContinue={sectionContinue(enterCredit)}
              onProgress={setFlowProg} />}
          {phase === 'credit' &&
            <CreditLiabilities loanType={borrowerFrom}
              onBack={() => setPhase('realestate')}
              onContinue={sectionContinue(enterQuestions)}
              onProgress={setFlowProg} />}
          {phase === 'questions' &&
            <QuestionsAboutYou loanType={borrowerFrom}
              onBack={() => setPhase('credit')}
              onContinue={sectionContinue(enterReview)}
              onProgress={setFlowProg} />}
          {phase === 'review' &&
            <ReviewSubmit loanType={borrowerFrom}
              onEdit={editFromReview}
              onBack={() => setPhase('questions')}
              onSubmitted={() => setPhase('tracker')}
              onProgress={setFlowProg} />}
          {phase === 'tracker' &&
            <TrackerView onViewApplication={() => setPhase('review')} />}
        </AppShell>
      </div>
    );
  }

  return (
    <div className="app">
      <CircuitBg />

      {/* top bar */}
      <header className="topbar">
        <button className="logo-btn" onClick={() => setPhase('welcome')} title="Back to home">
          <Wordmark size={22} markSize={32} />
        </button>
        <div className="topbar-right">
          <ThemeToggle />
          {hasSavedLoanDraft && <button className="ghost-btn" onClick={confirmStartNew}>New application</button>}
          <button className="ghost-btn sign-in-btn" style={{ fontWeight: 600, borderColor: 'var(--sage)', color: 'var(--sage)' }} onClick={() => setSignupOpen(true)}>Sign in</button>
        </div>
      </header>

      {phase === 'welcome' &&
        <Welcome onPurchase={enterPurchase} onRefinance={enterRefinance} onSend={send}
                 hasSavedLoanDraft={hasSavedLoanDraft} loanId={draftMeta.loanId}
                 overallPct={overallPct}
                 onResume={resumeSavedDraft} onStartNew={confirmStartNew}
                 onSignIn={() => setSignupOpen(true)}
                 draft={draft} setDraft={setDraft} taRef={taRef} onKeyDown={onKeyDown} />}
      {phase === 'chat' &&
        <Chat messages={messages} typing={typing} threadRef={threadRef}
              draft={draft} setDraft={setDraft} taRef={taRef}
              onKeyDown={onKeyDown} onSend={() => send(draft)} onQuick={handleQuick} />}
      <ToastRoot />
      <SignUpNudge open={signupOpen} onClose={() => setSignupOpen(false)} />
      <ConfirmNewModal open={confirmNewOpen} onCancel={() => setConfirmNewOpen(false)} onConfirm={doReset} />
    </div>
  );
}

/* ---------- confirm new application modal ---------- */
function ConfirmNewModal({ open, onCancel, onConfirm }) {
  if (!open) return null;
  return (
    <div className="modal-scrim" onClick={onCancel}>
      <div className="modal" onClick={e => e.stopPropagation()}>
        <div className="modal-title">Start a new application?</div>
        <div className="modal-body">This will clear all answers saved for this session. Your previous responses won't be recoverable after this.</div>
        <div className="modal-actions">
          <button className="btn btn-secondary" onClick={onCancel}>Cancel</button>
          <button className="btn btn-danger" onClick={onConfirm}>Start fresh</button>
        </div>
      </div>
    </div>
  );
}

/* ---------- welcome (page 1) ---------- */
function Welcome({ onPurchase, onRefinance, onSend, hasSavedLoanDraft, loanId, overallPct, onResume, onStartNew, onSignIn, draft, setDraft, taRef, onKeyDown }) {
  // LO white-labeling: an attributed link puts the loan officer's face and
  // name on screen one; unattributed sessions keep the Bevri mark. AppShell
  // loads first, so the shared branding resolver is available here.
  const [welcomeLo, setWelcomeLo] = useState(window.__bevriLoBranding || null);
  useEffect(() => {
    let alive = true;
    window.fetchPosLoBranding?.().then(lo => { if (alive && lo) setWelcomeLo(lo); });
    return () => { alive = false; };
  }, []);

  return (
    <main className="welcome">
      <div className="welcome-inner">
        <div className="hero-mark">
          <span className="hero-ring" />
          <span className="hero-ring-2" />
          {welcomeLo && welcomeLo.displayName
            ? <window.LoAvatar lo={welcomeLo} size={52} />
            : <BrainMark size={52} />}
        </div>
        <p className="eyebrow mono">FREE PRE-QUALIFICATION</p>
        {welcomeLo && welcomeLo.displayName && (
          <p className="hero-lo step-anim">
            with <b>{welcomeLo.displayName}</b>
            {[welcomeLo.nmls ? 'NMLS ' + welcomeLo.nmls : null, welcomeLo.companyName].filter(Boolean).map(part => ' \u00b7 ' + part).join('')}
          </p>
        )}
        <h1 className="hero-title">See what you <span className="hero-accent">qualify</span> for.</h1>
        <p className="hero-sub">Answer a few questions and get your personalized result.</p>

        <div className="trust-strip">
          <span className="trust-item">
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
            About 8 minutes
          </span>
          <span className="trust-item">
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
            No credit impact
          </span>
          <span className="trust-item">
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12.5 10 17.5 19 7"/></svg>
            Free to start
          </span>
        </div>

        {hasSavedLoanDraft && (
          <section className="resume-card" aria-label="Saved application">
            <div className="resume-copy">
              <span className="resume-kicker mono">Progress saved{loanId ? ` · ${loanId.slice(0, 8)}…` : ''}</span>
              <h2>Pick up where you left off</h2>
              {overallPct > 0 && (
                <div className="resume-prog">
                  <div className="resume-prog-bar">
                    <div className="resume-prog-fill" style={{ width: overallPct + '%' }} />
                  </div>
                  <span className="resume-prog-label">{overallPct}% complete</span>
                </div>
              )}
              <p>Your answers are saved to this device. Continue anytime, or start fresh for a different loan request.</p>
            </div>
            <div className="resume-actions">
              <button className="resume-primary" onClick={onResume}>Continue application</button>
              <button className="resume-secondary" onClick={onStartNew}>Start fresh</button>
              <button type="button" onClick={onSignIn} style={{ background: 'none', border: 0, padding: '4px 0 0', font: 'inherit', fontSize: 13, color: 'var(--sage)', textDecoration: 'underline', cursor: 'pointer', textAlign: 'center' }}>
                Sign in to your account →
              </button>
            </div>
          </section>
        )}

        <div className="choices">
          <ChoiceCard icon={<IconPurchase />} title="Purchase"
            sub="I'm buying a new home" onClick={onPurchase} featured />
          <ChoiceCard icon={<IconRefi />} title="Refinance"
            sub="Lower my rate or use my equity" onClick={onRefinance} />
        </div>

        <div className="sign-in-strip">
          Already have an account?{' '}
          <button type="button" className="sign-in-strip-btn" onClick={onSignIn}>Sign in →</button>
        </div>

        <Composer draft={draft} setDraft={setDraft} taRef={taRef}
                  onKeyDown={onKeyDown} onSend={() => onSend(draft)} />

        <div className="examples">
          {["What can I afford?", "How much down payment?", "How long does it take?"].map(x => (
            <button key={x} className="example-chip" onClick={() => onSend(x)}>{x}</button>
          ))}
        </div>

        <div className="security-row">
          <span>
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ verticalAlign: 'middle', marginRight: 3 }}><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
            Bank-grade encryption
          </span>
          <span>·</span>
          <span>Equal Housing Lender</span>
          <span>·</span>
          <span>NMLS #2026</span>
        </div>
      </div>
      <div className="powered-by-strip">Powered by <span>bevri.ai</span></div>
      </main>
  );
}

function ChoiceCard({ icon, title, sub, onClick, featured }) {
  return (
    <button className={'choice' + (featured ? ' featured' : '')} onClick={onClick}>
      <span className="choice-icon">{icon}</span>
      <span className="choice-text">
        <span className="choice-title">{title}</span>
        <span className="choice-sub">{sub}</span>
      </span>
      <span className="choice-arrow">→</span>
    </button>
  );
}

/* ---------- chat (conversation state) ---------- */
function Chat({ messages, typing, threadRef, draft, setDraft, taRef, onKeyDown, onSend, onQuick }) {
  const lastAiIdx = (() => {
    for (let i = messages.length - 1; i >= 0; i--) if (messages[i].role === 'ai') return i;
    return -1;
  })();
  return (
    <main className="chat">
      <div className="thread" ref={threadRef}>
        <div className="thread-inner">
          {messages.map((m, i) => (
            <Bubble key={m.id} m={m}
              showQuick={i === lastAiIdx && !typing}
              onQuick={onQuick} />
          ))}
          {typing && <TypingRow />}
        </div>
      </div>
      <div className="composer-dock">
        <div className="composer-dock-inner">
          <Composer draft={draft} setDraft={setDraft} taRef={taRef}
                    onKeyDown={onKeyDown} onSend={onSend} />
        </div>
      </div>
    </main>
  );
}

function Bubble({ m, showQuick, onQuick }) {
  if (m.role === 'user') {
    return <div className="row row-user"><div className="bubble bubble-user">{m.text}</div></div>;
  }
  return (
    <div className="row row-ai">
      <div className="ai-avatar"><BrainMark size={26} /></div>
      <div className="ai-body">
        <div className="bubble bubble-ai">{fmt(m.text)}</div>
        {showQuick && m.quick && m.quick.length > 0 && (
          <div className="quick-row">
            {m.quick.map(q => (
              <button key={q} className="quick-chip" onClick={() => onQuick(q)}>{q}</button>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

function TypingRow() {
  return (
    <div className="row row-ai">
      <div className="ai-avatar"><BrainMark size={26} /></div>
      <div className="ai-body">
        <div className="bubble bubble-ai typing">
          <span className="dot" /><span className="dot" /><span className="dot" />
        </div>
      </div>
    </div>
  );
}

/* ---------- composer (shared input bar) ---------- */
function Composer({ draft, setDraft, taRef, onKeyDown, onSend }) {
  return (
    <div className="composer-wrap">
      <div className="composer">
        <button className="comp-attach" title="Add a question"><IconPlus /></button>
        <textarea ref={taRef} className="comp-input" rows={1}
          placeholder="Message Bevri…  ask anything about your loan"
          value={draft} onChange={e => setDraft(e.target.value)} onKeyDown={onKeyDown} />
        <button className={"comp-send" + (draft.trim() ? " on" : "")}
          onClick={onSend} disabled={!draft.trim()} title="Send"><IconSend /></button>
      </div>
      <p className="disclaimer mono">
        Bevri provides guidance, not a commitment to lend. Equal Housing Lender · NMLS #2026
      </p>
    </div>
  );
}

/* ---------- faint circuit background ---------- */
function CircuitBg() {
  return (
    <svg className="circuit-bg" viewBox="0 0 1440 900" preserveAspectRatio="xMidYMid slice"
         fill="none" aria-hidden="true">
      <g stroke="#49765b" strokeWidth="1.5" opacity="0.13" strokeLinecap="round" strokeLinejoin="round">
        <path d="M-20 140 H180 V90 H360" /><circle cx="360" cy="90" r="4" />
        <path d="M-20 220 H120 V270 H300 V230 H520" /><circle cx="520" cy="230" r="4" />
        <path d="M1460 760 H1240 V810 H1040" /><circle cx="1040" cy="810" r="4" />
        <path d="M1460 680 H1320 V630 H1140 V670 H980" /><circle cx="980" cy="670" r="4" />
        <path d="M1460 200 H1300 V150 H1160" /><circle cx="1160" cy="150" r="4" />
        <path d="M-20 700 H140 V650 H300" /><circle cx="300" cy="650" r="4" />
      </g>
    </svg>
  );
}

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