// FILE: _St/IG_StYellow/test_ext_account_search_navigation_v285.js | ROLE: v285 Instagram 검색 기반 계정 이동·계정 컨텍스트 차단 검사
const assert = require('assert');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const vm = require('vm');

const root = __dirname;
const manifest = JSON.parse(fs.readFileSync(path.join(root, 'manifest.json'), 'utf8'));
const background = fs.readFileSync(path.join(root, 'background.js'), 'utf8');
const side = fs.readFileSync(path.join(root, 'side.js'), 'utf8');
const content = fs.readFileSync(path.join(root, 'content_instagram.js'), 'utf8');

assert.strictEqual(manifest.version, '2.3.8.2850');
assert.strictEqual(manifest.version_name, '2.3.8.285');
assert.ok(manifest.description.includes('search UI exact-account clicks'));

const navStart = background.indexOf('function igblueSearchAccountInActiveTab');
const navEnd = background.indexOf('function igblueEnsureContentScripts', navStart);
const nav = background.slice(navStart, navEnd);
assert.ok(navStart >= 0 && navEnd > navStart, 'search navigation block missing');
for (const token of ['igblue_search_account_in_tab', 'search_profile_ready', 'same_tab:true']) assert.ok(nav.includes(token), `search navigation token missing: ${token}`);
for (const removed of ['chrome.tabs.update(', 'chrome.tabs.create(', 'chrome.tabs.remove(']) assert.ok(!nav.includes(removed), `direct/replacement tab navigation remains: ${removed}`);

for (const token of [
  'svg[aria-label="검색"],svg[aria-label="Search"]',
  'input[placeholder="검색"]',
  'parts.length === 1 && String(parts[0] || "").toLowerCase() === expected',
  'exact_search_result_not_found',
  'searched_profile_not_ready',
  'localStorage.removeItem("IGBLUE/active_download_target")',
  'localStorage.removeItem("IGBLUE/internal_no_nav_state")'
]) assert.ok(content.includes(token), `content search token missing: ${token}`);

for (const token of [
  'action: "instagram_search_exact_click"',
  'type: "IGBLUE_SEARCH_ACCOUNT_IN_TAB"',
  'account_context_mismatch',
  'teAutoPyExpectedAccountUsername',
  '["profile_loaded", "private"]'
]) assert.ok(side.includes(token), `side account guard token missing: ${token}`);

// 계정 상태는 URL만 같다고 성공하지 않고 정확한 프로필 증거가 있을 때만 profile_loaded가 된다.
const stateStart = content.indexOf('function igblueReadAccountPageState(expectedUsername)');
const stateEnd = content.indexOf('function igblueSearchVisible', stateStart);
const stateCode = content.slice(stateStart, stateEnd) + '\nthis.readState=igblueReadAccountPageState;';
function readState(href, expected, options = {}) {
  const canonical = options.canonical || '';
  const context = {
    URL, Set,
    location: { href, origin: 'https://www.instagram.com' },
    document: {
      body: { innerText: options.text || '', textContent: options.text || '' },
      title: options.title || '',
      readyState: 'complete',
      querySelector(selector) {
        if (selector === 'link[rel="canonical"]' && canonical) return { href: canonical };
        return null;
      },
      querySelectorAll() { return []; }
    }
  };
  vm.runInNewContext(stateCode, context, { filename: 'account_state_v285.js' });
  return context.readState(expected);
}
let state = readState('https://www.instagram.com/gonggan__gyeol/', 'gonggan__gyeol');
assert.strictEqual(state.state, 'profile_loading');
assert.strictEqual(state.profile_evidence, false);
state = readState('https://www.instagram.com/gonggan__gyeol/', 'gonggan__gyeol', { canonical: 'https://www.instagram.com/gonggan__gyeol/' });
assert.strictEqual(state.state, 'profile_loaded');
assert.strictEqual(state.same_expected_profile, true);
state = readState('https://www.instagram.com/leon.majster/', 'gonggan__gyeol', { canonical: 'https://www.instagram.com/leon.majster/' });
assert.strictEqual(state.state, 'navigating');
assert.strictEqual(state.same_expected_profile, false);

// 검색 결과는 정확히 /username/ 한 단계 경로만 허용한다.
const helperStart = content.indexOf('function igblueSearchVisible');
const helperEnd = content.indexOf('function igblueResetAccountContextForSearch', helperStart);
const helperCode = content.slice(helperStart, helperEnd) + '\nthis.findExact=igblueSearchExactResult;';
const anchors = [
  { href: 'https://www.instagram.com/gonggan__gyeol.fan/', isConnected: true },
  { href: 'https://www.instagram.com/gonggan__gyeol/reels/', isConnected: true },
  { href: 'https://www.instagram.com/gonggan__gyeol/', isConnected: true }
];
for (const anchor of anchors) anchor.getBoundingClientRect = () => ({ width: 100, height: 20 });
const helperContext = {
  URL,
  location: { origin: 'https://www.instagram.com' },
  document: { querySelectorAll: (selector) => selector === 'a[href]' ? anchors : [] },
  getComputedStyle: () => ({ display: 'block', visibility: 'visible' }),
  Promise, setTimeout, Date, Number, String, Array, Object
};
vm.runInNewContext(helperCode, helperContext, { filename: 'search_exact_v285.js' });
assert.strictEqual(helperContext.findExact('gonggan__gyeol'), anchors[2]);
assert.strictEqual(helperContext.findExact('missing_account'), null);

// v283 다운로드 핵심 블록은 그대로 유지한다.
const dlStart = background.indexOf('function igblueDownloadWithApi(msg, sendResponse)');
const dlEnd = background.indexOf('function igblueIsInstagramUrl(url)', dlStart);
const downloadBlock = background.slice(dlStart, dlEnd);
assert.strictEqual(downloadBlock.length, 10362);
assert.strictEqual(crypto.createHash('sha256').update(downloadBlock).digest('hex'), 'a8d7247a26fa1b88fe2b8b7d7883b56e0b1a52961c065ab9e50e35af332b51ef');

console.log('OK test_ext_account_search_navigation_v285');
