(function(){
const {useState,useRef}=React;
const {Icon,Button,IconButton,Switch,Mark,Dialog,KeyValues}=ExtensionUI;
const validURL=s=>{try{return ['http:','https:'].includes(new URL(s).protocol);}catch{return false;}};
const Field=({label,children,note})=><label className="ext-field"><span>{label}</span>{children}{note&&<small>{note}</small>}</label>;
function MCPForm({data,names=[],onClose,onSave,embedded=false}){
 const [form,setForm]=useState(data||{name:'',protocol:'stdio',command:'',args:[],env:[],url:'',tokenEnv:'',headers:[]}),[error,setError]=useState('');
 const patch=(key,value)=>setForm(f=>({...f,[key]:value}));
 function submit(e){e.preventDefault();const f={...form,name:form.name.trim()};if(!f.name)return setError('请填写工具名称。');if(names.includes(f.name))return setError('已有同名工具，请使用其他名称。');if(f.protocol==='stdio'&&!f.command.trim())return setError('请填写启动命令。');if(f.protocol==='http'&&!validURL(f.url))return setError('请填写有效的 HTTP 或 HTTPS URL。');if(f.tokenEnv&&!/^[A-Za-z_][A-Za-z0-9_]*$/.test(f.tokenEnv))return setError('令牌环境变量名称格式不正确。');for(const key of [f.protocol==='stdio'?'env':'headers']){const rows=(f[key]||[]).filter(x=>x.key||x.value);if(rows.some(r=>!r.key.trim()))return setError('请为每一项填写名称。');if(new Set(rows.map(r=>r.key.trim().toLowerCase())).size!==rows.length)return setError('配置名称不可重复。');if(key==='env'&&rows.some(r=>!/^[A-Za-z_][A-Za-z0-9_]*$/.test(r.key)))return setError('环境变量名称格式不正确。');f[key]=rows;}onSave({...f,id:f.id||'mcp-'+Date.now()});}
 return <Dialog title={embedded?'配置插件 MCP':data?'编辑 MCP 工具':'添加 MCP 工具'} description={embedded?'由插件管理，保存后会同步到工具列表。':'选择连接协议，填写 MCP 服务配置。'} onClose={onClose} footer={<><Button onClick={onClose}>取消</Button><Button primary type="submit" form="mcp-form">保存配置</Button></>}><form id="mcp-form" onSubmit={submit}><Field label="工具名称"><input data-autofocus value={form.name} placeholder="例如：设计资料库" onChange={e=>patch('name',e.target.value)}/></Field><div className="ext-protocols" aria-label="连接协议">{[['stdio','terminal','stdio'],['http','globe','Streamable HTTP']].map(([v,icon,label])=><button type="button" key={v} aria-pressed={form.protocol===v} className={form.protocol===v?'active':''} onClick={()=>patch('protocol',v)}><Icon name={icon} size={16}/>{label}</button>)}</div>{form.protocol==='stdio'?<><Field label="启动命令"><input value={form.command||''} placeholder="npx" onChange={e=>patch('command',e.target.value)}/></Field><Field label="参数" note="每行一个参数，参数中的空格会保留。"><textarea value={(form.args||[]).join('\n')} placeholder={'-y\n@modelcontextprotocol/server-filesystem\n/Users/me/Documents'} onChange={e=>patch('args',e.target.value.split('\n'))}/></Field><KeyValues label="环境变量" rows={form.env||[]} onChange={v=>patch('env',v)} keyPlaceholder="API_KEY" valuePlaceholder="仅填演示值"/></>:<><Field label="服务 URL"><input value={form.url||''} placeholder="https://example.com/mcp" onChange={e=>patch('url',e.target.value)}/></Field><Field label="令牌环境变量" note="选填。填写变量名，运行时从环境中读取令牌。"><input value={form.tokenEnv||''} placeholder="SERVICE_API_TOKEN" onChange={e=>patch('tokenEnv',e.target.value)}/></Field><KeyValues label="Header" rows={form.headers||[]} onChange={v=>patch('headers',v)} keyPlaceholder="X-Workspace"/></>}<div className="ext-form-note"><Icon name="info" size={14}/>原型仅保存配置示例，不会启动命令或连接服务。请勿填写真实密钥。</div>{error&&<p role="alert" className="ext-form-error">{error}</p>}</form></Dialog>;
}
function UploadPlugin({onClose,onSave}){
 const [file,setFile]=useState(null),[name,setName]=useState(''),[format,setFormat]=useState('平台统一格式'),[auth,setAuth]=useState('none'),[error,setError]=useState(''),[drag,setDrag]=useState(false);const ref=useRef();
 function choose(f){if(!f)return;if(!/\.(zip|tar\.gz|json)$/i.test(f.name))return setError('请选择 .zip、.tar.gz 或 .json 文件。');setError('');setFile(f);setName(f.name.replace(/\.(zip|tar\.gz|json)$/i,''));}
 function save(e){e.preventDefault();if(!file||!name.trim())return setError('请先选择插件包并填写名称。');onSave({id:'upload-'+Date.now(),name:name.trim(),description:'从本地上传的插件包，可在详情中完成配置。',desc:'从本地上传的插件包',icon:'package',color:'slate',version:'1.0.0',latest:'1.0.0',source:'upload',marketKey:null,fileName:file.name,format,auth,connected:false,installed:true,enabled:true,harnesses:ExtensionData.allHarnesses,mcp:[],category:'效率'});}
 return <Dialog title="上传插件包" description="统一管理不同 Harness 的插件，安装后按需完成连接。" onClose={onClose} footer={<><Button onClick={onClose}>取消</Button><Button primary type="submit" form="upload-plugin">安装插件</Button></>}><form id="upload-plugin" onSubmit={save}><input ref={ref} type="file" accept=".zip,.gz,.json" hidden onChange={e=>choose(e.target.files[0])}/><button type="button" className={'ext-upload-area '+(file?'loaded ':'')+(drag?'drag':'')} onClick={()=>ref.current.click()} onDragOver={e=>{e.preventDefault();setDrag(true);}} onDragLeave={()=>setDrag(false)} onDrop={e=>{e.preventDefault();setDrag(false);choose(e.dataTransfer.files[0]);}}><Icon name={file?'package':'upload'} size={25}/><strong>{file?file.name:'点击选择或拖拽插件包到这里'}</strong><small>{file?'点击可重新选择':'ZIP、TAR.GZ 或 JSON'}</small></button><Field label="插件名称"><input value={name} onChange={e=>setName(e.target.value)} placeholder="插件顶层名称"/></Field><Field label="包格式"><select value={format} onChange={e=>setFormat(e.target.value)}>{['平台统一格式','Codex','Claude Code','pi'].map(s=><option key={s}>{s}</option>)}</select></Field><Field label="安装后连接"><select value={auth} onChange={e=>setAuth(e.target.value)}><option value="none">无需鉴权 · 安装后直接使用</option><option value="oauth">账号授权 · 提供连接引导</option><option value="token">令牌配置 · 提供连接引导</option></select></Field><div className="ext-form-note"><Icon name="info" size={14}/>演示安装流程：只记录文件名与表单信息，不上传、解压或转换插件包。</div>{error&&<p className="ext-form-error" role="alert">{error}</p>}</form></Dialog>;
}
function MarketSettings({kind,markets,onChange,onClose}){
 const [name,setName]=useState(''),[url,setURL]=useState(''),[error,setError]=useState('');
 function add(e){e.preventDefault();if(!name.trim()||!validURL(url))return setError('请填写市场名称和有效的 HTTP / HTTPS 地址。');if(markets.some(m=>m.url.replace(/\/$/,'')===url.trim().replace(/\/$/,'')))return setError('这个市场已经添加。');onChange([...markets,{id:'market-'+Date.now(),kind,name:name.trim(),url:url.trim(),enabled:true,builtin:false}]);setName('');setURL('');setError('');}
 return <Dialog title={kind==='plugins'?'插件市场管理':'技能市场管理'} description="选择显示在列表中的市场来源。" onClose={onClose} footer={<Button primary onClick={onClose}>完成</Button>}>
 {markets.filter(m=>m.kind===kind).map(m=><div className="ext-market-row" key={m.id}><Icon name="globe"/><div><h3>{m.name}{m.builtin&&<span className="ext-badge">默认</span>}</h3><p>{m.url}</p>{!m.builtin&&<p>已添加示例来源 · 尚未连接服务</p>}</div><Switch label={'显示 '+m.name} checked={m.enabled} onChange={v=>onChange(markets.map(x=>x.id===m.id?{...x,enabled:v}:x))}/>{!m.builtin&&<IconButton name="trash" label={'移除 '+m.name} onClick={()=>onChange(markets.filter(x=>x.id!==m.id))}/>}</div>)}
 {kind==='plugins'&&<form className="ext-market-form" onSubmit={add}><h3 className="ext-form-section"><Icon name="plus" size={14}/>连接第三方市场</h3><Field label="市场名称"><input placeholder="例如：团队插件市场" value={name} onChange={e=>setName(e.target.value)}/></Field><Field label="市场地址"><input placeholder="https://market.example.com" value={url} onChange={e=>setURL(e.target.value)}/></Field>{error&&<p role="alert" className="ext-form-error">{error}</p>}<Button type="submit"><Icon name="link" size={14}/>添加市场</Button></form>}<p className="ext-source-note">原型中的市场与插件均为示例，连接操作不会请求外部服务。</p></Dialog>;
}
function SkillFolders({state,onSave,onClose}){
 const [dirs,setDirs]=useState(state.directories),[auto,setAuto]=useState(state.autoScan),[error,setError]=useState('');
 function save(){const paths=dirs.map(d=>d.path.trim());if(paths.some(p=>!p)||new Set(paths).size!==paths.length)return setError('目录不能为空或重复。');onSave(dirs.map(d=>({...d,path:d.path.trim()})),auto);}
 return <Dialog title="技能发现设置" description="技能以顶层文件夹名称展示，从指定目录发现新增内容。" onClose={onClose} footer={<><Button onClick={onClose}>取消</Button><Button primary onClick={save}>保存并刷新</Button></>}><div className="ext-setting-row"><div><strong>自动发现技能</strong><p>返回工作台时，检查启用目录中的新增技能。</p></div><Switch label="自动发现技能" checked={auto} onChange={setAuto}/></div><h3 className="ext-form-section">扫描目录</h3>{dirs.map((d,i)=><div className="ext-path-row" key={d.id}><Switch label={'扫描目录 '+(i+1)} checked={d.enabled} onChange={v=>setDirs(ds=>ds.map(x=>x.id===d.id?{...x,enabled:v}:x))}/><input className="ext-path-input" aria-label={'目录路径 '+(i+1)} value={d.path} onChange={e=>setDirs(ds=>ds.map(x=>x.id===d.id?{...x,path:e.target.value}:x))}/><IconButton name="close" label={'删除目录 '+(i+1)} onClick={()=>setDirs(ds=>ds.filter(x=>x.id!==d.id))}/></div>)}<Button small onClick={()=>setDirs(ds=>[...ds,{id:'dir-'+Date.now(),path:'',enabled:true}])}><Icon name="plus" size={13}/>添加目录</Button>{error&&<p role="alert" className="ext-form-error">{error}</p>}<p className="ext-file-note">此交互演示使用示例文件夹，不访问设备文件系统。</p></Dialog>;
}
function UpdateSettings({state,onChange,onCheck,onClose}){return <Dialog title="插件更新设置" description="市场插件通过来源与唯一标识匹配更新。" onClose={onClose} footer={<Button primary onClick={onClose}>完成</Button>}>{[['checkUpdates','自动检查更新','打开插件页面时，检查市场中的新版本。'],['updateNotifications','更新消息提醒','在插件页显示更新消息及提醒标记。']].map(([key,title,desc])=><div className="ext-setting-row" key={key}><div><strong>{title}</strong><p>{desc}</p></div><Switch label={title} checked={state[key]} onChange={v=>onChange({[key]:v})}/></div>)}<div className="ext-setting-row"><div><strong>检查市场更新</strong><p>{state.lastChecked?'上次检查：'+new Date(state.lastChecked).toLocaleString('zh-CN'):'尚未手动检查'}</p></div><Button small onClick={onCheck}>立即检查</Button></div><p className="ext-source-note">本地上传的插件不自动匹配市场更新。当前使用预置版本数据演示。</p></Dialog>;}
function PluginDetails({plugin:p,markets,initialTab='overview',onClose,onPatch,onInstall,onUpdate,onDelete,onMCP}){
 const [tab,setTab]=useState(initialTab),[authStep,setAuthStep]=useState(false),[token,setToken]=useState(''),[error,setError]=useState('');
 return <Dialog title="插件详情" onClose={onClose} footer={<><span className="ext-footer-note">{p.installed?'已安装 · v'+p.version:'来自默认插件市场'}</span>{p.installed?<><Button subtle onClick={()=>onDelete(p)}>卸载插件</Button>{p.version!==p.latest&&p.marketKey&&<Button primary onClick={()=>onUpdate(p)}>更新至 {p.latest}</Button>}</>:<Button primary onClick={()=>onInstall(p)}>安装插件</Button>}</>}><div className="ext-detail-intro"><Mark icon={p.icon} color={p.color} large/><div><h3>{p.name}</h3><p>{p.category} · v{p.version}</p></div></div><div className="ext-dialog-tabs">{[['overview','概览'],['config','配置与连接']].map(([key,label])=><button key={key} className={tab===key?'active':''} onClick={()=>setTab(key)}>{label}</button>)}</div>{tab==='overview'?<><p className="ext-detail-description">{p.description}</p><dl className="ext-detail-meta"><dt>来源</dt><dd>{p.source==='upload'?'本地上传 · '+p.fileName:markets.find(m=>m.id===p.source)?.name||'插件市场'}</dd><dt>唯一标识</dt><dd><code>{p.marketKey||'本地插件，无市场标识'}</code></dd><dt>支持 Harness</dt><dd className="ext-compat">{p.harnesses.map(h=><span className="ext-badge" key={h}>{h}</span>)}</dd><dt>包格式</dt><dd>{p.format||'平台统一格式'}</dd><dt>鉴权方式</dt><dd>{p.auth==='none'?'无需鉴权':p.auth==='oauth'?'账号授权':'令牌环境变量'}</dd></dl>{p.releaseNotes&&<><h3 className="ext-form-section">v{p.latest} 更新内容</h3><ul className="ext-change-list">{p.releaseNotes.map(n=><li key={n}>{n}</li>)}</ul></>}</>:<>{p.installed?<><div className="ext-setting-row"><div><strong>启用插件</strong><p>启用后，可在对话中选择使用。</p></div><Switch label={'启用 '+p.name} checked={p.enabled} onChange={v=>onPatch({enabled:v})}/></div><div className="ext-setting-row"><div><strong>{p.auth==='none'?'无需鉴权':p.connected?'账号已连接':'完成安装后的连接'}</strong><p>{p.auth==='none'?'安装完成后即可使用。':p.connected?'授权状态为原型演示。':'按插件指引配置账号，再在对话中使用。'}</p></div>{p.auth!=='none'&&<Button small onClick={()=>p.connected?onPatch({connected:false}):setAuthStep(true)}>{p.connected?'断开连接':'连接账号'}</Button>}</div>{authStep&&!p.connected&&<div className="ext-plugin-config"><ol className="ext-steps"><li>确认需要连接的 {p.name} 工作账号。</li><li>{p.auth==='token'?'填写保存令牌的环境变量名称。':'在服务授权页面确认访问权限。'}</li><li>返回工作台，完成连接并查看可用配置。</li></ol>{p.auth==='token'&&<Field label="令牌环境变量"><input placeholder="SERVICE_API_TOKEN" value={token} onChange={e=>setToken(e.target.value)}/></Field>}{error&&<p className="ext-form-error">{error}</p>}<Button primary small onClick={()=>{if(p.auth==='token'&&!/^[A-Za-z_][A-Za-z0-9_]*$/.test(token))return setError('请填写有效的环境变量名称。');onPatch({connected:true,tokenEnv:token});setAuthStep(false);}}>模拟完成连接</Button><p className="ext-file-note">演示授权引导，不会打开外部服务或使用真实凭证。</p></div>}<h3 className="ext-form-section"><Icon name="tools" size={14}/>插件中的 MCP</h3>{p.mcp.length?p.mcp.map(m=><div className="ext-plugin-config" key={m.id}><strong>{m.name}</strong><small>{m.protocol==='stdio'?'stdio':'Streamable HTTP'} · 配置随插件统一管理</small><Button small onClick={()=>onMCP(m)}>编辑配置</Button></div>):<p className="ext-source-note">此插件未提供 MCP 配置。</p>}</>:<p className="ext-source-note">安装插件后可管理启用状态、账号连接和 MCP 配置。</p>}</>}</Dialog>;
}
window.ExtensionForms={MCPForm,UploadPlugin,MarketSettings,SkillFolders,UpdateSettings,PluginDetails};
})();
