/* InverseTermSheet.jsx: Sprint 9+10, inverse cap table with audio enforcement.
   Same machinery as InverseDesign, applied to the venture itself.
   Set desired return on capital + cheque size; engine returns viable boundary
   condition or constitutional breach. Audio fires on VIABLE->BREACH transition only.
*/

const PRE_MONEY_BASELINE = 5000000;
const OPTION_POOL = 0.10;

function computeTermSheet(targetRoce, capital) {
  const raw_equity = capital / (PRE_MONEY_BASELINE + capital);
  const demand_multiplier = 1 + (targetRoce / 100) * 0.6;
  let sponsor_pct = raw_equity * demand_multiplier;
  sponsor_pct = Math.max(0.02, Math.min(0.95, sponsor_pct));
  const founder_pct = Math.max(0.05, 1 - sponsor_pct - OPTION_POOL);
  const conv_pct = Math.max(0, 1 - sponsor_pct - founder_pct);
  return { sponsor_pct, founder_pct, conv_pct };
}

function InverseTermSheet() {
  const [roce, setRoce] = React.useState(25);
  const [capital, setCapital] = React.useState(500000);
  const [muted, setMuted] = React.useState(false);
  const prevStateRef = React.useRef(null);
  const voicesRef = React.useRef([]);

  // Load voices when available
  React.useEffect(() => {
    const loadVoices = () => {
      voicesRef.current = window.speechSynthesis ? window.speechSynthesis.getVoices() : [];
    };
    loadVoices();
    if (window.speechSynthesis && window.speechSynthesis.onvoiceschanged !== undefined) {
      window.speechSynthesis.onvoiceschanged = loadVoices;
    }
  }, []);

  // Compute result + breaches
  const result = React.useMemo(() => {
    const { sponsor_pct, founder_pct, conv_pct } = computeTermSheet(roce, capital);
    const breaches = [];
    if (founder_pct < 0.51) {
      breaches.push('Founder control floor breached (founders retained: ' + (founder_pct * 100).toFixed(1) + '%, floor: 51%).');
    }
    if (sponsor_pct > 0.40) {
      breaches.push('Sponsor extraction ceiling breached (sponsor equity: ' + (sponsor_pct * 100).toFixed(1) + '%, ceiling: 40%).');
    }
    if (capital < 100000) {
      breaches.push('Minimum capital floor breached (injection: $' + capital.toLocaleString() + ', floor: $100,000).');
    }
    const state = breaches.length === 0 ? 'VIABLE' : 'BREACH';
    return { sponsor_pct, founder_pct, conv_pct, breaches, state };
  }, [roce, capital]);

  // Speech enforcement
  const speakBreach = React.useCallback(() => {
    if (muted) return;
    try {
      if (!window.speechSynthesis) return;
      window.speechSynthesis.cancel();
      const u = new SpeechSynthesisUtterance(
        'That boundary condition violates the constitutional floor. Recalibrate.'
      );
      u.rate = 1.05;
      u.pitch = 0.85;
      u.volume = 0.85;
      u.lang = 'en-GB';
      const v = voicesRef.current;
      if (v && v.length) {
        const preferred = v.find(x => x.lang.startsWith('en-NZ')) ||
                          v.find(x => x.lang.startsWith('en-GB')) ||
                          v[0];
        if (preferred) u.voice = preferred;
      }
      window.speechSynthesis.speak(u);
    } catch (e) { /* graceful degradation */ }
  }, [muted]);

  // Detect VIABLE -> BREACH transition
  React.useEffect(() => {
    if (prevStateRef.current === 'VIABLE' && result.state === 'BREACH') {
      speakBreach();
    }
    if (prevStateRef.current !== null) {
      // Only update after initial mount has set a value
    }
    prevStateRef.current = result.state;
  }, [result.state, speakBreach]);

  const handleCompute = () => {
    // Button click: if currently in breach and transition just happened, audio already fired.
    // Force audio if state is BREACH and user clicks (re-trigger for affordance).
    if (result.state === 'BREACH') {
      speakBreach();
    }
  };

  const Slider = ({ label, value, onChange, min, max, step, unit, hint, format }) => (
    <div style={{ marginBottom: 18 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 6 }}>
        <div style={{ fontSize: 12.5, fontWeight: 500 }}>{label}</div>
        <div className="mono" style={{ fontSize: 13, fontWeight: 600, color: 'var(--red)' }}>
          {format ? format(value) : value}{unit || ''}
        </div>
      </div>
      <input type="range" min={min} max={max} step={step} value={value}
             onChange={e => onChange(parseFloat(e.target.value))}
             className="slider red" />
      <div style={{ fontSize: 11, color: 'var(--muted-2)', marginTop: 4 }}>{hint}</div>
    </div>
  );

  // SPRINT 7 — first-violated constraint name for INADMISSIBLE verdict line
  const breachNameOf = (br) => {
    if (!br) return '';
    if (/founder/i.test(br)) return 'Founder Control Floor';
    if (/sponsor/i.test(br)) return 'Sponsor Extraction Ceiling';
    if (/minimum capital|injection/i.test(br)) return 'Minimum Capital Floor';
    return 'Constitutional Floor';
  };
  const verdictLine = result.state === 'VIABLE'
    ? 'ADMISSIBLE: boundary condition exists.'
    : 'INADMISSIBLE: breach of ' + breachNameOf(result.breaches[0]) + '.';

  return (
    <section id="termsheet" style={{ background: 'var(--tint)' }}>
      <div className="container">
        <SectionHeader
          num="08 / 08"
          tag="Mechanism applied to the venture itself"
          title="The Inverse Cap Table."
          lede="Same machinery, applied to the venture itself. Set the desired return on capital and the cheque size. The engine returns either a viable boundary condition, or a constitutional breach."
        />

        {/* SPRINT 7 — enforcement warning eyebrow, immediately under the H2 */}
        <div className="enforce-warn">
          THIS MODULE ENFORCES. AUDIO ENFORCEMENT IS ON BY DEFAULT.
        </div>

        <span
          onClick={() => setMuted(m => !m)}
          style={{
            fontSize: 10, fontFamily: "'JetBrains Mono', monospace",
            color: 'var(--muted-2)', cursor: 'pointer',
            marginTop: 0, marginLeft: 12, display: 'inline-block',
          }}
        >
          {muted ? '[audio enforcement: OFF · click to enable]' : '[audio enforcement: ON · click to mute]'}
        </span>

        <InstrumentBand name="INVERSE CAP TABLE">
        <div style={{ display: 'grid', gridTemplateColumns: '320px 1fr', gap: 32, marginTop: 24, alignItems: 'start' }}>
          {/* LEFT: inputs */}
          <div className="card" style={{ padding: 24 }}>
            <div className="sub-h" style={{ marginTop: 0, paddingTop: 0, borderTop: 'none', marginBottom: 16 }}>
              Investor input
            </div>
            <Slider
              label="IRR floor (annualised, post-tax)"
              value={roce}
              onChange={setRoce}
              min={5} max={50} step={1}
              unit="%"
              hint="ROCE floor demanded by sponsor: ∈ [5, 50]; annualised, post-tax."
            />
            <Slider
              label="Primary injection (NZD)"
              value={capital}
              onChange={setCapital}
              min={100000} max={5000000} step={50000}
              format={v => '$' + v.toLocaleString()}
              hint="Cheque on offer: ∈ [$100,000, $5,000,000]; first-round commitment."
            />
            <button
              className="btn"
              style={{ width: '100%', marginTop: 12, letterSpacing: '0.10em' }}
              onClick={handleCompute}
            >
              ENFORCE CONSTITUTION
            </button>
          </div>

          {/* RIGHT: verdict */}
          <div className="card" style={{
            padding: 24,
            border: result.state === 'BREACH' ? '2px solid var(--red)' : '1px solid var(--rule)',
          }}>
            <div className="sub-h" style={{ marginTop: 0, paddingTop: 0, borderTop: 'none', marginBottom: 16 }}>
              Constitutional verdict
            </div>

            <div className={'verdict-line ' + (result.state === 'VIABLE' ? 'admissible' : 'inadmissible')}
                 style={{ marginBottom: 18 }}>
              {verdictLine}
            </div>

            {result.state === 'VIABLE' ? (
              <table style={{ width: '100%', borderCollapse: 'collapse' }}>
                <tbody className="mono" style={{ fontSize: 13 }}>
                  <tr>
                    <td style={{ padding: '8px 0', color: 'var(--muted-2)', borderBottom: '1px solid var(--rule)', letterSpacing: '0.04em', textTransform: 'uppercase', fontSize: 10.5 }}>Sponsor equity</td>
                    <td style={{ padding: '8px 0', textAlign: 'right', fontWeight: 600, borderBottom: '1px solid var(--rule)', fontFeatureSettings: '"tnum" 1' }}>
                      {(result.sponsor_pct * 100).toFixed(1)}%
                    </td>
                  </tr>
                  <tr>
                    <td style={{ padding: '8px 0', color: 'var(--muted-2)', borderBottom: '1px solid var(--rule)', letterSpacing: '0.04em', textTransform: 'uppercase', fontSize: 10.5 }}>Founders retained</td>
                    <td style={{ padding: '8px 0', textAlign: 'right', fontWeight: 600, borderBottom: '1px solid var(--rule)', fontFeatureSettings: '"tnum" 1' }}>
                      {(result.founder_pct * 100).toFixed(1)}%
                    </td>
                  </tr>
                  <tr>
                    <td style={{ padding: '8px 0', color: 'var(--muted-2)', letterSpacing: '0.04em', textTransform: 'uppercase', fontSize: 10.5 }}>Convertible note</td>
                    <td style={{ padding: '8px 0', textAlign: 'right', fontWeight: 600, fontFeatureSettings: '"tnum" 1' }}>
                      {(result.conv_pct * 100).toFixed(1)}%
                    </td>
                  </tr>
                </tbody>
              </table>
            ) : (
              <ul style={{ paddingLeft: 20, margin: 0 }}>
                {result.breaches.map((b, i) => (
                  <li key={i} style={{ fontSize: 13, lineHeight: 1.7, color: 'var(--ink)' }}>{b}</li>
                ))}
              </ul>
            )}
          </div>
        </div>

        {/* Constitutional floors reference */}
        <div className="sub-h" style={{ marginTop: 32, marginBottom: 8 }}>
          Constitutional floors
        </div>
        <div style={{ fontSize: 12, color: 'var(--muted-2)', lineHeight: 1.8 }}>
          <div>Founder retained &#8805; 51%: control of the venture remains with the founders.</div>
          <div>Sponsor equity &#8804; 40%: protects against extractive first-cheque dilution.</div>
          <div>Capital injection &#8805; $100,000: minimum cheque to participate.</div>
        </div>
        </InstrumentBand>
      </div>
    </section>
  );
}

window.InverseTermSheet = InverseTermSheet;
