// FILE: _St/IG_StYellow/test_ext_home_explore_recovery.js | ROLE: IG_StYellow 회귀 테스트
const fs=require('fs'),path=require('path'),assert=require('assert'),vm=require('vm');
const read=n=>fs.readFileSync(path.join(__dirname,n),'utf8');
const inject=read('js/instagram_inject.js');
const manifest=JSON.parse(read('manifest.json'));
assert.strictEqual(manifest.version,'2.3.8.3130');
assert.strictEqual(manifest.version_name,'2.3.8.313');

function extractFunction(source,name){
  const start=source.indexOf(`function ${name}(`); assert.ok(start>=0,`${name} missing`);
  const open=source.indexOf('{',start); let depth=0,quote='',escaped=false,inRegex=false;
  for(let i=open;i<source.length;i++){
    const ch=source[i];
    if(quote){ if(escaped)escaped=false; else if(ch==='\\')escaped=true; else if(ch===quote)quote=''; continue; }
    if(ch==='"'||ch==="'"||ch==='`'){quote=ch;continue;}
    if(ch==='{')depth++;
    else if(ch==='}'){depth--;if(depth===0)return source.slice(start,i+1);}
  }
  throw new Error(`${name} unclosed`);
}

for(const token of [
  'function teMainHomeArticleForHostV268',
  'function teMainFindHomeArticleCardV268',
  'function teMainHomeHasVideoForCodeV268',
  'blocked_source:"H_IMAGE_LINK"',
  'kept_source:"D_VIDEO_LINK"',
  'createSource==="B_HOME_ARTICLE"',
  'installIgblueResponseCaptureV268',
  'Response.prototype.json',
  'Response.prototype.text',
  '__IGBLUE_SKIP_RESPONSE_CAPTURE_V268__',
  'function teStatsCheckExploreRenderV268',
  'Explore 링크는 있으나 미디어 데이터 수집 0건',
  'igblue_dom_diagnostic_v268',
  'injection_check_log',
  'media_map_count',
  'capture_counters'
]) assert.ok(inject.includes(token),`missing v268 token: ${token}`);

// Home image route must not create a second card when the same article has a same-code video.
const names=['teMainHomeArticleForHostV268','teMainFindHomeArticleCardV268','teMainHomeHasVideoForCodeV268','H'];
const code=names.map(n=>extractFunction(inject,n)).join('\n');
let createCount=0,linkCount=0,logRows=[];
const video={checkVisibility:()=>true,clientHeight:320};
const anchor={href:'https://www.instagram.com/reels/CODE_VIDEO/',parentNode:{querySelector:()=>null}};
const article={
  querySelectorAll:(sel)=>sel==='a[role="link"] video'?[video]:[],
};
const imageHost={closest:(sel)=>sel==='article'?article:null};
const ctx={
  String,
  imageHost,
  location:{pathname:'/'},
  j:(node)=>node===imageHost?anchor:node===video?anchor:null,
  M:()=>({code:'CODE_VIDEO'}),
  teStatsShortcodeFromUrl:()=> 'CODE_VIDEO',
  teInjectionCheckV268:(id,status,message,detail)=>logRows.push({id,status,message,detail}),
  k:()=>{createCount++;return {};},
  N:()=>{linkCount++;},
};
vm.createContext(ctx);
vm.runInContext(`${code}; this.run=()=>H(imageHost);`,ctx);
ctx.run();
assert.strictEqual(createCount,0,'home video poster/image route must not create a card');
assert.strictEqual(linkCount,0,'blocked image route must not relink a card');
assert.ok(logRows.some(x=>x.id==='INJ-05'&&x.detail.blocked_source==='H_IMAGE_LINK'));

// Image-only home post still uses the existing image route.
article.querySelectorAll=()=>[];
ctx.run();
assert.strictEqual(createCount,1,'image-only home post must still create one card');
assert.strictEqual(linkCount,1,'image-only home post must link media once');

// Explore DOM observer must no longer ignore routes without a detail shortcode.
assert.ok(!inject.includes('new MutationObserver((()=>{if(!teStatsShortcodeFromUrl(location.href))return;'));
assert.ok(inject.includes('teStatsCheckExploreRenderV268("dom_change")'));
assert.ok(inject.includes('for(const delay of [0,100,300,700,1500,3000,5000,8000])'));

console.log('OK test_ext_home_explore_recovery v272');
