// FILE: _St/IG_StYellow/test_ext_settings_modal_restore_v323.js | ROLE: Side 설정 모달 전역 선언·실행 회귀
const fs = require('fs');
const vm = require('vm');
const assert = require('assert');
const side = fs.readFileSync(__dirname + '/side.js', 'utf8');
const manifest = JSON.parse(fs.readFileSync(__dirname + '/manifest.json', 'utf8'));
assert.strictEqual(manifest.version, '2.3.8.3240');
assert.strictEqual(manifest.version_name, '2.3.8.324');

// v319에서 잘못 삭제됐던 v317 정상 전역 선언을 반드시 보존한다.
for (const token of [
  'let teAutoPyStatsTimer = 0;',
  'let teAutoPyStatsLastMainPush = 0;',
  'const m = "ndy_ig_overlay_mode"',
  'b = ["detail", "download", "none"]',
  'g = "detail"',
  'y = "ndy_ig_er_weights"',
  'v = Object.freeze(["like", "comment", "repost"])',
  'w = Object.freeze({ like: 1, comment: 4, repost: 4 })',
  'let _ = g',
  'x = { ...w }'
]) assert.ok(side.includes(token), `missing restored global: ${token}`);

// v317의 기존 settings target gate도 원상복구한다.
const marker = 'const e = document.getElementById("settings");';
const hs = side.indexOf(marker);
assert.ok(hs >= 0, 'settings handler missing');
const handler = side.slice(hs, hs + 480);
assert.ok(handler.includes('teHasInstagramTarget || u'), 'original Instagram target gate must be restored');
assert.ok(handler.includes('T();'), 'settings handler must call T()');

function extractFunction(src, signature) {
  const start = src.indexOf(signature);
  assert.ok(start >= 0, `${signature} missing`);
  const brace = src.indexOf('{', start);
  let depth = 0;
  for (let i = brace; i < src.length; i++) {
    if (src[i] === '{') depth++;
    else if (src[i] === '}') {
      depth--;
      if (depth === 0) return src.slice(start, i + 1);
    }
  }
  throw new Error(`unterminated ${signature}`);
}

class FakeElement {
  constructor(tag='div') { this.tagName=tag; this.style={}; this.children=[]; this.dataset={}; this.classList={add(){},remove(){}}; this.value=''; this.checked=false; this.disabled=false; }
  appendChild(el){ this.children.push(el); el.parentNode=this; return el; }
  addEventListener(type, cb){ (this.listeners ||= {})[type]=cb; }
  setAttribute(k,v){ this[k]=v; }
  remove(){ this.removed=true; }
  focus(){ this.focused=true; }
  get valueAsNumber(){ const n=Number(this.value); return Number.isFinite(n)?n:NaN; }
}
const body = new FakeElement('body');
const document = {
  body,
  createElement: tag => new FakeElement(tag),
  getElementById: id => {
    const q=[body]; while(q.length){ const e=q.shift(); if(e.id===id) return e; q.push(...(e.children||[])); } return null;
  }
};
const section = () => ({ element:new FakeElement('section'), getValues:()=>({}), getValue:()=> 'full', save:()=>Promise.resolve() });
const context = {
  document,
  console,
  setTimeout: fn => { fn(); return 1; },
  clearTimeout(){},
  b:['detail','download','none'], g:'detail', _:'detail',
  w:{like:1,comment:4,repost:4}, x:{like:1,comment:4,repost:4}, v:['like','comment','repost'],
  k:e=>['detail','download','none'].includes(e),
  C:e=>Object.assign({like:1,comment:4,repost:4},e||{}),
  E:e=>!!e,
  teCreateErEmojiSettings:section,
  teCreateViewVisualSettings:()=>({element:new FakeElement('section'),getValues:()=>({metric:{},date:{},thumbWidth:100})}),
  teCreateRankBadgeSettings:section,
  teCreateActiveDownloadSettings:section,
  teCreateStatsModeSettings:()=>({element:new FakeElement('section'),getValue:()=> 'full'}),
  teCreateAutoThumbnailSettings:()=>({element:new FakeElement('section'),save:()=>Promise.resolve()}),
  teCreateSettingsTabs:()=>({element:new FakeElement('section')}),
  teSaveErEmojiSettings(){}, teSaveViewVisualSettings(){}, teSaveRankBadgeSettings(){}, teSaveActiveDownloadSettings(){}, teSaveStatsMode(){},
  teApplyThumbWidth(){}, teSendVisualSettingsToMain(){}, ee(){}, n(){}, oe:[],
  S:()=>Promise.resolve('detail'), M:()=>Promise.resolve({like:1,comment:4,repost:4}),
  chrome:{runtime:{lastError:null},storage:{local:{set:(o,cb)=>cb&&cb()}},tabs:{query:(q,cb)=>cb([]),sendMessage(){}}}
};
vm.createContext(context);
vm.runInContext(extractFunction(side, 'function T()'), context);
assert.doesNotThrow(()=>context.T(), 'T() must execute without deleted-global ReferenceError');
assert.ok(document.getElementById('settingsModal'), 'T() must append settingsModal to document.body');
console.log('OK test_ext_settings_modal_restore_v323');
