// Right-side inspector for either the selected node or edge
function Inspector({
  selection, setSelection,
  nodes, edges, groups, writings,
  updateNode, updateEdge, updateWriting,
  deleteNode, deleteEdge, deleteWriting,
  addNode, addWriting, clearAll,
  onLoadDemo,
  createGroupFromNode, updateGroup, deleteGroup,
  composingGroupId, setComposingGroupId,
}){
  groups = groups || [];
  writings = writings || [];
  if (!selection){
    return (
      <div className="side">
        <div className="card">
          <h3>Getting started</h3>
          <div style={{fontSize:13, lineHeight:1.7, color:'var(--ink-soft)'}}>
            ・Click <b>＋ Node</b> to add a character<br/>
            ・Drag the <b style={{color:'#7DD8B4'}}>＋</b> on the top-right of an avatar onto another character to create a relationship line<br/>
            ・Click a line or a node to edit it
          </div>
        </div>
        <div style={{display:'flex',gap:8, flexDirection:'column'}}>
          <button className="btn primary" onClick={addNode}>＋ Add a node</button>
          <button className="btn" onClick={addWriting}
                  style={{background:'var(--lav)', color:'#fff'}}>＋ Add a writing</button>
          <button className="btn" onClick={onLoadDemo}>🎀 Load sample diagram</button>
          <button className="btn ghost" onClick={clearAll}>🧹 Clear all</button>
        </div>
        <div className="empty-hint">
          Nothing selected.<br/>Click a node or a line on the canvas.
        </div>
      </div>
    );
  }

  if (selection.type === 'node'){
    const node = nodes.find(n=>n.id===selection.id);
    if (!node) return null;
    const nodeGroups = groups.filter(g => (g.nodeIds || []).includes(node.id));
    return (
      <div className="side">
        <NodeInspector node={node} updateNode={updateNode} deleteNode={deleteNode}
                       nodeGroups={nodeGroups}
                       createGroupFromNode={createGroupFromNode}
                       updateGroup={updateGroup} deleteGroup={deleteGroup}
                       setComposingGroupId={setComposingGroupId}
                       setSelection={setSelection}/>
      </div>
    );
  }

  if (selection.type === 'edge'){
    const edge = edges.find(e=>e.id===selection.id);
    if (!edge) return null;
    return (
      <div className="side">
        <EdgeInspector edge={edge} nodes={nodes} updateEdge={updateEdge} deleteEdge={deleteEdge}/>
      </div>
    );
  }

  if (selection.type === 'writing'){
    const writing = writings.find(w => w.id === selection.id);
    if (!writing) return null;
    return (
      <div className="side">
        <WritingInspector writing={writing} nodes={nodes} edges={edges}
                          updateWriting={updateWriting} deleteWriting={deleteWriting}/>
      </div>
    );
  }

  if (selection.type === 'group'){
    const group = groups.find(g=>g.id===selection.id);
    if (!group) return null;
    return (
      <div className="side">
        <GroupInspector group={group} nodes={nodes}
                        updateGroup={updateGroup} deleteGroup={deleteGroup}
                        setComposingGroupId={setComposingGroupId}
                        setSelection={setSelection}/>
      </div>
    );
  }
  return null;
}

function NodeInspector({node, updateNode, deleteNode, nodeGroups, createGroupFromNode, updateGroup, deleteGroup, setComposingGroupId, setSelection}){
  nodeGroups = nodeGroups || [];
  const fileRef = React.useRef(null);
  const onFile = async (e) => {
    const f = e.target.files?.[0];
    if (!f) return;
    try {
      const dataUrl = await compressImage(f);
      updateNode(node.id, { image: dataUrl });
    } catch(err) {
      console.error('Image compression failed', err);
    }
    e.target.value = '';
  };

  return (
    <>
      <h3>Edit node</h3>
      <div className="card">
        <div className="field">
          <label>Name</label>
          <input type="text" value={node.name||''} maxLength={40}
                 onChange={e=>updateNode(node.id,{name:e.target.value})}
                 placeholder="Character name"/>
        </div>
        <div className="field">
          <label>Subtitle / role (shown under name)</label>
          <input type="text" value={node.subtitle||''} maxLength={60}
                 onChange={e=>updateNode(node.id,{subtitle:e.target.value})}
                 placeholder="Protagonist / Freshman / etc."/>
        </div>
      </div>

      <div className="card mint">
        <h3 style={{marginTop:0}}>Avatar</h3>
        <div style={{display:'flex',gap:6,marginBottom:10, flexWrap:'wrap'}}>
          <button className="btn sm" onClick={()=>fileRef.current.click()}>📷 Upload image</button>
          {node.image && <button className="btn sm ghost" onClick={()=>updateNode(node.id,{image:null})}>Clear image</button>}
          <input ref={fileRef} className="file-hidden" type="file" accept="image/*" onChange={onFile}/>
        </div>
        <div className="field">
          <label>Emoji</label>
          <div className="emoji-row">
            <button className={!node.emoji?'on':''} onClick={()=>updateNode(node.id,{emoji:null})}>—</button>
            {EMOJI_PRESETS.map(em=>(
              <button key={em} className={node.emoji===em?'on':''}
                      onClick={()=>updateNode(node.id,{emoji:em, image:null})}>{em}</button>
            ))}
          </div>
        </div>
        <div className="field">
          <label>Avatar color</label>
          <div className="swatches">
            {NODE_COLORS.map(c=>(
              <button key={c} style={{background:c}}
                      className={node.color===c?'on':''}
                      onClick={()=>updateNode(node.id,{color:c})}/>
            ))}
            <label className={'rainbow-swatch' + (NODE_COLORS.indexOf(node.color)<0 ? ' on' : '')}
                   title="Pick a custom color"
                   style={{
                     width:30, height:30, borderRadius:'50%',
                     background:'conic-gradient(from 0deg, #f56a92, #ffd97a, #7dd8b4, #8ccbf0, #b7a0ee, #f56a92)',
                     border:'3px solid #fff', boxShadow:'0 2px 0 rgba(120,76,110,.15)',
                     cursor:'pointer', position:'relative', display:'inline-block', flexShrink:0,
                   }}>
              <input type="color" value={node.color || '#FFB3C7'}
                     onChange={e=>updateNode(node.id,{color:e.target.value},{skipHistory:true})}
                     onBlur={e=>updateNode(node.id,{color:e.target.value})}
                     style={{position:'absolute', inset:0, width:'100%', height:'100%', opacity:0, cursor:'pointer', border:'none', padding:0}}/>
            </label>
          </div>
        </div>
        <div className="field">
          <label>Shape</label>
          <div className="seg">
            {[['circle','Circle'],['square','Square'],['bubble','Bubble']].map(([v,l])=>(
              <button key={v} className={node.shape===v || (!node.shape && v==='circle')?'on':''}
                      onClick={()=>updateNode(node.id,{shape:v})}>{l}</button>
            ))}
          </div>
        </div>
        {/* Name/subtitle position relative to the avatar. Default = bottom.
            Useful when nodes are packed close together and labels collide. */}
        <div className="field">
          <label>Label position</label>
          <div className="seg">
            {[['top','Top'], ['left','Left'], ['bottom','Bottom'], ['right','Right']].map(([v,l])=>(
              <button key={v} className={(node.labelPos || 'bottom')===v?'on':''}
                      onClick={()=>updateNode(node.id,{labelPos:v})}>{l}</button>
            ))}
          </div>
        </div>
      </div>

      <button className="btn" style={{background:'#FFE0E0', color:'#C94A4A'}}
              onClick={()=>deleteNode(node.id)}>🗑 Delete node</button>

      {/* Group membership — multi-membership is allowed */}
      {nodeGroups.length > 0 ? (
        <div className="card" style={{background:'#FFF6FA', border:'2px dashed var(--line)'}}>
          <div style={{fontSize:12, fontWeight:800, color:'var(--ink-soft)', marginBottom:8}}>
            🫧 Groups ({nodeGroups.length})
          </div>
          {nodeGroups.map(ng => (
            <div key={ng.id} style={{display:'flex', alignItems:'center', gap:8, marginBottom:6, background:'#fff', padding:'6px 10px', borderRadius:10}}>
              <span style={{width:14, height:14, borderRadius:'50%', background:ng.color, display:'inline-block', border:'2px solid #fff', boxShadow:'0 1px 0 rgba(120,76,110,.15)', flexShrink:0}}/>
              <span style={{flex:1, fontWeight:900, fontSize:12, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>{ng.name || '(Untitled)'}</span>
              <button className="btn sm ghost" title="Edit"
                      style={{padding:'2px 8px', fontSize:12}}
                      onClick={()=>setSelection && setSelection({type:'group', id:ng.id})}>✎</button>
              <button className="btn sm ghost" title="Remove from this group"
                      style={{padding:'2px 8px', fontSize:12, color:'var(--coral)'}}
                      onClick={()=>{
                        const nextIds = (ng.nodeIds||[]).filter(x => x !== node.id);
                        if (nextIds.length === 0) { deleteGroup && deleteGroup(ng.id); }
                        else { updateGroup && updateGroup(ng.id, {nodeIds: nextIds}); }
                      }}>×</button>
            </div>
          ))}
          <button className="btn sm block" style={{marginTop:8}}
                  onClick={()=>{
                    const gid = createGroupFromNode && createGroupFromNode(node.id);
                    if (gid) { setComposingGroupId && setComposingGroupId(gid); }
                  }}>
            ＋ Add to another group
          </button>
        </div>
      ) : (
        <button className="btn" style={{background:'var(--bg-lav)', color:'var(--ink)'}}
                onClick={()=>{
                  const gid = createGroupFromNode && createGroupFromNode(node.id);
                  if (gid) { setComposingGroupId && setComposingGroupId(gid); }
                }}>
          🫧 Add to a group
        </button>
      )}
    </>
  );
}

function GroupInspector({group, nodes, updateGroup, deleteGroup, setComposingGroupId, setSelection}){
  const members = (group.nodeIds || [])
    .map(nid => nodes.find(n => n.id === nid))
    .filter(Boolean);
  const presets = ['#FFB3C7','#FFD3A8','#FFE8A3','#C7EFC0','#B5D9F2','#C9BEF5','#E8BCE8'];

  return (
    <>
      <h3>🫧 Edit group</h3>
      <div className="card">
        <div className="field">
          <label>Group name</label>
          <input type="text" value={group.name||''} maxLength={40}
                 onChange={e=>updateGroup(group.id, {name:e.target.value})}
                 placeholder="e.g. Team A / Main Cast"/>
        </div>
        <label className="pop-check" style={{borderTop:'none', padding:0}}>
          <input type="checkbox" checked={group.showName !== false}
                 onChange={e=>updateGroup(group.id, {showName:e.target.checked})}/>
          Show name on canvas
        </label>
      </div>

      <div className="card mint">
        <h3 style={{marginTop:0}}>Color</h3>
        <div className="swatches">
          {presets.map(c=>(
            <button key={c} style={{background:c}}
                    className={group.color===c?'on':''}
                    onClick={()=>updateGroup(group.id,{color:c})}/>
          ))}
          <label className={'rainbow-swatch' + (presets.indexOf(group.color)<0 ? ' on' : '')}
                 title="Pick a custom color"
                 style={{
                   width:30, height:30, borderRadius:'50%',
                   background:'conic-gradient(from 0deg, #f56a92, #ffd97a, #7dd8b4, #8ccbf0, #b7a0ee, #f56a92)',
                   border:'3px solid #fff', boxShadow:'0 2px 0 rgba(120,76,110,.15)',
                   cursor:'pointer', position:'relative', display:'inline-block', flexShrink:0,
                 }}>
            <input type="color" value={group.color || '#FFB3C7'}
                   onChange={e=>updateGroup(group.id,{color:e.target.value},{skipHistory:true})}
                   onBlur={e=>updateGroup(group.id,{color:e.target.value})}
                   style={{position:'absolute', inset:0, width:'100%', height:'100%', opacity:0, cursor:'pointer', border:'none', padding:0}}/>
          </label>
        </div>
      </div>

      <div className="card lav">
        <h3 style={{marginTop:0}}>Members ({members.length})</h3>
        <div style={{display:'flex', flexDirection:'column', gap:6}}>
          {members.map(n => (
            <div key={n.id} style={{display:'flex', alignItems:'center', gap:8, background:'#fff', padding:'6px 10px', borderRadius:10}}>
              <span style={{width:22, height:22, borderRadius:'50%', background:n.color, display:'grid', placeItems:'center', fontSize:14}}>
                {n.emoji || (n.name||'?').charAt(0).toUpperCase()}
              </span>
              <span style={{flex:1, fontSize:13, fontWeight:700, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>{n.name || '(Unnamed)'}</span>
              <button className="btn sm ghost" title="Remove from group"
                      onClick={()=>{
                        const next = (group.nodeIds||[]).filter(x => x !== n.id);
                        if (next.length === 0) { deleteGroup(group.id); return; }
                        updateGroup(group.id, {nodeIds: next});
                      }}>×</button>
            </div>
          ))}
        </div>
        <button className="btn sm block" style={{marginTop:10}}
                onClick={()=>{ setComposingGroupId && setComposingGroupId(group.id); }}>
          ＋ Add / edit members
        </button>
      </div>

      <button className="btn" style={{background:'#FFE0E0', color:'#C94A4A'}}
              onClick={()=>deleteGroup(group.id)}>🗑 Delete group</button>
    </>
  );
}

function EdgeInspector({edge, nodes, updateEdge, deleteEdge}){
  const from = nodes.find(n=>n.id===edge.from);
  const to = nodes.find(n=>n.id===edge.to);
  const rel = RELATIONS.find(r=>r.id===edge.relation) || RELATIONS[0];

  return (
    <>
      <h3>Edit relationship</h3>
      <div className="card lav">
        <div style={{fontSize:13, fontWeight:800, marginBottom:8}}>
          <span style={{color:'var(--ink-soft)'}}>from</span> {from?.name||'?'}
          <span style={{margin:'0 6px'}}>→</span>
          <span style={{color:'var(--ink-soft)'}}>to</span> {to?.name||'?'}
          {' '}
          <button className="btn sm ghost" title="Swap direction"
                  onClick={()=>updateEdge(edge.id,{from:edge.to,to:edge.from})}>⇄</button>
        </div>

        <div className="field">
          <label>Relationship type</label>
          <div className="seg">
            {RELATIONS.map(r=>(
              <button key={r.id} className={edge.relation===r.id?'on':''}
                      onClick={()=>updateEdge(edge.id,{relation:r.id, color:r.color, label:r.label})}>
                {r.stamp} {r.label}
              </button>
            ))}
          </div>
        </div>

        <div className="field">
          <label>Label (free text)</label>
          <input type="text" value={edge.label ?? rel.label} maxLength={40}
                 onChange={e=>updateEdge(edge.id,{label:e.target.value})}/>
        </div>

        <div className="field">
          <label>Stamp</label>
          <div className="stamp-row">
            <button className={!edge.stamp?'on':''}
                    onClick={()=>updateEdge(edge.id,{stamp:''})}>None</button>
            {STAMPS.map(s=>(
              <button key={s} className={edge.stamp===s?'on':''}
                      onClick={()=>updateEdge(edge.id,{stamp:s})}>{s}</button>
            ))}
          </div>
        </div>
      </div>

      <div className="card sky">
        <h3 style={{marginTop:0}}>Arrow style</h3>
        <div className="seg">
          {ARROW_STYLES.map(s=>(
            <button key={s.id} className={edge.style===s.id?'on':''}
                    onClick={()=>updateEdge(edge.id,{style:s.id})}>{s.label}</button>
          ))}
        </div>
        <div className="field" style={{marginTop:10}}>
          <label>Line color</label>
          <div className="swatches">
            {(() => {
              const presets = ['#F56A92','#F77F6E','#FFB86B','#7DD8B4','#8CCBF0','#B7A0EE','#7a6a7a','#3a2c3a'];
              return (
                <>
                  {presets.map(c=>(
                    <button key={c} style={{background:c}}
                            className={edge.color===c?'on':''}
                            onClick={()=>updateEdge(edge.id,{color:c})}/>
                  ))}
                  <label className={'rainbow-swatch' + (presets.indexOf(edge.color)<0 ? ' on' : '')}
                         title="Pick a custom color"
                         style={{
                           width:30, height:30, borderRadius:'50%',
                           background:'conic-gradient(from 0deg, #f56a92, #ffd97a, #7dd8b4, #8ccbf0, #b7a0ee, #f56a92)',
                           border:'3px solid #fff', boxShadow:'0 2px 0 rgba(120,76,110,.15)',
                           cursor:'pointer', position:'relative', display:'inline-block', flexShrink:0,
                         }}>
                    <input type="color" value={edge.color || '#F56A92'}
                           onChange={e=>updateEdge(edge.id,{color:e.target.value},{skipHistory:true})}
                           onBlur={e=>updateEdge(edge.id,{color:e.target.value})}
                           style={{position:'absolute', inset:0, width:'100%', height:'100%', opacity:0, cursor:'pointer', border:'none', padding:0}}/>
                  </label>
                </>
              );
            })()}
          </div>
        </div>
        {edge.customOffset !== undefined && edge.customOffset !== 0 && (
          <button className="btn sm" style={{marginTop:8}}
                  onClick={()=>updateEdge(edge.id,{customOffset:undefined})}>↺ Reset curve</button>
        )}
      </div>

      <button className="btn" style={{background:'#FFE0E0', color:'#C94A4A'}}
              onClick={()=>deleteEdge(edge.id)}>🗑 Delete relationship</button>

      <div style={{fontSize:11, color:'var(--ink-soft)', textAlign:'center', marginTop:4, lineHeight:1.6}}>
        💡 <b>Shift+click</b> another arrow to swap their stacking order
      </div>
    </>
  );
}

function WritingInspector({writing, nodes, edges, updateWriting, deleteWriting}){
  const presets = ['#F56A92','#F77F6E','#FFB86B','#FFD97A','#7DD8B4','#8CCBF0','#B7A0EE','#3a2c3a'];

  const fontSize = writing.fontSize || 28;
  const rotation = writing.rotation || 0;
  const links = writing.links || [];

  const linkLabel = (link) => {
    if (link.type === 'node') {
      const n = nodes.find(x => x.id === link.id);
      return n ? `Node "${n.name || '?'}"` : '(deleted node)';
    }
    if (link.type === 'edge') {
      const ed = edges.find(x => x.id === link.id);
      return ed ? `Arrow "${ed.label || ed.relation || ''}"` : '(deleted arrow)';
    }
    return '?';
  };

  const removeLinkAt = (idx) => {
    const next = links.filter((_, i) => i !== idx);
    updateWriting(writing.id, { links: next });
  };
  const resetCurveAt = (idx) => {
    const next = links.map((l, i) => i === idx ? { ...l, lineCurve: 0 } : l);
    updateWriting(writing.id, { links: next });
  };
  const detachAll = () => updateWriting(writing.id, { links: [] });

  return (
    <>
      <h3>📝 Edit writing</h3>
      <div className="card">
        <div className="field">
          <label>Text</label>
          <textarea value={writing.text || ''} maxLength={200} rows={3}
                    onChange={e=>updateWriting(writing.id, {text: e.target.value})}
                    placeholder="Write anything"
                    style={{border:'2px solid #fff', background:'#fff', borderRadius:12, padding:'8px 10px', fontSize:14, fontFamily:'inherit', outline:'none', color:'inherit', resize:'vertical', minHeight:60}}/>
        </div>
        <div className="field">
          <label>Size ({fontSize}px)</label>
          <input type="range" className="pastel" min={12} max={96} step={1} value={fontSize}
                 onChange={e=>updateWriting(writing.id, {fontSize: parseInt(e.target.value, 10)}, {skipHistory:true})}
                 onMouseUp={e=>updateWriting(writing.id, {fontSize: parseInt(e.target.value, 10)})}
                 onTouchEnd={e=>updateWriting(writing.id, {fontSize: parseInt(e.target.value, 10)})}/>
          <div className="seg">
            {[16, 24, 32, 48, 64].map(v => (
              <button key={v} className={fontSize===v?'on':''}
                      onClick={()=>updateWriting(writing.id, {fontSize: v})}>{v}</button>
            ))}
          </div>
        </div>
        <div className="field">
          <label>Rotation ({rotation}°)</label>
          <input type="range" className="pastel" min={-180} max={180} step={1} value={rotation}
                 onChange={e=>updateWriting(writing.id, {rotation: parseInt(e.target.value, 10)}, {skipHistory:true})}
                 onMouseUp={e=>updateWriting(writing.id, {rotation: parseInt(e.target.value, 10)})}
                 onTouchEnd={e=>updateWriting(writing.id, {rotation: parseInt(e.target.value, 10)})}/>
          {rotation !== 0 && (
            <button className="btn sm" style={{alignSelf:'flex-start'}}
                    onClick={()=>updateWriting(writing.id, {rotation: 0})}>↺ Reset rotation</button>
          )}
        </div>
      </div>

      <div className="card mint">
        <h3 style={{marginTop:0}}>Text color (line color follows)</h3>
        <div className="swatches">
          {presets.map(c => (
            <button key={c} style={{background:c}}
                    className={writing.color===c?'on':''}
                    onClick={()=>updateWriting(writing.id, {color: c})}/>
          ))}
          <label className={'rainbow-swatch' + (presets.indexOf(writing.color)<0 ? ' on' : '')}
                 title="Pick a custom color"
                 style={{
                   width:30, height:30, borderRadius:'50%',
                   background:'conic-gradient(from 0deg, #f56a92, #ffd97a, #7dd8b4, #8ccbf0, #b7a0ee, #f56a92)',
                   border:'3px solid #fff', boxShadow:'0 2px 0 rgba(120,76,110,.15)',
                   cursor:'pointer', position:'relative', display:'inline-block', flexShrink:0,
                 }}>
            <input type="color" value={writing.color || '#F56A92'}
                   onChange={e=>updateWriting(writing.id, {color: e.target.value}, {skipHistory:true})}
                   onBlur={e=>updateWriting(writing.id, {color: e.target.value})}
                   style={{position:'absolute', inset:0, width:'100%', height:'100%', opacity:0, cursor:'pointer', border:'none', padding:0}}/>
          </label>
        </div>
      </div>

      <div className="card sky">
        <h3 style={{marginTop:0}}>Links</h3>
        {links.length === 0 ? (
          <div style={{fontSize:12, color:'var(--ink-soft)'}}>No links</div>
        ) : (
          <div style={{display:'flex', flexDirection:'column', gap:6}}>
            {links.map((link, idx) => {
              const bent = (link.lineCurve || 0) !== 0;
              return (
                <div key={`${link.type}-${link.id}-${idx}`}
                     style={{display:'flex', alignItems:'center', gap:6, background:'#fff', padding:'6px 10px', borderRadius:10}}>
                  <span style={{flex:1, fontSize:12, fontWeight:800, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>
                    🔗 {linkLabel(link)}
                  </span>
                  {bent && (
                    <button className="btn sm ghost" title="Reset bend on this link"
                            style={{padding:'2px 6px', fontSize:12, color:'var(--ink-soft)'}}
                            onClick={()=>resetCurveAt(idx)}>↺</button>
                  )}
                  <button className="btn sm ghost" title="Remove this link"
                          style={{padding:'2px 8px', fontSize:12, color:'var(--coral)'}}
                          onClick={()=>removeLinkAt(idx)}>×</button>
                </div>
              );
            })}
          </div>
        )}
        {links.length > 0 && (
          <button className="btn sm" style={{marginTop:10}}
                  onClick={detachAll}>✕ Detach all lines</button>
        )}
      </div>

      <button className="btn" style={{background:'#FFE0E0', color:'#C94A4A'}}
              onClick={()=>deleteWriting(writing.id)}>🗑 Delete writing</button>
    </>
  );
}

window.Inspector = Inspector;
