// FILE: _St/IG_StYellow/test_ext_overlay_mode_bridge.js | ROLE: IG_StYellow 회귀 테스트
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const vm = require('vm');

const root = __dirname;
const read = (name) => fs.readFileSync(path.join(root, name), 'utf8');
const content = read('content_instagram.js');
const side = read('side.js');
const inject = read(path.join('js', 'instagram_inject.js'));
const manifest = JSON.parse(read('manifest.json'));

assert.strictEqual(manifest.version, '2.3.8.2810');
assert.strictEqual(manifest.version_name, '2.3.8.281');
assert.ok(side.includes('const IGBLUE_PACKAGE_VERSION = "v281";'));

// Side must still expose exactly the three user-facing modes.
for (const token of [
  'detail: "Detail (stats + downloads)"',
  'download: "Down icon only"',
  'none: "None (hide overlay)"',
  'type: "ndy_ig_overlay_mode_changed"'
]) assert.ok(side.includes(token), `missing Side overlay option: ${token}`);

// The isolated content bridge functions must be defined before their first call.
for (const fn of [
  'isOverlayMode',
  'validWeights',
  'normalizeWeights',
  'postOverlayMode',
  'postErWeights',
  'postVisualSettings'
]) {
  const def = content.indexOf(`function ${fn}(`);
  const call = content.indexOf(`${fn}(`, def + 1);
  assert.ok(def >= 0, `missing content bridge function: ${fn}`);
  assert.ok(call > def, `content bridge function has no later use: ${fn}`);
}

// Execute the restored helper block and verify payload normalization.
const start = content.indexOf('  function isOverlayMode(value)');
const end = content.indexOf('  // OS mouse, origin calibration', start);
assert.ok(start >= 0 && end > start, 'restored helper block not found');
const posted = [];
const ctx = {
  OVERLAY_MODES: ['detail', 'download', 'none'],
  DEFAULT_OVERLAY_MODE: 'detail',
  ER_KEYS: Object.freeze(['like', 'comment', 'repost']),
  DEFAULT_ER_WEIGHTS: Object.freeze({like:1, comment:4, repost:4}),
  window: {postMessage: (payload, target) => posted.push({payload, target})},
  Number,
  Object
};
vm.createContext(ctx);
vm.runInContext(`${content.slice(start, end)}; this.api={isOverlayMode,validWeights,normalizeWeights,postOverlayMode,postErWeights,postVisualSettings};`, ctx);
assert.strictEqual(ctx.api.isOverlayMode('detail'), true);
assert.strictEqual(ctx.api.isOverlayMode('download'), true);
assert.strictEqual(ctx.api.isOverlayMode('none'), true);
assert.strictEqual(ctx.api.isOverlayMode('broken'), false);
assert.strictEqual(ctx.api.validWeights({like:0, comment:2, repost:3}), true);
assert.strictEqual(ctx.api.validWeights({like:-1, comment:2, repost:3}), false);
assert.deepStrictEqual(JSON.parse(JSON.stringify(ctx.api.normalizeWeights({like:2, comment:'3'}))), {like:2, comment:3, repost:4});
ctx.api.postOverlayMode('download');
ctx.api.postOverlayMode('none');
ctx.api.postOverlayMode('broken');
ctx.api.postErWeights({like:2, comment:3, repost:5});
ctx.api.postVisualSettings({metric_bars:{enabled:false}});
assert.deepStrictEqual(posted.map(x => x.payload.type), [
  'ndy_ig_overlay_mode',
  'ndy_ig_overlay_mode',
  'ndy_ig_overlay_mode',
  'ndy_ig_er_weights',
  'ndy_ig_visual_settings'
]);
assert.deepStrictEqual(posted.slice(0,3).map(x => x.payload.mode), ['download','none','detail']);
assert.deepStrictEqual(JSON.parse(JSON.stringify(posted[3].payload.weights)), {like:2, comment:3, repost:5});
assert.deepStrictEqual(JSON.parse(JSON.stringify(posted[4].payload.value)), {metric_bars:{enabled:false}});
assert.ok(posted.every(x => x.target === '*'));

// MAIN-world receiver must preserve the three class modes and apply them to every card.
for (const token of [
  'const l="detail",a=["detail","download","none"]',
  'detail:"overlay-mode-detail"',
  'download:"overlay-mode-download"',
  'none:"overlay-mode-none"',
  'document.querySelectorAll(".ndy_ins_info").forEach',
  '"ndy_ig_overlay_mode"===t.type?h(t.mode)'
]) assert.ok(inject.includes(token), `missing MAIN overlay receiver token: ${token}`);

// CSS mode contract: detail keeps all, download hides stats but leaves overlay_download,
// none hides the complete injected card UI.
for (const token of [
  '.ndy_ins_info.overlay-mode-download .overlay{display:none}',
  '.ndy_ins_info.overlay-mode-download .overlay_download{display:flex}',
  '.ndy_ins_info.overlay-mode-none{display:none}'
]) assert.ok(inject.includes(token), `missing overlay mode CSS contract: ${token}`);

console.log('OK test_ext_overlay_mode_bridge v272');
