/* Shared components & primitives — Shoppes at San Felipe (JAL-JCP) */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ------------------------------------------------------------------ */
/*  Real deal data                                                     */
/* ------------------------------------------------------------------ */
const DEAL = {
  sponsor: 'JAL-JCP Real Estate Partners',
  principals: [
    { name:'Justin A. Levine', email:'jlevine@jalstrategies.com', firm:'JAL-JCP Real Estate Partners' },
    { name:'James C. Pappas', email:'jcp@jcpinv.com', firm:'JAL-JCP Real Estate Partners' },
  ],
  property: 'The Shoppes at San Felipe',
  address: '1415 S. Voss Rd · NEC San Felipe & S. Voss · Houston, TX 77057',
  gla: '61,196 SF',
  acres: 4.54,
  occupancy: '95.2%',
  tenants: 21,
  walt: '5.77 yrs',
  purchase: '$31,750,000',
  basis: '$32,500,000',
  basisPSF: '$163 / SF',
  capIn: '5.81%',
  noiY1: '$1,845,794',
  lpEquity: '$13,000,000',
  ltv: '60%',
  debt: '$19,500,000',
  rate: '5.50%',
  hold: 10,
  projIRR: '16.4%',
  projMult: '3.69×',
  lpIRR: '14.0%',
  lpMult: '3.10×',
  cash: '4.7–8.0%',
  exitPSF: 300,
  exitLandSF: 197762,
  exitGross: '$59,328,600',
  exitNet: '$37,822,475',
  lpTotal: '$40,353,557',
  refiY5: '$2,495,492',
};

const PALETTES = {
  institutional: {
    name: 'Midnight',
    ivory:'#F4F2ED', ivory2:'#EAE6DC', ink:'#0B163C', ink2:'#162148',
    muted:'#6E6A61', rule:'#D6D1C2', accent:'#3A243A', accentSoft:'#A0B4C3',
  },
  editorial: {
    name: 'Aubergine',
    ivory:'#F4F2ED', ivory2:'#ECE4E4', ink:'#3A243A', ink2:'#4A2F4A',
    muted:'#6E6A61', rule:'#D9CBD4', accent:'#0B163C', accentSoft:'#A0B4C3',
  },
  verdant: {
    name: 'Slate',
    ivory:'#F4F2ED', ivory2:'#E4EAEE', ink:'#0B163C', ink2:'#162148',
    muted:'#6E6A61', rule:'#C8D2DC', accent:'#A0B4C3', accentSoft:'#3A243A',
  },
};

function applyPalette(key){
  const p = PALETTES[key] || PALETTES.institutional;
  const r = document.documentElement.style;
  r.setProperty('--ivory', p.ivory);
  r.setProperty('--ivory-2', p.ivory2);
  r.setProperty('--ink', p.ink);
  r.setProperty('--ink-2', p.ink2);
  r.setProperty('--muted', p.muted);
  r.setProperty('--rule', p.rule);
  r.setProperty('--gold', p.accent);
  r.setProperty('--gold-soft', p.accentSoft);
}

/* Utils */
const fmtUSD = (n, d=0) => '$' + Number(n).toLocaleString(undefined,{maximumFractionDigits:d});
const fmtUSDshort = (n) => {
  if (n >= 1_000_000) return '$' + (n/1_000_000).toFixed(n>=10_000_000?1:2).replace(/\.0+$/,'') + 'M';
  if (n >= 1_000) return '$' + Math.round(n/1_000) + 'K';
  return '$' + n;
};
const fmtPct = (n, d=1) => `${n.toFixed(d)}%`;

function useInView(options={threshold:0.15}){
  const ref = useRef(null);
  const [inView, setInView] = useState(false);
  useEffect(()=>{
    const el = ref.current; if(!el) return;
    const check = () => {
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight || document.documentElement.clientHeight;
      if (r.top < vh * 0.9 && r.bottom > 0) { setInView(true); return true; }
      return false;
    };
    if (check()) return;
    const io = new IntersectionObserver(([e])=>{
      if(e.isIntersecting){ setInView(true); io.disconnect(); }
    }, options);
    io.observe(el);
    const t = setTimeout(()=>{ if(check()) io.disconnect(); }, 100);
    return ()=>{ io.disconnect(); clearTimeout(t); };
  },[]);
  return [ref, inView];
}

function useCounter(target, active, duration=1400){
  const [val, setVal] = useState(0);
  useEffect(()=>{
    if(!active) return;
    let raf, start;
    const tick = t => {
      if(!start) start = t;
      const p = Math.min(1, (t-start)/duration);
      const eased = 1 - Math.pow(1-p, 3);
      setVal(target * eased);
      if(p<1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return ()=>cancelAnimationFrame(raf);
  },[active,target,duration]);
  return val;
}

/* Atoms */
function Eyebrow({children, color}){
  return <div style={{
    fontFamily:"'JetBrains Mono',ui-monospace,monospace", fontSize:11, letterSpacing:'0.22em',
    textTransform:'uppercase', color: color || 'var(--muted)', marginBottom:18
  }}>{children}</div>;
}

function Btn({children, variant='primary', onClick, full, style, href, target}){
  const base = {
    display:'inline-flex', alignItems:'center', justifyContent:'center', gap:10,
    padding:'14px 22px', border:'1px solid transparent', fontSize:13,
    letterSpacing:'0.04em', fontWeight:500, transition:'all .2s ease',
    width: full?'100%':'auto', cursor:'pointer', textDecoration:'none',
  };
  const variants = {
    primary:{ background:'var(--ink)', color:'var(--ivory)', borderColor:'var(--ink)' },
    ghost:{ background:'transparent', color:'var(--ink)', borderColor:'var(--ink)' },
    gold:{ background:'var(--gold)', color:'var(--ivory)', borderColor:'var(--gold)' },
    light:{ background:'var(--ivory)', color:'var(--ink)', borderColor:'var(--ivory)' },
    lightGhost:{ background:'transparent', color:'var(--ivory)', borderColor:'rgba(244,242,237,0.4)' },
  };
  const enter = e=>{e.currentTarget.style.transform='translateY(-1px)'};
  const leave = e=>{e.currentTarget.style.transform='translateY(0)'};
  if(href){
    return <a href={href} target={target} onClick={onClick}
      style={{...base, ...variants[variant], ...style}}
      onMouseEnter={enter} onMouseLeave={leave}>{children}</a>;
  }
  return <button onClick={onClick} style={{...base, ...variants[variant], ...style}}
    onMouseEnter={enter} onMouseLeave={leave}>
    {children}
  </button>;
}

function Stat({label, value, sub, big}){
  return <div>
    <div style={{fontFamily:"'JetBrains Mono',ui-monospace,monospace", fontSize:10, letterSpacing:'0.22em',
      textTransform:'uppercase', color:'var(--muted)', marginBottom:10}}>{label}</div>
    <div style={{fontFamily:"'Jost',sans-serif", fontSize: big?64:40, lineHeight:0.95,
      fontWeight:300, letterSpacing:'-0.02em'}} className="tnum">{value}</div>
    {sub && <div style={{fontSize:12, color:'var(--muted)', marginTop:8}}>{sub}</div>}
  </div>;
}

function Monogram({size=40}){
  return <div style={{
    width:size, height:size, border:'1px solid var(--ink)',
    display:'flex', alignItems:'center', justifyContent:'center',
    fontFamily:"'Jost',sans-serif", fontSize:size*0.38, fontStyle:'italic',
    letterSpacing:'-0.02em'
  }}>SSF</div>;
}

function SectionLabel({num, title}){
  return <div style={{display:'flex', alignItems:'baseline', gap:20,
    fontFamily:"'JetBrains Mono',ui-monospace,monospace", fontSize:11, letterSpacing:'0.22em',
    textTransform:'uppercase', color:'var(--muted)', marginBottom:40}}>
    <span>§ {num}</span>
    <span style={{flex:1, height:1, background:'var(--rule)'}}/>
    <span>{title}</span>
  </div>;
}

function Nav({onCTA}){
  const [scrolled, setScrolled] = useState(false);
  const [active, setActive] = useState('');
  const links = [
    ['Snapshot','overview'],
    ['Property','property'],
    ['Rent Roll','rentroll'],
    ['Thesis','thesis'],
    ['Financials','financials'],
    ['Returns','returns'],
    ['Sponsor','sponsor'],
  ];
  useEffect(()=>{
    const onScroll = ()=> {
      setScrolled(window.scrollY > 40);
      const y = window.scrollY + 120;
      let current = '';
      for(const [,id] of links){
        const el = document.getElementById(id);
        if(el && el.offsetTop <= y) current = id;
      }
      setActive(current);
    };
    window.addEventListener('scroll', onScroll, {passive:true});
    onScroll();
    return ()=>window.removeEventListener('scroll', onScroll);
  },[]);
  const scrollTo = id => {
    const el = document.getElementById(id);
    if(el){ window.scrollTo({top: el.offsetTop - 60, behavior:'smooth'}); }
  };
  return <nav style={{
    position:'fixed', top:0, left:0, right:0, zIndex:100,
    padding: scrolled ? '14px 40px' : '22px 40px',
    background: scrolled ? 'rgba(244,242,237,0.92)' : 'transparent',
    backdropFilter: scrolled ? 'blur(10px)' : 'none',
    borderBottom: scrolled ? '1px solid var(--rule)' : '1px solid transparent',
    display:'flex', alignItems:'center', gap:40, transition:'all .25s ease',
  }}>
    <div style={{display:'flex', alignItems:'center', gap:14, cursor:'pointer', flexShrink:0, minWidth:0}}
      onClick={()=>window.scrollTo({top:0, behavior:'smooth'})}>
      <Monogram size={36}/>
      <div style={{minWidth:0}}>
        <div style={{fontFamily:"'Jost',sans-serif", fontSize:16, lineHeight:1, whiteSpace:'nowrap'}}>Shoppes at San Felipe</div>
        <div style={{fontFamily:"'JetBrains Mono',ui-monospace,monospace", fontSize:9, letterSpacing:'0.2em',
          textTransform:'uppercase', color:'var(--muted)', marginTop:3, whiteSpace:'nowrap'}}>JAL-JCP · Spring 2026</div>
      </div>
    </div>
    <div style={{flex:1}}/>
    <div style={{display:'flex', gap:24}}>
      {links.map(([l,id]) => <a key={id} onClick={()=>scrollTo(id)}
        className={"nav-link" + (active===id ? ' nav-link--active' : '')} style={{
        fontSize:12, letterSpacing:'0.04em', cursor:'pointer', color:'var(--ink)'
      }}>{l}</a>)}
    </div>
    <Btn variant="primary" onClick={onCTA} style={{padding:'10px 18px', fontSize:12}}>
      Request Package <span style={{opacity:0.6}}>→</span>
    </Btn>
  </nav>;
}

function Placeholder({label, height='100%', dark, style}){
  return <div className={"ph-stripes" + (dark?' ph-dark':'')} data-ph={label}
    style={{width:'100%', height, ...style}}/>;
}

function PhotoTile({src, caption, style}){
  return <div style={{position:'relative', width:'100%', height:'100%', overflow:'hidden', background:'#0b1220', ...style}}>
    <img src={src} alt={caption||''} loading="lazy"
      style={{width:'100%', height:'100%', objectFit:'cover', display:'block'}}/>
    {caption && <div style={{position:'absolute', left:0, right:0, bottom:0, padding:'10px 12px',
      background:'linear-gradient(to top, rgba(11,22,60,0.8), rgba(11,22,60,0))',
      fontFamily:"'JetBrains Mono',ui-monospace,monospace", fontSize:10, letterSpacing:'0.14em',
      textTransform:'uppercase', color:'rgba(244,242,237,0.92)'}}>{caption}</div>}
  </div>;
}

function TweaksPanel({open, tweaks, setTweaks, onClose}){
  if(!open) return null;
  const update = (k,v) => {
    const next = {...tweaks, [k]:v};
    setTweaks(next);
    window.parent?.postMessage({type:'__edit_mode_set_keys', edits:{[k]:v}}, '*');
  };
  return <div style={{
    position:'fixed', bottom:24, right:24, width:320, zIndex:200,
    background:'var(--ink)', color:'var(--ivory)', padding:24,
    boxShadow:'0 30px 60px rgba(0,0,0,0.25)', fontFamily:"'Geist',sans-serif"
  }}>
    <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:20}}>
      <div style={{fontFamily:"'Jost',sans-serif", fontSize:20}}>Tweaks</div>
      <button onClick={onClose} style={{background:'none', border:'1px solid rgba(244,242,237,0.3)',
        color:'var(--ivory)', width:28, height:28, padding:0}}>×</button>
    </div>
    <div style={{marginBottom:20}}>
      <div style={{fontFamily:"'JetBrains Mono',ui-monospace,monospace", fontSize:10, letterSpacing:'0.2em',
        textTransform:'uppercase', opacity:0.6, marginBottom:10}}>Palette</div>
      <div style={{display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:8}}>
        {Object.entries(PALETTES).map(([k,p])=>(
          <button key={k} onClick={()=>update('palette', k)} style={{
            padding:'10px 6px', background: tweaks.palette===k ? 'var(--gold)' : 'transparent',
            color:'var(--ivory)', border:'1px solid rgba(244,242,237,0.25)',
            fontSize:11, letterSpacing:'0.04em', cursor:'pointer',
            display:'flex', flexDirection:'column', gap:8, alignItems:'center'
          }}>
            <div style={{display:'flex', gap:3}}>
              <span style={{width:12,height:12, background:p.ivory, border:'1px solid rgba(244,242,237,0.3)'}}/>
              <span style={{width:12,height:12, background:p.ink}}/>
              <span style={{width:12,height:12, background:p.accent}}/>
            </div>
            {p.name}
          </button>
        ))}
      </div>
    </div>
    <div style={{marginBottom:20}}>
      <div style={{display:'flex', justifyContent:'space-between',
        fontFamily:"'JetBrains Mono',ui-monospace,monospace", fontSize:10, letterSpacing:'0.2em',
        textTransform:'uppercase', opacity:0.6, marginBottom:10}}>
        <span>Type scale</span><span>{tweaks.fontScale.toFixed(2)}×</span>
      </div>
      <input type="range" min="0.9" max="1.15" step="0.01" value={tweaks.fontScale}
        onChange={e=>update('fontScale', parseFloat(e.target.value))}
        style={{width:'100%', accentColor:'var(--gold)'}}/>
    </div>
  </div>;
}

function RequestModal({open, onClose}){
  const [step, setStep] = useState(0);
  const [form, setForm] = useState({name:'', email:'', firm:'', accredited:false});
  useEffect(()=>{ if(open) setStep(0); },[open]);
  if(!open) return null;
  const field = (k, label, type='text') => (
    <label style={{display:'block', marginBottom:18}}>
      <div style={{fontFamily:"'JetBrains Mono',ui-monospace,monospace", fontSize:10, letterSpacing:'0.2em',
        textTransform:'uppercase', color:'var(--muted)', marginBottom:8}}>{label}</div>
      <input type={type} value={form[k]} onChange={e=>setForm({...form, [k]:e.target.value})}
        style={{width:'100%', padding:'12px 0', border:'none', borderBottom:'1px solid var(--rule)',
          background:'transparent', fontSize:16, fontFamily:"'Jost',sans-serif",
          color:'var(--ink)', outline:'none'}}
        onFocus={e=>e.target.style.borderBottomColor='var(--ink)'}
        onBlur={e=>e.target.style.borderBottomColor='var(--rule)'}/>
    </label>
  );
  return <div style={{
    position:'fixed', inset:0, zIndex:300, background:'rgba(11,22,60,0.65)',
    backdropFilter:'blur(4px)', display:'flex', alignItems:'center', justifyContent:'center', padding:24,
  }} onClick={onClose}>
    <div onClick={e=>e.stopPropagation()} style={{
      width:'min(520px, 100%)', background:'var(--ivory)', padding:'48px 48px 40px',
      position:'relative', maxHeight:'90vh', overflow:'auto'
    }}>
      <button onClick={onClose} style={{position:'absolute', top:20, right:20,
        background:'none', border:'1px solid var(--rule)', width:32, height:32, fontSize:18}}>×</button>
      {step===0 && <>
        <Eyebrow>Investor Access · Step 1 of 2</Eyebrow>
        <h2 style={{fontSize:36, marginBottom:14, letterSpacing:'-0.015em'}}>
          Request the full <em>investment package</em>.
        </h2>
        <p style={{color:'var(--muted)', fontSize:14, marginBottom:28, maxWidth:400}}>
          We'll share the financial model, offering memorandum, and rent roll upon NDA execution.
        </p>
        {field('name','Full name')}
        {field('email','Email', 'email')}
        {field('firm','Firm / family office (optional)')}
        <label style={{display:'flex', alignItems:'flex-start', gap:12, cursor:'pointer', marginBottom:28, fontSize:13, color:'var(--muted)'}}>
          <input type="checkbox" checked={form.accredited}
            onChange={e=>setForm({...form, accredited:e.target.checked})}
            style={{marginTop:3, accentColor:'var(--gold)'}}/>
          I represent that I am an <strong style={{color:'var(--ink)'}}>accredited investor</strong> as defined in Rule 501 of Regulation&nbsp;D.
        </label>
        <Btn variant="primary" full onClick={()=>setStep(1)}>Continue →</Btn>
      </>}
      {step===1 && <>
        <Eyebrow>Investor Access · Step 2 of 2</Eyebrow>
        <h2 style={{fontSize:36, marginBottom:14, letterSpacing:'-0.015em'}}>
          Thank you, {form.name ? form.name.split(' ')[0] : 'there'}.
        </h2>
        <p style={{color:'var(--muted)', fontSize:14, marginBottom:28, maxWidth:400}}>
          The package has been sent to <strong style={{color:'var(--ink)'}}>{form.email || 'your email'}</strong>.
          Justin or James will reach out within one business day.
        </p>
        <div style={{background:'var(--ivory-2)', padding:24, marginBottom:24,
          borderLeft:'2px solid var(--gold)'}}>
          <div style={{fontFamily:"'JetBrains Mono',ui-monospace,monospace", fontSize:10, letterSpacing:'0.2em',
            textTransform:'uppercase', color:'var(--muted)', marginBottom:8}}>Next step</div>
          <div style={{fontFamily:"'Jost',sans-serif", fontSize:20, lineHeight:1.3}}>
            A principal will contact you directly to walk through the offering.
          </div>
        </div>
        <Btn variant="primary" full onClick={onClose}>Close</Btn>
      </>}
    </div>
  </div>;
}

Object.assign(window, {
  DEAL, PALETTES, applyPalette, fmtUSD, fmtUSDshort, fmtPct,
  useInView, useCounter, Eyebrow, Btn, Stat, Monogram, SectionLabel,
  Nav, Placeholder, PhotoTile, TweaksPanel, RequestModal,
});
