/* Review-request modal — opens from the Disclosure panel.
 *
 * Lets a reader contest a specific passage classification with structured,
 * evidence-anchored input. Posts to /api/review-request. Validation runs
 * client-side for UX and again on the server for trust. The hidden
 * `website` field is a honeypot — bots that fill every input trip it and
 * the server silently drops the submission. We never echo the user's
 * evidence or explanation back into the page (XSS guard).
 *
 * Field caps mirror the server caps so the textarea counters stay
 * truthful. If the server rejects with a generic 400 we surface a
 * neutral message — specific reasons stay server-side so probing for
 * reflection oracles doesn't pay off.
 */
const REVIEW_LIMITS = {
  evidence_quote: { min: 10, max: 2000 },
  evidence_page:  { min: 1,  max: 64   },
  explanation:    { min: 20, max: 3000 },
  name:           { min: 0,  max: 200  },
  email:          { min: 0,  max: 254  },
};

const ISSUE_TYPE_OPTIONS = [
  { value: '',                           label: 'Select an issue type…',  disabled: true },
  { value: 'misclassification',          label: 'Misclassification' },
  { value: 'missing_context',            label: 'Missing context' },
  { value: 'factual_error',              label: 'Factual error' },
  { value: 'methodology_disagreement',   label: 'Methodology disagreement' },
  { value: 'other',                      label: 'Other' },
];

const SUGGESTED_LABEL_OPTIONS = [
  { value: '',      label: 'No suggestion' },
  { value: 'true',  label: 'True shared value' },
  { value: 'ambig', label: 'Ambiguous' },
  { value: 'none',  label: 'No measurable value' },
];

const AFFILIATION_OPTIONS = [
  { value: '',            label: 'Prefer not to say' },
  { value: 'independent', label: 'Independent user' },
  { value: 'academic',    label: 'Academic / researcher' },
  { value: 'investor',    label: 'Investor / analyst' },
  { value: 'company',     label: 'Company representative' },
  { value: 'other',       label: 'Other' },
];

const REVIEW_EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;

const ReviewRequestModal = ({ passage, onClose }) => {
  const open = !!passage;

  const [form, setForm] = React.useState({
    issue_type:      '',
    suggested_label: '',
    evidence_quote:  '',
    evidence_page:   '',
    explanation:     '',
    name:            '',
    email:           '',
    affiliation:     '',
    consent:         false,
    website:         '',
  });
  const [touched, setTouched] = React.useState({});
  const [status, setStatus]   = React.useState('idle'); // idle | sending | sent | error
  const [errorMsg, setErrorMsg] = React.useState('');

  // Reset whenever the modal closes/opens for a different passage.
  React.useEffect(() => {
    if (!open) return;
    setForm({
      issue_type: '', suggested_label: '',
      evidence_quote: '', evidence_page: '', explanation: '',
      name: '', email: '', affiliation: '',
      consent: false, website: '',
    });
    setTouched({});
    setStatus('idle');
    setErrorMsg('');
  }, [open, passage && passage.id]);

  // Esc closes; lock body scroll while open.
  React.useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => {
      window.removeEventListener('keydown', onKey);
      document.body.style.overflow = prev;
    };
  }, [open, onClose]);

  const set = (k) => (e) => {
    const v = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
    setForm(f => ({ ...f, [k]: v }));
  };
  const blur = (k) => () => setTouched(t => ({ ...t, [k]: true }));

  const errors = React.useMemo(() => {
    const e = {};
    if (!form.issue_type) e.issue_type = 'Select an issue type';

    const q = form.evidence_quote.trim();
    if (q.length < REVIEW_LIMITS.evidence_quote.min) e.evidence_quote = `Paste at least ${REVIEW_LIMITS.evidence_quote.min} characters of evidence`;
    else if (q.length > REVIEW_LIMITS.evidence_quote.max) e.evidence_quote = 'Evidence quote is too long';

    const p = form.evidence_page.trim();
    if (p.length < REVIEW_LIMITS.evidence_page.min) e.evidence_page = 'Page or location is required';
    else if (p.length > REVIEW_LIMITS.evidence_page.max) e.evidence_page = 'Page reference is too long';

    const x = form.explanation.trim();
    if (x.length < REVIEW_LIMITS.explanation.min) e.explanation = `Explain in at least ${REVIEW_LIMITS.explanation.min} characters`;
    else if (x.length > REVIEW_LIMITS.explanation.max) e.explanation = 'Explanation is too long';

    if (form.name.length > REVIEW_LIMITS.name.max) e.name = 'Name is too long';

    const em = form.email.trim();
    if (em && (em.length < 5 || em.length > REVIEW_LIMITS.email.max || !REVIEW_EMAIL_RE.test(em))) e.email = 'Enter a valid email or leave blank';

    if (!form.consent) e.consent = 'Please confirm to submit';
    return e;
  }, [form]);

  const showErr = (k) => touched[k] && errors[k];
  const isInvalid = Object.keys(errors).length > 0;

  if (!open) return null;
  const co = passage.co ? (window.byId ? window.byId(passage.co) : null) : null;
  const companyName = co?.name || passage.co || '';
  const raw = passage._raw || {};
  const initiative = (window.INITIATIVE_LABEL && window.INITIATIVE_LABEL[raw.initiative_type]) || raw.initiative_type || '—';
  const labelText = (window.CSV_LABELS && window.CSV_LABELS[passage.c]) || passage.c || '—';

  const submit = async (e) => {
    e.preventDefault();
    setTouched({
      issue_type: true, evidence_quote: true, evidence_page: true,
      explanation: true, name: true, email: true, consent: true,
    });
    if (isInvalid) return;
    if (form.website) { setStatus('sent'); return; } // honeypot

    setStatus('sending');
    setErrorMsg('');
    try {
      const r = await fetch('/api/review-request', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          passage_id:              String(passage.id),
          company:                 companyName,
          report_year:             passage.year ? String(passage.year) : '',
          current_label:           passage.c || '',
          current_initiative_type: raw.initiative_type || '',
          issue_type:              form.issue_type,
          suggested_label:         form.suggested_label,
          evidence_quote:          form.evidence_quote.trim(),
          evidence_page:           form.evidence_page.trim(),
          explanation:             form.explanation.trim(),
          name:                    form.name.trim(),
          email:                   form.email.trim(),
          affiliation:             form.affiliation,
          consent:                 form.consent === true,
          source_url:              (typeof window !== 'undefined' && window.location)
                                     ? window.location.href.slice(0, 500)
                                     : '',
          website:                 form.website,
        }),
      });
      if (r.ok) {
        setStatus('sent');
      } else if (r.status === 429) {
        setStatus('error');
        setErrorMsg('Too many requests — please wait a moment and try again.');
      } else if (r.status === 400) {
        setStatus('error');
        setErrorMsg('Something went wrong while submitting your request. Please try again.');
      } else {
        setStatus('error');
        setErrorMsg('Something went wrong while submitting your request. Please try again.');
      }
    } catch (_) {
      setStatus('error');
      setErrorMsg('Network error — check your connection and try again.');
    }
  };

  if (status === 'sent') {
    return (
      <RRShell onClose={onClose}>
        <div style={{padding:'28px 28px 24px',display:'flex',justifyContent:'space-between',alignItems:'flex-start',gap:12,borderBottom:'1px solid var(--line)'}}>
          <div>
            <div className="eyebrow" style={{fontSize:11}}>Review request</div>
            <h3 id="rr-title" style={{fontSize:22,lineHeight:'28px',fontWeight:600,letterSpacing:'-0.015em',color:'var(--ink)',marginTop:8}}>
              Thank you — your request was recorded.
            </h3>
          </div>
          <button onClick={onClose} aria-label="Close"
            style={{background:'transparent',border:'1px solid var(--line)',borderRadius:999,width:32,height:32,display:'flex',alignItems:'center',justifyContent:'center',cursor:'pointer',color:'var(--ink-2)',flexShrink:0}}>
            <Icon name="close" size={14}/>
          </button>
        </div>
        <div style={{padding:'24px 28px 28px'}}>
          <p style={{fontSize:14,lineHeight:'22px',color:'var(--ink-2)'}}>
            Review request submitted. This does not automatically change the classification, but it has been recorded for methodological review.
          </p>
          <div style={{marginTop:24,display:'flex',gap:10}}>
            <button onClick={onClose} className="btn btn-primary" style={{padding:'10px 16px',fontSize:13}}>Close</button>
          </div>
        </div>
      </RRShell>
    );
  }

  return (
    <RRShell onClose={onClose}>
      <div className="review-modal-head" style={{position:'sticky',top:0,background:'rgba(250,250,247,0.94)',backdropFilter:'blur(14px)',borderBottom:'1px solid var(--line)',padding:'18px 24px',display:'flex',justifyContent:'space-between',alignItems:'flex-start',gap:12,zIndex:2}}>
        <div style={{minWidth:0}}>
          <div className="eyebrow" style={{fontSize:11}}>Contest classification</div>
          <h3 id="rr-title" style={{fontSize:20,lineHeight:'26px',fontWeight:600,letterSpacing:'-0.015em',color:'var(--ink)',marginTop:6}}>
            Request classification review
          </h3>
        </div>
        <button onClick={onClose} aria-label="Close"
          style={{background:'transparent',border:'1px solid var(--line)',borderRadius:999,width:32,height:32,display:'flex',alignItems:'center',justifyContent:'center',cursor:'pointer',color:'var(--ink-2)',flexShrink:0}}>
          <Icon name="close" size={14}/>
        </button>
      </div>

      <div style={{padding:'20px 24px 28px'}}>
        <p style={{fontSize:13,lineHeight:'20px',color:'var(--ink-2)'}}>
          Kestrel classifications are evidence-based and conservative. Use this form to request a review of a specific passage. Please provide exact report evidence; unsupported challenges may not be reviewed.
        </p>

        {/* Read-only context card — what the user is contesting. */}
        <div style={{
          marginTop:18,padding:'14px 16px',
          border:'1px solid var(--line)',borderRadius:10,background:'var(--canvas-2)',
          display:'grid',gridTemplateColumns:'repeat(2,minmax(0,1fr))',gap:'10px 14px',
        }}>
          <ReviewMeta k="Passage">{passage.title || passage.id}</ReviewMeta>
          <ReviewMeta k="Company">{companyName}{passage.year ? ` · ${passage.year}` : ''}</ReviewMeta>
          <ReviewMeta k="Current label">{labelText}</ReviewMeta>
          <ReviewMeta k={<Term name="initiative-type">Initiative type</Term>}>{initiative}</ReviewMeta>
        </div>

        <form onSubmit={submit} noValidate className="review-form" style={{
          marginTop:20,display:'grid',gridTemplateColumns:'1fr 1fr',gap:16,
        }}>
          <RRField label="Issue type" required full error={showErr('issue_type') && errors.issue_type}>
            <select
              value={form.issue_type}
              onChange={set('issue_type')}
              onBlur={blur('issue_type')}
              required
              aria-invalid={!!showErr('issue_type')}
              className="contact-input">
              {ISSUE_TYPE_OPTIONS.map(o =>
                <option key={o.value} value={o.value} disabled={o.disabled}>{o.label}</option>
              )}
            </select>
          </RRField>

          <RRField label="Suggested label" full
                 help="Optional — only if you think a different Kestrel label fits.">
            <select
              value={form.suggested_label}
              onChange={set('suggested_label')}
              className="contact-input">
              {SUGGESTED_LABEL_OPTIONS.map(o =>
                <option key={o.value} value={o.value}>{o.label}</option>
              )}
            </select>
          </RRField>

          <RRField label="Evidence quote" required full
                 help={`${form.evidence_quote.length} / ${REVIEW_LIMITS.evidence_quote.max}`}
                 error={showErr('evidence_quote') && errors.evidence_quote}>
            <textarea
              value={form.evidence_quote}
              onChange={set('evidence_quote')}
              onBlur={blur('evidence_quote')}
              maxLength={REVIEW_LIMITS.evidence_quote.max}
              rows={4}
              required
              aria-invalid={!!showErr('evidence_quote')}
              className="contact-input contact-textarea"
              placeholder="Paste the exact quote or report wording that supports your challenge."
            />
          </RRField>

          <RRField label="Page / location" required
                 error={showErr('evidence_page') && errors.evidence_page}>
            <input
              type="text"
              value={form.evidence_page}
              onChange={set('evidence_page')}
              onBlur={blur('evidence_page')}
              maxLength={REVIEW_LIMITS.evidence_page.max}
              required
              aria-invalid={!!showErr('evidence_page')}
              className="contact-input"
              placeholder="Page number or report location"
            />
          </RRField>

          <RRField label="Affiliation">
            <select
              value={form.affiliation}
              onChange={set('affiliation')}
              className="contact-input">
              {AFFILIATION_OPTIONS.map(o =>
                <option key={o.value} value={o.value}>{o.label}</option>
              )}
            </select>
          </RRField>

          <RRField label="Explanation" required full
                 help={`${form.explanation.length} / ${REVIEW_LIMITS.explanation.max}`}
                 error={showErr('explanation') && errors.explanation}>
            <textarea
              value={form.explanation}
              onChange={set('explanation')}
              onBlur={blur('explanation')}
              maxLength={REVIEW_LIMITS.explanation.max}
              rows={5}
              required
              aria-invalid={!!showErr('explanation')}
              className="contact-input contact-textarea"
              placeholder="Explain why this changes the classification under Kestrel's methodology."
            />
          </RRField>

          <RRField label="Name (optional)" error={showErr('name') && errors.name}>
            <input
              type="text"
              value={form.name}
              onChange={set('name')}
              onBlur={blur('name')}
              maxLength={REVIEW_LIMITS.name.max}
              autoComplete="name"
              className="contact-input"
            />
          </RRField>

          <RRField label="Email (optional)" error={showErr('email') && errors.email}>
            <input
              type="email"
              value={form.email}
              onChange={set('email')}
              onBlur={blur('email')}
              maxLength={REVIEW_LIMITS.email.max}
              autoComplete="email"
              inputMode="email"
              aria-invalid={!!showErr('email')}
              className="contact-input"
            />
          </RRField>

          {/* Honeypot — visually hidden, off the tab order. */}
          <div aria-hidden="true" className="contact-honeypot">
            <label>Website (leave blank)
              <input type="text" tabIndex={-1} autoComplete="off"
                value={form.website} onChange={set('website')}/>
            </label>
          </div>

          <div style={{gridColumn:'1 / -1',marginTop:4}}>
            <label style={{display:'flex',gap:10,alignItems:'flex-start',cursor:'pointer'}}>
              <input
                type="checkbox"
                checked={form.consent}
                onChange={set('consent')}
                onBlur={blur('consent')}
                required
                aria-invalid={!!showErr('consent')}
                style={{marginTop:3,flexShrink:0,accentColor:'var(--moss-deep, #3E5C2E)'}}
              />
              <span style={{fontSize:12,lineHeight:'18px',color:'var(--ink-2)'}}>
                I understand that submitting this does not automatically change the classification and that Kestrel may review, reject, or retain the original judgement.
              </span>
            </label>
            {showErr('consent') && (
              <div className="contact-error" role="alert" style={{marginTop:6,marginLeft:26}}>{errors.consent}</div>
            )}
          </div>

          {status === 'error' && (
            <div role="alert" style={{
              gridColumn:'1 / -1',
              padding:'12px 16px',borderRadius:10,
              border:'1px solid #C97070',background:'#FBEDED',
              color:'#7A2E2E',fontSize:13,lineHeight:'20px',
            }}>
              {errorMsg || 'Something went wrong while submitting your request. Please try again.'}
            </div>
          )}

          <div style={{gridColumn:'1 / -1',display:'flex',gap:12,justifyContent:'flex-end',marginTop:6,flexWrap:'wrap'}}>
            <button type="button" onClick={onClose} className="btn btn-text" style={{fontSize:13}}>
              Cancel
            </button>
            <button
              type="submit"
              className="btn btn-primary"
              style={{padding:'10px 18px',fontSize:13}}
              disabled={status === 'sending'}>
              {status === 'sending' ? 'Submitting…' : 'Submit review request'}
            </button>
          </div>
        </form>
      </div>
    </RRShell>
  );
};

/* Stable shell — hoisted out of ReviewRequestModal so React doesn't see a new
 * component identity on every parent render (which would unmount/remount the
 * whole subtree and lose form state mid-typing). */
const RRShell = ({ children, onClose }) => (
  <div role="dialog" aria-modal="true" aria-labelledby="rr-title"
       style={{position:'fixed',inset:0,zIndex:200,pointerEvents:'auto'}}>
    <div onClick={onClose}
      style={{position:'absolute',inset:0,background:'rgba(26,26,23,0.32)',animation:'kestrel-overlay-in 220ms var(--ease-quiet) both'}}/>
    <div className="thin-scroll review-modal" style={{
      position:'absolute',top:'50%',left:'50%',transform:'translate(-50%,-50%)',
      width:'min(640px,calc(100vw - 32px))',
      maxHeight:'calc(100vh - 48px)',overflowY:'auto',
      background:'var(--canvas)',border:'1px solid var(--line)',borderRadius:14,
      boxShadow:'var(--shadow-float)',
      animation:'kestrel-overlay-in 240ms var(--ease-quiet) both',
    }}>
      {children}
    </div>
  </div>
);

const ReviewMeta = ({ k, children }) => (
  <div style={{minWidth:0}}>
    <div className="eyebrow" style={{fontSize:10}}>{k}</div>
    <div style={{fontSize:13,color:'var(--ink)',marginTop:3,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}} title={typeof children === 'string' ? children : undefined}>
      {children || '—'}
    </div>
  </div>
);

/* Local copy of contact.jsx's <Field> — kept private so this script has
 * no cross-file load-order dependency on contact.jsx. */
const RRField = ({ label, required, full, help, error, children }) => (
  <div className={`contact-field ${full ? 'is-full' : ''}`} style={full ? {gridColumn:'1 / -1'} : undefined}>
    <div className="contact-field-head">
      <label className="contact-label">
        {label}{required && <span aria-hidden="true" style={{color:'var(--moss-deep)',marginLeft:4}}>*</span>}
      </label>
      {help && <span className="contact-help">{help}</span>}
    </div>
    {children}
    {error && <div className="contact-error" role="alert">{error}</div>}
  </div>
);

window.ReviewRequestModal = ReviewRequestModal;
