// FactorViews.jsx — 요인 분석 공용 컴포넌트: 요인 시황 연결 · 단일 요인 스트레스.

// deterministic spark series (LCG)
function fvSpark(seed, end, vol) {
  let r = seed >>> 0; const rnd = () => { r = Math.imul(r, 1103515245) + 12345 >>> 0; return r / 4294967296; };
  const n = 22, arr = new Array(n); let v = end;
  for (let i = n - 1; i >= 0; i--) { arr[i] = v; v = v * (1 + (rnd() - 0.5) * vol); }
  return arr;
}
const fvEok = (v) => (v > 0 ? '+' : v < 0 ? '−' : '') + Math.abs(Math.round(v)).toLocaleString() + '억';

// ── 요인 시황 연결 (지표 + 내 포지션 민감도) ──
function FactorMarketLink({ pf, fids }) {
  const s = factorSens(pf);
  const items = fids ? FACTOR_MARKET.filter((m) => fids.includes(m.fid)) : FACTOR_MARKET;
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
      {items.map((m) => {
        const f = FMAP[m.fid]; const c = dirColor(m.delta);
        const impact = m.shock(s, pf.value);
        return (
          <div key={m.sub} style={{ border: '1px solid ' + T.line, borderRadius: 10, padding: '12px 14px', background: T.c50, display: 'flex', gap: 14, alignItems: 'center', minWidth: 0 }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
                <span style={{ width: 7, height: 7, borderRadius: 3, background: f.color, flex: 'none', alignSelf: 'center' }} />
                <span style={{ fontFamily: T.font, fontWeight: 700, fontSize: 12.5, color: T.c700, whiteSpace: 'nowrap' }}>{m.label}</span>
                <span style={{ fontFamily: T.mono, fontSize: 9.5, color: T.c400 }}>{m.sub}</span>
              </div>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 5, marginTop: 5 }}>
                <span className="num" style={{ fontFamily: T.font, fontWeight: 800, fontSize: 21, color: T.c900, letterSpacing: '-.02em' }}>{m.value}</span>
                <span style={{ fontFamily: T.font, fontWeight: 600, fontSize: 11, color: T.c400 }}>{m.unit}</span>
                <span style={{ marginLeft: 4 }}><Delta v={m.delta} suffix={m.dunit} digits={m.ddig} size={11.5} /></span>
              </div>
              <div style={{ marginTop: 7, display: 'inline-flex', alignItems: 'center', gap: 6, background: T.white, border: '1px solid ' + T.c200, borderRadius: 7, padding: '4px 9px' }}>
                <Icon name="briefcase" size={12} color={T.c400} />
                <span style={{ fontFamily: T.font, fontWeight: 600, fontSize: 11, color: T.c500 }}>{m.shockText} →</span>
                <span className="num" style={{ fontFamily: T.font, fontWeight: 700, fontSize: 11.5, color: impact < 0 ? T.down : T.up }}>{fvEok(impact)}</span>
              </div>
            </div>
            <div style={{ width: 132, flex: 'none' }}><Spark data={fvSpark(m.seed, m.num, m.mvol)} color={c} full w={132} h={54} /></div>
          </div>);
      })}
    </div>);
}

// ── 단일 요인 스트레스 ── keys: 표시할 요인 슬라이더 목록 (자산군별로 다름)
function FactorStress({ pf, keys }) {
  const [v, setV] = React.useState({ rate: 0, credit: 0, eq: 0, fx: 0 });
  const set = (k) => (e) => setV((o) => ({ ...o, [k]: +e.target.value }));
  const base = summarize(pf);
  const sim = simulate(pf, { eq: v.eq, rateBp: v.rate, creditBp: v.credit, fxPct: v.fx, volX: 1 });
  const active = Object.values(v).some((x) => x !== 0);
  const ALL_SLIDERS = [
    { k: 'rate',   name: '금리',       min: -200, max: 200, step: 5,  unit: 'bp', fmt: (x) => (x > 0 ? '+' : '') + x + 'bp' },
    { k: 'credit', name: '신용스프레드', min: -100, max: 300, step: 5,  unit: 'bp', fmt: (x) => (x > 0 ? '+' : '') + x + 'bp' },
    { k: 'eq',     name: '주식',       min: -30,  max: 15,  step: 1,  unit: '%',  fmt: (x) => (x > 0 ? '+' : '') + x + '%' },
    { k: 'fx',     name: '원/달러',    min: -10,  max: 20,  step: 0.5, unit: '%', fmt: (x) => (x > 0 ? '+' : '') + x + '% (원' + (x >= 0 ? '약세' : '강세') + ')' },
  ];
  const sliders = keys ? ALL_SLIDERS.filter((s) => keys.includes(s.k)) : ALL_SLIDERS;
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0,1.25fr) minmax(0,1fr)', gap: 18, alignItems: 'start' }}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 13 }}>
        {sliders.map((sl) => { const f = FMAP[sl.k]; const scol = f.color; const pct = (v[sl.k] - sl.min) / (sl.max - sl.min) * 100;
          // 단일 요인 손익 (해당 요인만 적용)
          const solo = simulate(pf, { eq: sl.k === 'eq' ? v.eq : 0, rateBp: sl.k === 'rate' ? v.rate : 0, creditBp: sl.k === 'credit' ? v.credit : 0, fxPct: sl.k === 'fx' ? v.fx : 0, volX: 1 });
          return (
            <div key={sl.k} style={{ border: '1px solid ' + T.line, borderRadius: 10, padding: '11px 14px', background: T.white }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
                <span style={{ width: 8, height: 8, borderRadius: 3, background: scol, flex: 'none' }} />
                <span style={{ fontFamily: T.font, fontWeight: 700, fontSize: 12.5, color: T.c800 }}>{sl.name}</span>
                <span className="num" style={{ fontFamily: T.font, fontWeight: 700, fontSize: 12.5, color: v[sl.k] === 0 ? T.c400 : T.c900 }}>{sl.fmt(v[sl.k])}</span>
                <span className="num" style={{ marginLeft: 'auto', fontFamily: T.font, fontWeight: 700, fontSize: 12, color: v[sl.k] === 0 ? T.c300 : solo.portPnl < 0 ? T.down : T.up }}>{v[sl.k] === 0 ? '—' : fvEok(solo.lossAmt)}</span>
              </div>
              <input type="range" min={sl.min} max={sl.max} step={sl.step} value={v[sl.k]} onChange={set(sl.k)}
                style={{ width: '100%', display: 'block', '--rng': scol, background: `linear-gradient(90deg, ${scol} ${pct}%, #E6EBF1 ${pct}%)` }} />
              <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 3 }}>
                <span className="num" style={{ fontFamily: T.font, fontWeight: 600, fontSize: 10, color: T.c400 }}>{sl.fmt(sl.min)}</span>
                <span className="num" style={{ fontFamily: T.font, fontWeight: 600, fontSize: 10, color: T.c400 }}>{sl.fmt(sl.max)}</span>
              </div>
            </div>);
        })}
        <button onClick={() => setV({ rate: 0, credit: 0, eq: 0, fx: 0 })} disabled={!active}
          style={{ alignSelf: 'flex-start', border: '1px solid ' + T.c250, background: T.white, borderRadius: 8, padding: '6px 13px', cursor: active ? 'pointer' : 'default', opacity: active ? 1 : .5, fontFamily: T.font, fontWeight: 600, fontSize: 12, color: T.c600, display: 'inline-flex', alignItems: 'center', gap: 6 }}>
          <Icon name="refresh" size={13} /> 초기화</button>
      </div>
      <div style={{ border: '1px solid ' + T.line, borderRadius: 12, padding: '4px 18px 16px', background: T.c50 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '14px 0 4px' }}>
          <span style={{ width: 7, height: 7, borderRadius: 9, background: T.ok, boxShadow: '0 0 0 3px ' + T.okS }} />
          <span style={{ fontFamily: T.font, fontWeight: 700, fontSize: 13, color: T.c800 }}>스트레스 결과</span>
        </div>
        <CompareRow label="예상 손익" before={0} after={sim.lossAmt} unit="억" />
        <CompareRow label="평가액" before={pf.value} after={sim.newValue} unit="억" neutral />
        <CompareRow label="시나리오 후 위험액" before={base.risk} after={sim.newRisk} unit="억" betterLow />
        <CompareRow label="한도 소진율" before={base.util} after={sim.util} unit="%" digits={1} betterLow />
        <div style={{ marginTop: 12 }}>
          <LimitMeter pct={sim.util} />
          {sim.util >= 100 && <div style={{ marginTop: 9, display: 'flex', alignItems: 'center', gap: 7 }}><Icon name="alert" size={14} color={T.alert} /><span style={{ fontFamily: T.font, fontWeight: 600, fontSize: 11.5, color: T.alert }}>이 충격에서 리스크 한도를 초과해요.</span></div>}
        </div>
        {!active && <div style={{ marginTop: 11, display: 'flex', gap: 7, alignItems: 'center' }}><Icon name="info" size={13} color={T.c400} /><span style={{ fontFamily: T.font, fontWeight: 500, fontSize: 11.5, color: T.c400, textAlign: 'left' }}>슬라이더를 움직여 단일 요인 충격의 영향을 확인하세요.</span></div>}
      </div>
    </div>);
}

Object.assign(window, { FactorMarketLink, FactorStress, fvEok, fvSpark });
