const sleep=ms=>new Promise(r=>setTimeout(r,ms));
const visible=e=>e&&e.getBoundingClientRect().width>0&&e.getBoundingClientRect().height>0;
let activeJob=null,running=false,stage='idle',baselineTexts=new Set(),resultSent=false;

function panel(){
  let p=document.querySelector('#product-workbench-agent');
  if(p&&p.querySelector('.pwa-status')&&p.querySelector('.pwa-run'))return p;
  if(p)p.remove();
  p=document.createElement('div');p.id='product-workbench-agent';
  p.innerHTML=`<div class="pwa-title">产品定义自动桥接 <span>v1.7.2</span></div><div class="pwa-status">正在连接工作台</div><button class="pwa-run">继续自动执行</button><button class="pwa-close" title="收起">×</button>`;
  const s=document.createElement('style');s.textContent=`#product-workbench-agent{position:fixed;right:16px;bottom:18px;z-index:2147483647;width:310px;padding:14px;border:1px solid #cfd7e6;border-radius:14px;background:#fff;color:#172033;box-shadow:0 16px 50px rgba(0,0,0,.2);font:14px/1.5 system-ui,"Microsoft YaHei",sans-serif}.pwa-title{font-weight:800;margin-bottom:7px}.pwa-title span{float:right;color:#667085;font-size:11px}.pwa-status{color:#475467;white-space:pre-wrap;margin-bottom:10px}.pwa-run{width:100%;border:0;border-radius:8px;padding:8px;background:#3157d5;color:#fff;font-weight:700;cursor:pointer}.pwa-run:disabled{opacity:.45}.pwa-close{position:absolute;right:7px;top:5px;border:0;background:transparent;font-size:18px;color:#98a2b3;cursor:pointer}`;
  document.documentElement.appendChild(s);document.documentElement.appendChild(p);
  p.querySelector('.pwa-run').onclick=()=>activeJob&&resume(activeJob);
  p.querySelector('.pwa-close').onclick=()=>p.style.display='none';return p;
}
function status(text,kind='normal'){
  const p=panel(),e=p.querySelector('.pwa-status'),b=p.querySelector('.pwa-run');if(!e||!b)return;
  e.textContent=text;e.style.color=kind==='error'?'#b42318':kind==='ok'?'#087a55':'#475467';
  b.textContent=stage==='sent'||stage==='waiting'?'继续检测回答':stage==='complete'?'已完成':'继续自动执行';b.disabled=running||stage==='complete';p.style.display='block';
  chrome.runtime.sendMessage({type:'JOB_PROGRESS',message:text});
}
async function waitFor(fn,timeout=45000,interval=400){const end=Date.now()+timeout;while(Date.now()<end){const v=fn();if(v)return v;await sleep(interval)}throw new Error('绛夊緟缃戦〉鎺т欢瓒呮椂锛岃纭宸茬粡鐧诲綍涓斿璇濊緭鍏ユ鍙')}
function dataUrlFile(dataUrl,name='product-image.png'){const [head,b64]=dataUrl.split(','),mime=(head.match(/data:([^;]+)/)||[])[1]||'image/png',bytes=Uint8Array.from(atob(b64),c=>c.charCodeAt(0));return new File([bytes],name,{type:mime})}
async function jobImageFile(image){if(String(image||'').startsWith('data:'))return dataUrlFile(image);if(/^https?:\/\//i.test(String(image||''))){status('正在由扩展下载网络图片，不需要手工保存');const r=await chrome.runtime.sendMessage({type:'FETCH_IMAGE_DATA',url:image});if(!r?.ok)throw new Error('网络图片下载失败：'+(r?.error||'图片站点拒绝访问'));return dataUrlFile(r.data,'network-product-image.png')}throw new Error('产品图片地址无效')}
function buttonByText(re){return [...document.querySelectorAll('button,[role="button"],[role="menuitem"]')].find(e=>visible(e)&&re.test(((e.getAttribute('aria-label')||'')+' '+(e.getAttribute('data-testid')||'')+' '+(e.textContent||'')).trim()))}
function editor(platform){
  const preferred=platform==='Gemini'?[document.querySelector('rich-textarea .ql-editor[contenteditable="true"]'),document.querySelector('rich-textarea [contenteditable="true"]'),document.querySelector('.ql-editor[contenteditable="true"]')]:[document.querySelector('#prompt-textarea'),document.querySelector('[data-testid="composer-input"]')];
  return [...preferred,...document.querySelectorAll('textarea,[contenteditable="true"]')].find(visible);
}
function fileInput(){return [...document.querySelectorAll('input[type="file"]')].find(x=>!x.disabled&&(!x.accept||/image|\*/i.test(x.accept)))}
async function ensureFileInput(platform){
  let input=fileInput();if(input)return input;
  const re=platform==='Gemini'?/upload|attach|add file|涓婁紶|闄勪欢|娣诲姞鏂囦欢|娣诲姞鍥剧墖/i:/attach|upload|add photos|add files|闄勪欢|涓婁紶|娣诲姞鏂囦欢|娣诲姞鐓х墖|娣诲姞/i;
  const attach=buttonByText(re);if(attach){attach.click();await sleep(700);input=fileInput();if(input)return input;const menu=buttonByText(/upload file|upload from computer|涓婁紶鏂囦欢|浠庤绠楁満涓婁紶/i);if(menu){menu.click();await sleep(600);input=fileInput()}}
  return input||null;
}
const editorValue=el=>(el.tagName==='TEXTAREA'||el.tagName==='INPUT'?el.value:el.innerText||el.textContent||'').trim();
async function setEditor(el,text){
  el.focus();if(el.tagName==='TEXTAREA'||el.tagName==='INPUT'){const proto=el.tagName==='TEXTAREA'?HTMLTextAreaElement.prototype:HTMLInputElement.prototype,setter=Object.getOwnPropertyDescriptor(proto,'value')?.set;setter?setter.call(el,text):el.value=text;el.dispatchEvent(new InputEvent('input',{bubbles:true,inputType:'insertText',data:text}));el.dispatchEvent(new Event('change',{bubbles:true}))}
  else{const sel=getSelection(),range=document.createRange();range.selectNodeContents(el);sel.removeAllRanges();sel.addRange(range);document.execCommand('insertText',false,text);await sleep(250);if(!editorValue(el).includes(text.slice(0,20))){const dt=new DataTransfer();dt.setData('text/plain',text);el.dispatchEvent(new ClipboardEvent('paste',{bubbles:true,cancelable:true,clipboardData:dt}));await sleep(350)}if(!editorValue(el).includes(text.slice(0,20))){el.innerHTML='';text.split('\n').forEach(line=>{const p=document.createElement('p');p.textContent=line||' ';el.appendChild(p)});el.dispatchEvent(new InputEvent('input',{bubbles:true,inputType:'insertText',data:text}));el.dispatchEvent(new Event('change',{bubbles:true}))}}
  await sleep(400);return editorValue(el).includes(text.slice(0,20));
}
function sendButton(platform){const ed=editor(platform),form=ed?.closest('form'),selectors=platform==='Gemini'?['button.send-button','button[aria-label*="Send"]','button[aria-label*="鍙戦€?]','button[aria-label*="鎻愪氦"]']:['button[data-testid="send-button"]','#composer-submit-button','button[aria-label*="Send"]','button[aria-label*="鍙戦€?]','button[aria-label*="鎻愪氦"]'];return [...selectors.map(s=>document.querySelector(s)),form?.querySelector('button[type="submit"]'),document.querySelector('button[type="submit"]'),buttonByText(/^send$|^鍙戦€?|^鎻愪氦$/i)].find(e=>visible(e)&&!e.disabled)}
async function submitPrompt(platform,ed,marker){
  const key=String(marker||editorValue(ed)).slice(0,20),before=editorValue(ed),send=await waitFor(()=>sendButton(platform),15000).catch(()=>null);
  if(send)send.click();else{ed.focus();ed.dispatchEvent(new KeyboardEvent('keydown',{key:'Enter',code:'Enter',bubbles:true,cancelable:true}));ed.dispatchEvent(new KeyboardEvent('keyup',{key:'Enter',code:'Enter',bubbles:true}))}
  const end=Date.now()+10000;while(Date.now()<end){await sleep(500);const fresh=editor(platform)||ed,now=editorValue(fresh);if(!now||!now.includes(key)||now.length<Math.max(8,Math.floor(before.length*.35)))return true}
  throw new Error('网页没有真正发送：内容仍停留在输入框里。请确认发送按钮可用，或手动点一次发送后再点“继续检测回答”。')
}
async function attachImage(input,file,ed){if(input){const dt=new DataTransfer();dt.items.add(file);input.files=dt.files;input.dispatchEvent(new Event('input',{bubbles:true}));input.dispatchEvent(new Event('change',{bubbles:true}));return}const dt=new DataTransfer();dt.items.add(file);const ev=new ClipboardEvent('paste',{bubbles:true,cancelable:true,clipboardData:dt});ed.dispatchEvent(ev);await sleep(500);if(!ev.defaultPrevented)throw new Error('缃戦〉闃绘浜嗚嚜鍔ㄤ笂浼狅紝璇锋鏌ラ〉闈㈠悗閲嶈瘯')}
function composerRoot(ed){
  const rich=ed?.closest('rich-textarea');
  if(rich){let root=rich;for(let i=0;i<6&&root.parentElement;i++){root=root.parentElement;if(root.querySelectorAll('img,button,input[type="file"]').length)return root}return rich.parentElement||rich}
  return ed?.closest('form')||ed?.closest('[data-testid*="composer"],[class*="composer"]')||ed?.parentElement||document.body
}
function nearEditor(img,ed){
  if(!ed)return true;const ib=img.getBoundingClientRect(),eb=ed.getBoundingClientRect();
  return ib.bottom>eb.top-520&&ib.top<eb.bottom+360&&ib.right>eb.left-80&&ib.left<eb.right+420;
}
function hasImageAttachment(ed){
  const root=composerRoot(ed),text=(root.innerText||root.textContent||'').toLowerCase();
  if(/uploading|processing|attaching|正在上传|上传中|处理中/.test(text))return false;
  const imgs=[...root.querySelectorAll('img')].filter(img=>{
    const src=img.currentSrc||img.src||'',box=img.getBoundingClientRect();
    return visible(img)&&nearEditor(img,ed)&&Math.max(img.naturalWidth||0,box.width)>40&&Math.max(img.naturalHeight||0,box.height)>40&&!/avatar|emoji|icon|logo|profile/i.test(src);
  });
  if(imgs.length)return true;
  if(/uploaded|attached|image|图片|附件|remove file|移除文件/.test(text)&&nearEditor(root,ed))return true;
  return !!root.querySelector('[data-testid*="attachment"],[class*="attachment"],[aria-label*="Remove"],[aria-label*="移除"]');
}
async function waitForImageAttachment(ed,timeout=45000){
  const end=Date.now()+timeout;let stable=0;
  while(Date.now()<end){if(hasImageAttachment(ed)){stable++;if(stable>=2)return true}else stable=0;await sleep(800)}
  return false;
}

function responseCandidates(platform){
  const selectors=platform==='Gemini'?['model-response','[data-test-id="model-response"]','.model-response-text','message-content','.markdown','pre','code']:['[data-message-author-role="assistant"]','article[data-turn="assistant"]','[data-testid*="conversation-turn"] .markdown','.markdown','pre','code'];
  const seen=new Set(),out=[];for(const sel of selectors)for(const n of document.querySelectorAll(sel)){if(!visible(n))continue;const t=(n.innerText||n.textContent||'').trim();if(t.length<20||t.length>30000||seen.has(t))continue;seen.add(t);out.push(t)}return out;
}
function extractProductJson(text){
  const cleaned=String(text||'').replace(/^```(?:json)?\s*/i,'').replace(/\s*```$/,'').trim(),starts=[];for(let i=0;i<cleaned.length;i++)if(cleaned[i]==='{')starts.push(i);
  for(let a=starts.length-1;a>=0;a--){for(let end=cleaned.lastIndexOf('}');end>starts[a];end=cleaned.lastIndexOf('}',end-1)){try{const raw=cleaned.slice(starts[a],end+1),o=JSON.parse(raw);if(o&&typeof o==='object'&&(o.productName||o.titleStyles||o.listingTitles||o.details||o.productDetails))return raw}catch(e){}}}return'';
}
function newAnswer(platform){const candidates=responseCandidates(platform).filter(t=>!baselineTexts.has(t));for(let i=candidates.length-1;i>=0;i--){const raw=extractProductJson(candidates[i]);if(raw)return raw}return''}

async function waitForAnswer(job){
  stage='waiting';status('问题已发送，只检测回答，不会再次提交');let last='',stable=0;const deadline=Date.now()+240000;
  while(Date.now()<deadline){await sleep(1500);const now=newAnswer(job.platform);if(!now){stable=0;continue}if(now===last)stable++;else stable=0;last=now;if(stable>=2)break}
  if(!last){stage='sent';throw new Error('暂未检测到完整 JSON 回答；点击继续检测回答只会继续读取，不会重复发送')}
  if(resultSent)return;resultSent=true;stage='complete';status('完整回答已捕获，正在回传并切换到工作台','ok');chrome.runtime.sendMessage({type:'JOB_RESULT',result:last});
}
async function prepareAndSend(job){
  const ed=await waitFor(()=>editor(job.platform));baselineTexts=new Set(responseCandidates(job.platform));status('已找到 '+job.platform+' 输入框，正在填写固定问题');
  if(stage==='idle'||stage==='preparing'){
    stage='preparing';if(!await setEditor(ed,job.prompt))throw new Error(job.platform+' 阻止了提示词写入，请点击继续自动执行重试');stage='prompted';
  }
  const jobImages=[...(Array.isArray(job.images)?job.images:[]),job.image].filter(Boolean).map(x=>String(x).trim()).filter(Boolean).filter((x,i,a)=>a.indexOf(x)===i);
  if(stage==='prompted'&&!job.textOnly&&jobImages.length){
    for(const [i,img] of jobImages.entries()){
      status('提示词已写入，正在上传产品图片 '+(i+1)+'/'+jobImages.length);
      const input=await ensureFileInput(job.platform);
      try{await attachImage(input,await jobImageFile(img),ed)}catch(err){throw new Error('第 '+(i+1)+' 张产品图片上传失败：'+err.message)}
      status('第 '+(i+1)+' 张图片已交给网页，正在确认附件是否上传完成');
      if(!await waitForImageAttachment(ed))throw new Error('未检测到第 '+(i+1)+' 张图片附件，已停止发送；请确认网页输入框里出现图片缩略图后重试');
      await sleep(900);
    }
    stage='attached';
  } else if(stage==='prompted'){
    stage='attached';status('文字资料已写入，当前没有有效产品图片，准备发送');
  }
  if(!editorValue(ed).includes(job.prompt.slice(0,20))&&!await setEditor(ed,job.prompt))throw new Error('涓婁紶鍥剧墖鍚庢彁绀鸿瘝琚竻闄わ紝鑷姩鎭㈠澶辫触');
  status('图片和提示词均已就绪，准备发送');await sleep(400);await submitPrompt(job.platform,ed,job.prompt);
  stage='sent';status('问题已发送，开始检测回答');await waitForAnswer(job);
}
function pageImageSources(){return [...document.images].map(img=>img.currentSrc||img.src||'').filter(Boolean)}
function isAssistantImage(img,platform){
  const src=img.currentSrc||img.src||'',box=img.getBoundingClientRect();
  if(!src||/avatar|emoji|icon|logo|profile|user/i.test(src))return false;
  if(Math.max(img.naturalWidth||0,box.width)<220||Math.max(img.naturalHeight||0,box.height)<220)return false;
  if(img.closest('form,[data-testid*="composer"],[class*="composer"],[contenteditable="true"],textarea'))return false;
  if(img.closest('[data-message-author-role="user"],article[data-turn="user"],[data-testid*="user"]'))return false;
  if(platform==='Gemini')return !!img.closest('model-response,[data-test-id="model-response"],.model-response,[class*="generated-image"]');
  return !!img.closest('[data-message-author-role="assistant"],article[data-turn="assistant"],[data-testid*="conversation-turn"]');
}
function generatedImages(platform){
  const selectors=platform==='Gemini'?['model-response img','[data-test-id="model-response"] img','.model-response img','generated-image img','[class*="generated-image"] img']:['[data-message-author-role="assistant"] img','article[data-turn="assistant"] img','[data-testid*="conversation-turn"] img'];
  const out=[],seen=new Set();for(const sel of selectors)for(const img of document.querySelectorAll(sel)){const src=img.currentSrc||img.src||'';if(seen.has(src)||!isAssistantImage(img,platform))continue;seen.add(src);out.push({img,src})}return out;
}
async function imageData(src){
  if(src.startsWith('data:'))return src;
  try{const r=await fetch(src,{credentials:'include'});if(!r.ok)throw new Error('HTTP '+r.status);const b=await r.blob();return await new Promise((ok,no)=>{const f=new FileReader();f.onload=()=>ok(f.result);f.onerror=no;f.readAsDataURL(b)})}catch(e){}
  const r=await chrome.runtime.sendMessage({type:'FETCH_IMAGE_DATA',url:src});if(r?.ok)return r.data;throw new Error('生成图已出现，但扩展无法读取图片数据');
}
async function waitForNewImage(platform,baseline,timeout=180000){const end=Date.now()+timeout;let lastSrc='',stable=0,lastItem=null;while(Date.now()<end){await sleep(1800);const found=generatedImages(platform).filter(x=>!baseline.has(x.src));if(found.length){const item=found[found.length-1];if(item.src===lastSrc){stable++;lastItem=item}else{lastSrc=item.src;stable=1;lastItem=item}if(stable>=2)return lastItem}}throw new Error('等待生成图片超时')}
async function sendImagePrompt(job,task,index){
  const ed=await waitFor(()=>editor(job.platform),60000),baseline=new Set([...pageImageSources(),...generatedImages(job.platform).map(x=>x.src)]);
  status('四套图片生成中：'+(index+1)+'/'+job.tasks.length+'\n'+task.styleName+' · '+task.label);if(!await setEditor(ed,task.prompt))throw new Error('图片提示词写入失败');
  if(index===0){let input=await ensureFileInput(job.platform);await attachImage(input,await jobImageFile(job.image),ed);await sleep(1800);pageImageSources().forEach(src=>baseline.add(src));for(const [refIndex,ref] of (job.referenceImages||[]).slice(0,4).entries()){input=await ensureFileInput(job.platform);await attachImage(input,await jobImageFile(ref),ed);status('正在附加 SKU 版式参考 '+(refIndex+1)+'/'+Math.min(4,job.referenceImages.length));await sleep(1200);pageImageSources().forEach(src=>baseline.add(src))}await sleep(1000);generatedImages(job.platform).forEach(x=>baseline.add(x.src));if(!editorValue(ed).includes(task.prompt.slice(0,20)))await setEditor(ed,task.prompt)}
  await submitPrompt(job.platform,ed,task.prompt);
  const found=await waitForNewImage(job.platform,baseline),data=await imageData(found.src);chrome.runtime.sendMessage({type:'JOB_IMAGE',item:{sourceIndex:task.sourceIndex,styleId:task.styleId,styleName:task.styleName,slotIndex:task.slotIndex,targetIndex:task.targetIndex,label:task.label,assetType:task.assetType,skuIndex:task.skuIndex,data,sourceUrl:/^https:/i.test(found.src)?found.src:''}});status('第 '+(index+1)+'/'+job.tasks.length+' 张已识别并回传，准备下一张','ok');await sleep(1200);
}
async function generateImageBatch(job){
  stage='preparing';const start=Math.max(0,Number(job.completed||0));job.retryCounts=job.retryCounts||{};
  for(let i=start;i<job.tasks.length;i++){
    job.completed=i;await chrome.runtime.sendMessage({type:'UPDATE_JOB_STATE',state:{completed:i,retryCounts:job.retryCounts}});
    let success=false,lastError;
    for(let attempt=Number(job.retryCounts[i]||0);attempt<3&&!success;attempt++){
      job.retryCounts[i]=attempt;
      try{
        if(attempt>0){status('第 '+(i+1)+' 张未生成，正在自动重试 '+(attempt+1)+'/3','error');const ed=await waitFor(()=>editor(job.platform),45000);await setEditor(ed,job.tasks[i].prompt);await sleep(1200)}
        await sendImagePrompt(job,job.tasks[i],i);success=true;
      }catch(e){lastError=e;job.retryCounts[i]=attempt+1;await chrome.runtime.sendMessage({type:'UPDATE_JOB_STATE',state:{completed:i,retryCounts:job.retryCounts}});await sleep(2500)}
    }
    if(!success)throw new Error('第 '+(i+1)+' 张自动重试 3 次仍失败：'+(lastError?.message||lastError));
    job.completed=i+1;await chrome.runtime.sendMessage({type:'UPDATE_JOB_STATE',state:{completed:i+1,retryCounts:job.retryCounts}});
  }
  stage='complete';resultSent=true;status((job.batchLabel||'图片任务')+'已完成，共 '+job.tasks.length+' 张，正在返回工作台','ok');chrome.runtime.sendMessage({type:'JOB_RESULT',result:{kind:'image-batch',count:job.tasks.length,batchLabel:job.batchLabel||'图片任务'}});
}
async function resume(job){
  if(running||stage==='complete')return;running=true;activeJob=job;panel().querySelector('.pwa-run').disabled=true;
  try{if(job.mode==='image-batch')await generateImageBatch(job);else if(stage==='sent'||stage==='waiting')await waitForAnswer(job);else await prepareAndSend(job)}
  catch(e){status('自动执行暂停：\n'+(e.message||String(e)),'error');chrome.runtime.sendMessage({type:'JOB_ERROR',error:e.message||String(e)})}
  finally{running=false;status(panel().querySelector('.pwa-status').textContent,stage==='complete'?'ok':stage==='sent'?'error':'normal')}
}

chrome.runtime.sendMessage({type:'GET_JOB'},response=>{if(!response?.job){panel().style.display='none';return}activeJob=response.job;resume(activeJob)});
