// Project R — API tools section for the skill drawer.
// Optional. A skill can declare zero, one, or many tools. Each tool maps to
// a generic "fire an HTTP request with LLM-supplied inputs" runtime call.
//
// Two ways in: paste raw JSON, or upload a .json file. Both feed the same
// parser. Once parsed, tools render as editable cards. Inline fields for the
// common stuff (name, description, method, url, timeout); the more
// structured bits (headers, body fields, response) live in collapsible
// sub-editors and are edited as JSON text — that's deliberate, those shapes
// are too varied for a fixed form and the JSON is what the backend stores
// anyway.

const { useState: useATS, useEffect: useATE, useRef: useATR, useMemo: useATM } = React;

const METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];

// Normalise whatever the user threw in: bare object, single tool object,
// array of tools, or a wrapper like {api_tools: [...]}. Returns an array.
function normaliseApiTools(raw) {
  if (raw == null) return [];
  if (Array.isArray(raw)) return raw;
  if (typeof raw === 'object') {
    if (Array.isArray(raw.api_tools)) return raw.api_tools;
    if (Array.isArray(raw.tools)) return raw.tools;
    // Single tool definition (has a name + url)
    if (raw.name && raw.url) return [raw];
  }
  return [];
}

// Light validation — surfaces problems but doesn't gate. The user can still
// save a tool with warnings; the runtime will reject anything truly broken.
function validateTool(t) {
  const errs = [];
  if (!t || typeof t !== 'object') return ['Tool must be an object.'];
  if (!t.name || typeof t.name !== 'string') errs.push('Missing name.');
  else if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(t.name)) errs.push('Name should be snake_case (letters, digits, underscore).');
  if (!t.url || typeof t.url !== 'string') errs.push('Missing url.');
  if (t.method && !METHODS.includes(String(t.method).toUpperCase())) errs.push(`Unsupported method: ${t.method}`);
  if (t.headers && typeof t.headers !== 'object') errs.push('Headers must be an object.');
  if (t.body && typeof t.body !== 'object') errs.push('Body must be an object.');
  return errs;
}

function ApiToolsSection({ value, onChange }) {
  // value is the array of tools (possibly empty). Section is collapsed when
  // empty — user opts in by clicking "Add API tools".
  const [expanded, setExpanded] = useATS(value && value.length > 0);
  const [importMode, setImportMode] = useATS(null); // null | 'paste' | 'file'
  const [pasteText, setPasteText] = useATS('');
  const [parseError, setParseError] = useATS('');
  const fileRef = useATR();

  useATE(() => {
    if (value && value.length > 0 && !expanded) setExpanded(true);
  }, [value && value.length]);

  const tools = value || [];

  const importParsed = (parsed) => {
    const arr = normaliseApiTools(parsed);
    if (arr.length === 0) {
      setParseError('No tools found. Expected an array, or an object with an api_tools array.');
      return;
    }
    onChange([...(tools || []), ...arr]);
    setImportMode(null);
    setPasteText('');
    setParseError('');
  };

  const handlePaste = () => {
    setParseError('');
    if (!pasteText.trim()) { setParseError('Paste some JSON first.'); return; }
    let parsed;
    try {
      parsed = JSON.parse(pasteText);
    } catch (e) {
      // Try wrapping fragment in [] in case user pasted a bare comma-separated
      // list of tool objects (the snippet style from internal docs).
      try { parsed = JSON.parse('[' + pasteText.trim().replace(/,\s*$/, '') + ']'); }
      catch { setParseError('Invalid JSON: ' + e.message); return; }
    }
    importParsed(parsed);
  };

  const handleFile = (fs) => {
    if (!fs || !fs[0]) return;
    const f = fs[0];
    const r = new FileReader();
    r.onload = (e) => {
      try { importParsed(JSON.parse(e.target.result)); }
      catch (err) { setParseError('Could not parse ' + f.name + ': ' + err.message); }
    };
    r.onerror = () => setParseError('Failed to read file.');
    r.readAsText(f);
  };

  const updateTool = (idx, patch) => {
    const next = tools.map((t, i) => i === idx ? { ...t, ...patch } : t);
    onChange(next);
  };
  const removeTool = (idx) => onChange(tools.filter((_, i) => i !== idx));
  const addBlank = () => {
    onChange([...tools, {
      name: 'new_tool', description: '', method: 'POST', url: '',
      headers: { 'Content-Type': { value: 'application/json' } },
      body: {}, timeout_seconds: 30,
    }]);
  };

  // Collapsed empty state — just the opt-in button.
  if (!expanded && tools.length === 0) {
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
        <div>
          <div style={{ fontFamily: "'Suisse Int\\'l', sans-serif", fontWeight: 500, fontSize: 14, color: 'var(--c-ink-900)' }}>
            API tools <span style={{ fontSize: 11, fontWeight: 500, color: 'var(--c-ink-500)', letterSpacing: '0.04em', marginLeft: 6, padding: '2px 6px', borderRadius: 4, background: 'var(--c-cream-100)', border: '1px solid var(--border-subtle)' }}>OPTIONAL</span>
          </div>
          <div style={{ fontSize: 12, color: 'var(--c-ink-500)', marginTop: 2 }}>
            Let this skill call HTTP endpoints at runtime. Most skills don't need this.
          </div>
        </div>
        <button onClick={() => setExpanded(true)} style={{
          alignSelf: 'flex-start', height: 36, padding: '0 14px', borderRadius: 10,
          border: '1.5px dashed var(--border-default)', background: 'var(--c-white)',
          color: 'var(--c-petrol-800)', fontFamily: "'Inter', sans-serif",
          fontWeight: 700, fontSize: 12, cursor: 'pointer',
          display: 'inline-flex', alignItems: 'center', gap: 6,
        }}>
          <img src="../assets/icons/plus.svg" width={11} height={11} alt="" />
          Add API tools
        </button>
      </div>
    );
  }

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
      {/* Header */}
      <div style={{ display: 'flex', alignItems: 'flex-start', gap: 8 }}>
        <div style={{ flex: 1 }}>
          <div style={{ fontFamily: "'Suisse Int\\'l', sans-serif", fontWeight: 500, fontSize: 14, color: 'var(--c-ink-900)' }}>
            API tools
            <span style={{ fontSize: 11, fontWeight: 500, color: 'var(--c-ink-500)', letterSpacing: '0.04em', marginLeft: 6, padding: '2px 6px', borderRadius: 4, background: 'var(--c-cream-100)', border: '1px solid var(--border-subtle)' }}>OPTIONAL</span>
          </div>
          <div style={{ fontSize: 12, color: 'var(--c-ink-500)', marginTop: 2 }}>
            Each tool defines an HTTP call the LLM can invoke at runtime. Inputs are populated by the model.
          </div>
        </div>
        {tools.length > 0 && (
          <button onClick={() => { onChange([]); setExpanded(false); }} title="Remove all API tools" style={{
            height: 32, padding: '0 10px', borderRadius: 8, border: '1px solid var(--border-subtle)',
            background: 'var(--c-white)', color: 'var(--c-ink-500)',
            fontFamily: "'Inter', sans-serif", fontWeight: 700, fontSize: 11, cursor: 'pointer',
          }}>Clear</button>
        )}
      </div>

      {/* Existing tools */}
      {tools.map((t, i) => (
        <ToolCard key={i} tool={t} onChange={p => updateTool(i, p)} onRemove={() => removeTool(i)} />
      ))}

      {/* Importer */}
      <div style={{
        padding: 12, borderRadius: 12, background: 'var(--c-cream-100)',
        border: '1px dashed var(--border-default)',
        display: 'flex', flexDirection: 'column', gap: 10,
      }}>
        {importMode === null && (
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
            <button onClick={() => fileRef.current && fileRef.current.click()} style={ghostBtn}>
              <img src="../assets/icons/plus.svg" width={11} height={11} alt="" />
              Upload JSON file
            </button>
            <button onClick={() => setImportMode('paste')} style={ghostBtn}>
              Paste JSON
            </button>
            <button onClick={addBlank} style={ghostBtn}>
              Add blank tool
            </button>
            <input ref={fileRef} type="file" accept="application/json,.json"
              style={{ display: 'none' }}
              onChange={e => { handleFile(e.target.files); e.target.value = ''; }} />
          </div>
        )}
        {importMode === 'paste' && (
          <>
            <textarea value={pasteText} onChange={e => setPasteText(e.target.value)}
              placeholder='Paste tool JSON. Accepts an array, a single tool object, or {"api_tools": [...]}.'
              rows={8}
              style={{
                width: '100%', boxSizing: 'border-box', padding: '10px 12px', borderRadius: 10,
                border: '1.5px solid var(--border-subtle)', background: 'var(--c-white)',
                fontFamily: 'ui-monospace, "JetBrains Mono", Menlo, monospace', fontSize: 12,
                lineHeight: 1.5, color: 'var(--c-ink-900)', resize: 'vertical', outline: 'none',
              }} />
            <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', alignItems: 'center' }}>
              <button onClick={() => { setImportMode(null); setPasteText(''); setParseError(''); }} style={pasteActionBtn(false)}>Cancel</button>
              <button onClick={handlePaste} style={pasteActionBtn(true)}>Import</button>
            </div>
          </>
        )}
        {parseError && (
          <div style={{
            fontSize: 12, color: 'var(--c-terra-600, #C65A42)',
            fontFamily: "'Inter', sans-serif",
          }}>{parseError}</div>
        )}
      </div>
    </div>
  );
}

// One tool. Inline editable fields up top, collapsible JSON sub-editors for
// the structured bits.
function ToolCard({ tool, onChange, onRemove }) {
  const errs = useATM(() => validateTool(tool), [tool]);
  const [openSection, setOpenSection] = useATS(null); // 'headers' | 'body' | 'response' | null

  return (
    <div style={{
      padding: 14, borderRadius: 12, background: 'var(--c-white)',
      border: '1px solid var(--border-subtle)', boxShadow: 'var(--shadow-raised-sm)',
      display: 'flex', flexDirection: 'column', gap: 10,
    }}>
      {/* Top row — name + remove */}
      <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
        <div style={{
          padding: '2px 8px', borderRadius: 6, background: 'var(--c-petrol-050, #E8F0F2)',
          color: 'var(--c-petrol-800)', fontFamily: "'Inter', sans-serif",
          fontWeight: 700, fontSize: 10, letterSpacing: '0.06em', flex: 'none',
        }}>TOOL</div>
        <input value={tool.name || ''}
          onChange={e => onChange({ name: e.target.value.replace(/[^a-zA-Z0-9_]/g, '_') })}
          placeholder="tool_name"
          style={{ ...fieldInput, flex: 1, height: 36,
            fontFamily: 'ui-monospace, "JetBrains Mono", Menlo, monospace', fontSize: 13 }} />
        <button onClick={onRemove} title="Remove tool" style={{
          width: 36, height: 36, borderRadius: 10, border: '1px solid var(--border-subtle)',
          background: 'var(--c-cream-50)', cursor: 'pointer',
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flex: 'none',
        }}>
          <img src="../assets/icons/cross.svg" width={11} height={11} alt="" />
        </button>
      </div>

      {/* Description */}
      <textarea value={tool.description || ''}
        onChange={e => onChange({ description: e.target.value })}
        placeholder="What this tool does. The LLM reads this verbatim."
        rows={2}
        style={{ ...fieldInput, height: 'auto', minHeight: 56, padding: '10px 14px', resize: 'vertical', lineHeight: 1.45 }} />

      {/* Method + URL */}
      <div style={{ display: 'flex', gap: 8 }}>
        <select value={(tool.method || 'POST').toUpperCase()}
          onChange={e => onChange({ method: e.target.value })}
          style={{ ...fieldInput, width: 100, height: 36, padding: '0 10px',
            fontFamily: "'Inter', sans-serif", fontWeight: 700, fontSize: 12, cursor: 'pointer' }}>
          {METHODS.map(m => <option key={m} value={m}>{m}</option>)}
        </select>
        <input value={tool.url || ''}
          onChange={e => onChange({ url: e.target.value })}
          placeholder="https://api.example.com/v1/endpoint"
          style={{ ...fieldInput, flex: 1, height: 36,
            fontFamily: 'ui-monospace, "JetBrains Mono", Menlo, monospace', fontSize: 12 }} />
      </div>

      {/* Timeout */}
      <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
        <label style={{ fontSize: 12, color: 'var(--c-ink-500)', fontFamily: "'Inter', sans-serif", fontWeight: 500 }}>Timeout (s)</label>
        <input type="number" min={1} max={300}
          value={tool.timeout_seconds || 30}
          onChange={e => onChange({ timeout_seconds: parseInt(e.target.value, 10) || 30 })}
          style={{ ...fieldInput, width: 80, height: 32, padding: '0 10px',
            fontFamily: 'ui-monospace, "JetBrains Mono", Menlo, monospace', fontSize: 12 }} />
      </div>

      {/* Sub-editors */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginTop: 2 }}>
        <SubEditor label="Headers"
          summary={summarise(tool.headers)}
          isOpen={openSection === 'headers'}
          onToggle={() => setOpenSection(openSection === 'headers' ? null : 'headers')}
          value={tool.headers}
          onChange={v => onChange({ headers: v })} />
        <SubEditor label="Body fields"
          summary={summarise(tool.body)}
          isOpen={openSection === 'body'}
          onToggle={() => setOpenSection(openSection === 'body' ? null : 'body')}
          value={tool.body}
          onChange={v => onChange({ body: v })} />
        <SubEditor label="Response"
          summary={tool.response ? summarise(tool.response) : 'defaults'}
          isOpen={openSection === 'response'}
          onToggle={() => setOpenSection(openSection === 'response' ? null : 'response')}
          value={tool.response}
          onChange={v => onChange({ response: v })} />
      </div>

      {/* Validation */}
      {errs.length > 0 && (
        <div style={{
          padding: '8px 10px', borderRadius: 8,
          background: 'rgba(198, 90, 66, 0.08)',
          border: '1px solid rgba(198, 90, 66, 0.3)',
          fontSize: 11, fontFamily: "'Inter', sans-serif",
          color: 'var(--c-terra-600, #C65A42)', lineHeight: 1.5,
        }}>
          {errs.map((e, i) => <div key={i}>• {e}</div>)}
        </div>
      )}
    </div>
  );
}

// Collapsible JSON sub-editor. We edit as JSON because shapes vary too much
// to bake a fixed form, and what we round-trip IS the JSON anyway.
function SubEditor({ label, summary, isOpen, onToggle, value, onChange }) {
  const [text, setText] = useATS(() => value === undefined ? '' : JSON.stringify(value, null, 2));
  const [error, setError] = useATS('');

  useATE(() => {
    if (isOpen) setText(value === undefined ? '' : JSON.stringify(value, null, 2));
  }, [isOpen]);

  const commit = (raw) => {
    setText(raw);
    if (!raw.trim()) { setError(''); onChange(undefined); return; }
    try {
      const parsed = JSON.parse(raw);
      setError('');
      onChange(parsed);
    } catch (e) {
      setError(e.message);
    }
  };

  return (
    <div style={{
      borderRadius: 8, border: '1px solid var(--border-subtle)',
      background: 'var(--c-cream-50)', overflow: 'hidden',
    }}>
      <button onClick={onToggle} style={{
        width: '100%', padding: '8px 12px', border: 'none', background: 'transparent',
        cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 8, textAlign: 'left',
      }}>
        <span style={{
          width: 14, height: 14, display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          color: 'var(--c-ink-500)', transform: isOpen ? 'rotate(90deg)' : 'rotate(0)',
          transition: 'transform .12s ease-out', fontSize: 10,
        }}>▶</span>
        <span style={{ fontFamily: "'Inter', sans-serif", fontWeight: 700, fontSize: 12, color: 'var(--c-ink-900)' }}>{label}</span>
        <span style={{
          flex: 1, fontFamily: 'ui-monospace, "JetBrains Mono", Menlo, monospace',
          fontSize: 11, color: 'var(--c-ink-500)', whiteSpace: 'nowrap',
          overflow: 'hidden', textOverflow: 'ellipsis',
        }}>{summary}</span>
      </button>
      {isOpen && (
        <div style={{ padding: '0 10px 10px', display: 'flex', flexDirection: 'column', gap: 6 }}>
          <textarea value={text} onChange={e => commit(e.target.value)}
            rows={8}
            spellCheck={false}
            style={{
              width: '100%', boxSizing: 'border-box', padding: '8px 10px', borderRadius: 6,
              border: `1px solid ${error ? 'var(--c-terra-600, #C65A42)' : 'var(--border-subtle)'}`,
              background: 'var(--c-white)',
              fontFamily: 'ui-monospace, "JetBrains Mono", Menlo, monospace', fontSize: 11,
              lineHeight: 1.5, color: 'var(--c-ink-900)', resize: 'vertical', outline: 'none',
            }} />
          {error && (
            <div style={{ fontSize: 11, color: 'var(--c-terra-600, #C65A42)' }}>JSON: {error}</div>
          )}
        </div>
      )}
    </div>
  );
}

// Compact one-line summary of an object — used for the collapsed sub-editor
// header so the user can see at a glance what's in there without expanding.
function summarise(obj) {
  if (obj == null) return 'empty';
  if (typeof obj !== 'object') return String(obj);
  const keys = Object.keys(obj);
  if (keys.length === 0) return 'empty';
  return `${keys.length} ${keys.length === 1 ? 'field' : 'fields'} · ${keys.slice(0, 4).join(', ')}${keys.length > 4 ? '…' : ''}`;
}

const fieldInput = {
  height: 44, padding: '0 14px', borderRadius: 10,
  background: 'var(--c-cream-50)',
  border: '1.5px solid var(--border-subtle)',
  boxShadow: 'var(--shadow-inset-input)',
  fontFamily: "'Suisse Int\\'l', sans-serif", fontSize: 14, color: 'var(--c-ink-900)',
  width: '100%', outline: 'none', boxSizing: 'border-box',
};

const ghostBtn = {
  height: 36, padding: '0 12px', borderRadius: 10,
  border: '1.5px solid var(--border-subtle)',
  background: 'var(--c-white)', color: 'var(--c-petrol-800)',
  fontFamily: "'Inter', sans-serif", fontWeight: 700, fontSize: 12,
  cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6,
};

// Cancel + Import share identical chrome (size, padding, font, radius) so
// they sit side-by-side as a balanced pair. Only the fill swaps.
const pasteActionBtn = (primary) => ({
  height: 36, padding: '0 16px', borderRadius: 10,
  border: primary ? 'none' : '1.5px solid var(--c-petrol-800)',
  background: primary ? 'var(--c-petrol-800)' : 'var(--c-white)',
  color: primary ? '#fff' : 'var(--c-petrol-800)',
  fontFamily: "'Inter', sans-serif", fontWeight: 700, fontSize: 12,
  letterSpacing: '0.02em',
  boxShadow: primary ? 'var(--shadow-raised-sm)' : 'none',
  cursor: 'pointer',
  display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
  minWidth: 92, boxSizing: 'border-box',
});

const primaryBtn = {
  height: 36, padding: '0 14px', borderRadius: 10,
  border: 'none', background: 'var(--c-petrol-800)', color: '#fff',
  fontFamily: "'Inter', sans-serif", fontWeight: 700, fontSize: 12,
  boxShadow: 'var(--shadow-raised-sm)', cursor: 'pointer',
};

// ─────────────────────────────────────────────────────────────────────────
// ApiConfigSection — schema/skills.json-shaped api_config editor.
// Replaces the legacy ApiToolsSection. Renders a card per endpoint with
// inline-editable URL + method, expandable Headers (JSON), Body params, and
// Query params. Drives the same state shape we send to the backend:
//   [{ url, method, headers, body: [{parameter, description}], query_params: [...] }]
// ─────────────────────────────────────────────────────────────────────────

const HEADERS_PLACEHOLDER = '{\n  "Content-Type": "application/json",\n  "Authorization": "Bearer {{token}}"\n}';

function ApiConfigSection({ value, onChange }) {
  const rows = Array.isArray(value) ? value : [];

  const update = (idx, patch) =>
    onChange(rows.map((r, i) => i === idx ? { ...r, ...patch } : r));
  const remove = (idx) => onChange(rows.filter((_, i) => i !== idx));
  const add = () =>
    onChange([...rows, {
      url: '', method: 'GET', headers: {}, body: [], query_params: [],
    }]);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      <div style={{
        display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 12,
      }}>
        <div>
          <div style={{
            fontFamily: "'Suisse Int\\'l', sans-serif", fontWeight: 600, fontSize: 14,
            color: 'var(--c-ink-900)',
          }}>API endpoints <span style={{
            fontFamily: "'Inter', sans-serif", fontWeight: 500, fontSize: 11,
            color: 'var(--c-ink-500)', letterSpacing: '0.04em', marginLeft: 6,
          }}>{rows.length} configured</span></div>
          <div style={{ fontSize: 12, color: 'var(--c-ink-600)', marginTop: 2, lineHeight: 1.45 }}>
            Endpoints the runtime executor will call. Auto-populated from <code>api_config</code>
            in <code>SKILL.md</code> when you upload a .skill bundle. Edit, add, or remove freely.
          </div>
        </div>
        <button type="button" onClick={add} style={{
          height: 32, padding: '0 12px', borderRadius: 8, flex: 'none',
          background: 'var(--c-cream-50)', color: 'var(--c-petrol-800)',
          border: '1.5px solid var(--c-petrol-800)', cursor: 'pointer',
          fontFamily: "'Suisse Int\\'l', sans-serif", fontWeight: 500, fontSize: 12,
          display: 'inline-flex', alignItems: 'center', gap: 6,
        }}>
          <img src="../assets/icons/plus.svg" width={10} height={10} alt=""
            style={{ filter: 'invert(20%) sepia(15%) saturate(800%) hue-rotate(160deg)' }} />
          Add endpoint
        </button>
      </div>

      {rows.length === 0 && (
        <div style={{
          padding: 24, borderRadius: 12, textAlign: 'center',
          background: 'var(--c-cream-50)', border: '1px dashed var(--border-default)',
          fontSize: 12, color: 'var(--c-ink-500)',
        }}>
          No endpoints yet. Upload a <code>.skill</code> bundle on step 4 to auto-populate, or click
          <strong style={{ color: 'var(--c-petrol-800)' }}> Add endpoint</strong> to define one manually.
        </div>
      )}

      {rows.map((row, idx) => (
        <ApiConfigCard
          key={idx}
          row={row}
          onChange={(patch) => update(idx, patch)}
          onRemove={() => remove(idx)}
          index={idx}
        />
      ))}
    </div>
  );
}

function ApiConfigCard({ row, onChange, onRemove, index }) {
  const [headersOpen, setHeadersOpen] = useATS(false);
  const [headersText, setHeadersText] = useATS(() => safeStringify(row.headers || {}));
  const [headersErr, setHeadersErr] = useATS('');

  // Re-sync the headers textarea when the row's headers prop changes from
  // outside (e.g. parse autofill landed after this card already mounted).
  useATE(() => { setHeadersText(safeStringify(row.headers || {})); setHeadersErr(''); }, [JSON.stringify(row.headers || {})]);

  const commitHeaders = () => {
    if (!headersText.trim()) {
      onChange({ headers: {} });
      setHeadersErr('');
      return;
    }
    try {
      const parsed = JSON.parse(headersText);
      if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
        onChange({ headers: parsed });
        setHeadersErr('');
      } else {
        setHeadersErr('Headers must be a JSON object.');
      }
    } catch (e) {
      setHeadersErr('Invalid JSON.');
    }
  };

  const method = row.method || 'GET';
  const methodColor = method === 'GET' ? 'var(--c-petrol-800)'
    : method === 'POST' ? 'var(--c-olive-700, #3F4A28)'
    : method === 'PUT' || method === 'PATCH' ? 'var(--c-gold-700, #946B0F)'
    : 'var(--c-terra-600, #C65A42)';

  return (
    <div style={{
      padding: 14, borderRadius: 12,
      background: 'var(--c-cream-50)', border: '1px solid var(--border-subtle)',
      display: 'flex', flexDirection: 'column', gap: 12,
    }}>
      {/* Header row: method + url + remove */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
        <select value={method} onChange={(e) => onChange({ method: e.target.value })}
          style={{
            height: 32, padding: '0 8px', borderRadius: 8, flex: 'none',
            background: '#fff', color: methodColor, fontWeight: 700, fontSize: 12,
            border: '1.5px solid var(--border-subtle)',
            fontFamily: "'JetBrains Mono', monospace",
          }}>
          {METHODS.map(m => <option key={m} value={m}>{m}</option>)}
        </select>
        <input value={row.url || ''} onChange={(e) => onChange({ url: e.target.value })}
          placeholder="https://api.example.com/v1/resource"
          style={{
            flex: 1, minWidth: 0, height: 32, padding: '0 10px', borderRadius: 8,
            background: '#fff', border: '1.5px solid var(--border-subtle)',
            fontFamily: "'JetBrains Mono', monospace", fontSize: 12,
            color: 'var(--c-ink-900)', outline: 'none',
          }} />
        <button type="button" onClick={onRemove} title={`Remove endpoint #${index + 1}`}
          style={{
            width: 32, height: 32, borderRadius: 8, flex: 'none',
            background: 'transparent', color: 'var(--c-terra-600, #C65A42)',
            border: '1px solid var(--border-subtle)', cursor: 'pointer',
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          }}>
          <img src="../assets/icons/cross.svg" width={10} height={10} alt="Remove" />
        </button>
      </div>

      {/* Headers (collapsible) */}
      <div>
        <button type="button" onClick={() => setHeadersOpen(o => !o)}
          style={{
            background: 'transparent', border: 'none', padding: 0, cursor: 'pointer',
            fontFamily: "'Inter', sans-serif", fontSize: 11, fontWeight: 600,
            color: 'var(--c-ink-700)', letterSpacing: '0.04em', textTransform: 'uppercase',
          }}>
          {headersOpen ? '▾' : '▸'} Headers · {Object.keys(row.headers || {}).length} key(s)
        </button>
        {headersOpen && (
          <div style={{ marginTop: 8 }}>
            <textarea value={headersText}
              onChange={(e) => setHeadersText(e.target.value)}
              onBlur={commitHeaders}
              placeholder={HEADERS_PLACEHOLDER}
              rows={4}
              style={{
                width: '100%', padding: '10px 12px', borderRadius: 8,
                background: '#fff', border: '1.5px solid var(--border-subtle)',
                fontFamily: "'JetBrains Mono', monospace", fontSize: 12, lineHeight: 1.5,
                color: 'var(--c-ink-900)', outline: 'none', resize: 'vertical',
                boxSizing: 'border-box',
              }} />
            {headersErr && <div style={{ marginTop: 4, fontSize: 11, color: 'var(--c-terra-600, #C65A42)' }}>{headersErr}</div>}
          </div>
        )}
      </div>

      {/* Body params */}
      <ApiConfigParamList
        label="Body parameters"
        items={row.body || []}
        onChange={(next) => onChange({ body: next })}
      />

      {/* Query params */}
      <ApiConfigParamList
        label="Query parameters"
        items={row.query_params || []}
        onChange={(next) => onChange({ query_params: next })}
      />
    </div>
  );
}

function ApiConfigParamList({ label, items, onChange }) {
  const [open, setOpen] = useATS(false);
  const update = (idx, patch) => onChange(items.map((p, i) => i === idx ? { ...p, ...patch } : p));
  const remove = (idx) => onChange(items.filter((_, i) => i !== idx));
  const add = () => onChange([...items, { parameter: '', description: '' }]);

  return (
    <div>
      <button type="button" onClick={() => setOpen(o => !o)}
        style={{
          background: 'transparent', border: 'none', padding: 0, cursor: 'pointer',
          fontFamily: "'Inter', sans-serif", fontSize: 11, fontWeight: 600,
          color: 'var(--c-ink-700)', letterSpacing: '0.04em', textTransform: 'uppercase',
        }}>
        {open ? '▾' : '▸'} {label} · {items.length}
      </button>
      {open && (
        <div style={{ marginTop: 8, display: 'flex', flexDirection: 'column', gap: 8 }}>
          {items.length === 0 && (
            <div style={{ fontSize: 11, color: 'var(--c-ink-500)' }}>No parameters yet.</div>
          )}
          {items.map((p, idx) => (
            <div key={idx} style={{
              display: 'grid', gridTemplateColumns: '180px 1fr auto', gap: 8, alignItems: 'flex-start',
            }}>
              <input value={p.parameter || ''} onChange={(e) => update(idx, { parameter: e.target.value })}
                placeholder="parameter_name"
                style={{
                  height: 32, padding: '0 10px', borderRadius: 8,
                  background: '#fff', border: '1.5px solid var(--border-subtle)',
                  fontFamily: "'JetBrains Mono', monospace", fontSize: 12,
                  color: 'var(--c-ink-900)', outline: 'none',
                }} />
              <textarea value={p.description || ''}
                onChange={(e) => update(idx, { description: e.target.value })}
                placeholder="What this parameter is, type, format. The runtime LLM reads this verbatim."
                rows={2}
                style={{
                  padding: '8px 10px', borderRadius: 8,
                  background: '#fff', border: '1.5px solid var(--border-subtle)',
                  fontSize: 12, lineHeight: 1.45, color: 'var(--c-ink-900)',
                  outline: 'none', resize: 'vertical', fontFamily: "'Inter', sans-serif",
                  boxSizing: 'border-box',
                }} />
              <button type="button" onClick={() => remove(idx)} title="Remove parameter"
                style={{
                  width: 32, height: 32, borderRadius: 8, flex: 'none',
                  background: 'transparent', color: 'var(--c-terra-600, #C65A42)',
                  border: '1px solid var(--border-subtle)', cursor: 'pointer',
                  display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                }}>
                <img src="../assets/icons/cross.svg" width={10} height={10} alt="Remove" />
              </button>
            </div>
          ))}
          <button type="button" onClick={add}
            style={{
              alignSelf: 'flex-start',
              height: 28, padding: '0 10px', borderRadius: 8,
              background: 'transparent', color: 'var(--c-petrol-800)',
              border: '1px dashed var(--c-petrol-800)', cursor: 'pointer',
              fontFamily: "'Inter', sans-serif", fontWeight: 500, fontSize: 11,
            }}>
            + Add parameter
          </button>
        </div>
      )}
    </div>
  );
}

function safeStringify(o) { try { return JSON.stringify(o, null, 2); } catch { return '{}'; } }

Object.assign(window, { ApiToolsSection, ApiConfigSection });
