// FILE: _St/IG_StYellow/test_ext_v303_core_regression.js | ROLE: v303 CDP·Cache Image·Swipe·Explorer 회귀 보호
const assert = require('assert');
const fs = require('fs');
const path = require('path');

const root = __dirname;
const read = (rel) => fs.readFileSync(path.join(root, rel), 'utf8');
const background = read('background.js');
const content = read('content_instagram.js');
const side = read('side.js');
const html = read('side.html');
const inject = read('js/instagram_inject.js');
const cachePy = fs.readFileSync(path.join(root, '..', 'Cache8701', 'cache8701_main.py'), 'utf8');
const storagePy = fs.readFileSync(path.join(root, '..', 'Shared', 'storage', 'sort_storage.py'), 'utf8');

// CDP 상태는 Side/Background가 원본이고 Main은 표시 전용이다.
assert.ok(background.includes('YELLOW/cdp_state_v303'));
assert.ok(background.includes('IGBLUE_CDP_STATE_UPDATE'));
assert.ok(background.includes('IGBLUE_GET_CDP_STATE'));
assert.ok(background.includes('IGBLUE_CDP_STATE_CHANGED'));
assert.ok(side.includes('function publishCdpState'));
assert.ok(side.includes('cdpStatusFailureCount >= 2'));
assert.ok(content.includes("ok:null, checking:true, source:'startup_checking'"));
assert.ok(content.includes("chrome.runtime.sendMessage({type:'IGBLUE_GET_CDP_STATE'"));
assert.ok(content.includes('function igbluePublishCdpProof'));
assert.ok(!content.includes("let igblueCdpGateState = { ok:false, source:'startup'"));
assert.ok(content.includes("toggle.textContent = 'CDP:? · 탭 0 · OWNER 없음'"));
assert.ok(!content.includes("toggle.textContent = 'CDP:X · 탭 0 · OWNER 없음'"));

// Cache Image는 Video 저장과 독립적으로 Side 수집 뒤 비동기 전송한다.
assert.ok(html.includes('id="igblue_cache_image_status"'));
assert.ok(side.includes('[Cache Image 자동 저장][회귀 금지]'));
assert.ok(side.includes('http://127.0.0.1:8701/api/meta'));
assert.ok(side.includes('http://127.0.0.1:8701/api/status?run_id='));
assert.ok(side.includes('setTimeout(() => teCache8701PostShopPayload(e), 80)'));
assert.ok(side.includes('const items = teCache8701Items(teMetricSourceList())'));
assert.ok(cachePy.includes('CACHE_RUNS: Dict[str, dict] = {}'));
assert.ok(cachePy.includes('if self.path.startswith("/api/status")'));
assert.ok(cachePy.includes('ensure_instagram_account_index'));
assert.ok(storagePy.includes('def ensure_instagram_account_index'));
assert.ok(storagePy.includes('D:/_StDown/instagram/'));

// 기존 자동 탐색은 대상 0개만으로 종료하지 않고 Swipe·날짜 경계를 확인한다.
assert.ok(side.includes('[기존 정상 기능 보호][회귀 금지]'));
assert.ok(side.includes('조건 대상이 0개이거나 목표보다 적어도 날짜 범위 안이면 Swipe를 계속한다.'));
assert.ok(side.includes('action: "check_new_media_date_range"'));
assert.ok(side.includes('reason: dateDelta.exhausted_batch ? "new_media_all_older_than_filter" : "valid_or_unknown_date_media_present"'));
assert.ok(side.includes('if (dateDelta.active && consecutiveDateExhausted >= 1)'));
assert.ok(side.includes('현재 후보가 0개여도 loadPlan이 실제 종료를 증명하지 않으면 다음 Swipe 탐색으로 돌아간다.'));

// Explorer 원본 섬네일 링크는 EXT 전후 모두 Instagram 기본 이동을 유지한다.
assert.ok(inject.includes('[Explorer 기본 클릭 보호][회귀 금지]'));
assert.ok(inject.includes('a[href*="/p/"]'));
assert.ok(inject.includes('a[href*="/reel/"]'));
const dangerousAnchorInterceptor = /closest\([^)]*a\[href\*=["']\/(?:p|reel)\/["'][^)]*\)[\s\S]{0,500}preventDefault\(/;
assert.ok(!dangerousAnchorInterceptor.test(inject), 'Instagram media anchor click must not be broadly intercepted');

console.log('OK test_ext_v303_core_regression');
