"""
Unit/Node Empirical Challenger Stress Harness for FreeExile Reactive i18n Subsystem (Milestone 2).
Adversarial Verification Targets:
1. 1,000 rapid programmatic switches cycling across all 9 languages in < 1000ms.
2. Character set encoding veracity for non-Latin scripts (Chinese, Japanese, Korean, Thai, German, Russian).
3. Zero subscriber / listener leaks under rapid registration & unregistration loops.
4. Exception resilience and subscriber isolation during burst notifications.
5. Ring buffer message retention and date formatting stability across multi-language cycles.
"""

from __future__ import annotations

import json
import subprocess
import sys
import unittest
from pathlib import Path
from typing import Any, Dict

if hasattr(sys.stdout, "reconfigure"):
    sys.stdout.reconfigure(encoding="utf-8")

PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
CLIENT_DIR = PROJECT_ROOT / "client" / "webapp"
I18N_JS = CLIENT_DIR / "js" / "data" / "i18n.js"
I18N_CATALOG_JS = CLIENT_DIR / "js" / "data" / "i18n_catalog.js"
CHAT_CATALOG_JS = CLIENT_DIR / "js" / "data" / "chat_i18n_catalog.js"
CHAT_UI_JS = CLIENT_DIR / "js" / "ui" / "chat_ui.js"


def run_node_stress_harness() -> Dict[str, Any]:
    """Executes high-throughput Node.js stress testing against i18n engine and chat UI."""
    i18n_p = str(I18N_JS).replace("\\", "/")
    chat_ui_p = str(CHAT_UI_JS).replace("\\", "/")
    chat_cat_p = str(CHAT_CATALOG_JS).replace("\\", "/")
    i18n_cat_p = str(I18N_CATALOG_JS).replace("\\", "/")

    script = f"""
import fs from 'fs';
import vm from 'vm';
import {{ performance }} from 'perf_hooks';

global.Image = class {{ constructor() {{ this.src = ''; }} }};
const storage = {{}};
global.localStorage = {{
  getItem: (k) => storage[k] || null,
  setItem: (k, v) => {{ storage[k] = String(v); }},
  removeItem: (k) => {{ delete storage[k]; }}
}};

const listeners = {{}};
global.CustomEvent = class CustomEvent {{
  constructor(t, i = {{}}) {{ this.type = t; this.detail = i.detail || {{}}; }}
}};
global.window = {{
  addEventListener: (n, cb) => {{ listeners[n] = listeners[n] || []; listeners[n].push(cb); }},
  removeEventListener: (n, cb) => {{ if (listeners[n]) listeners[n] = listeners[n].filter(f => f !== cb); }},
  dispatchEvent: (e) => {{ (listeners[e.type] || []).forEach(f => f(e)); }},
  localStorage: global.localStorage
}};

const elements = new Map();
const createMockEl = (id = '', tag = 'div') => ({{
  id, tagName: tag.toUpperCase(), dataset: {{}}, textContent: '', innerText: '', value: '', placeholder: '',
  disabled: false, className: '', classList: {{ add: () => {{}}, remove: () => {{}}, contains: () => false }},
  appendChild: (c) => c, querySelectorAll: () => [], querySelector: () => null, addEventListener: () => {{}}
}});
const getEl = (id) => {{ if (!elements.has(id)) elements.set(id, createMockEl(id)); return elements.get(id); }};
const tabs = Array.from({{ length: 8 }}, (_, i) => {{
  const t = createMockEl('chat-tab-' + (i + 1), 'button');
  t.dataset.channelId = String(i + 1);
  return t;
}});

global.document = {{
  readyState: 'complete',
  getElementById: (id) => getEl(id),
  createElement: (tag) => createMockEl('', tag),
  querySelectorAll: (sel) => (sel === '.chat-channel-tab' ? tabs : []),
  addEventListener: () => {{}}
}};

const catCode = fs.readFileSync('{i18n_cat_p}', 'utf-8');
const sb = {{ window: global.window }};
vm.createContext(sb);
vm.runInContext(catCode, sb);
global.I18N_CATALOG = global.window.I18N_CATALOG;

const chatCatModule = await import('file:///{chat_cat_p}');
global.CHAT_I18N_CATALOG = chatCatModule.CHAT_I18N_CATALOG;
await import('file:///{i18n_p}');
const i18n = global.window.FreeExileI18n;
const chatUI = await import('file:///{chat_ui_p}');
chatUI.initChatUI();

const report = {{}};

// 1. Stress Test: 1,000 rapid programmatic switches (< 1000ms SLA)
const allLocales = ['vi', 'en', 'zh', 'ja', 'ko', 'th', 'de', 'ru', 'es'];
const t0 = performance.now();
for (let i = 0; i < 1000; i++) {{
  i18n.setLocale(allLocales[i % allLocales.length]);
}}
const t1 = performance.now();
report.switches1000DurationMs = t1 - t0;
report.finalLocale = i18n.getLocale();

// 2. Non-Latin Script Encoding Veracity & Direct String Assertions
const scriptCheck = {{}};
for (const loc of allLocales) {{
  i18n.setLocale(loc);
  scriptCheck[loc] = {{
    worldTab: tabs[0].textContent,
    sendBtn: getEl('chat-send-btn').textContent,
    badgeLocked: i18n.t('chat_badge_locked'),
    systemNotice: i18n.t('chat_perm_system_only'),
    rarity5: i18n.t('rarity_5')
  }};
}}
report.scriptCheck = scriptCheck;

// 3. Zero Subscriber Leaks Under 500 Subscriptions/Unsubscriptions
const initialListenerCount = i18n.listeners.length;
const unsubs = [];
for (let i = 0; i < 500; i++) {{
  unsubs.push(i18n.subscribe(() => {{}}));
}}
report.peakListenerCount = i18n.listeners.length;
unsubs.forEach(u => u());
report.postCleanupListenerCount = i18n.listeners.length;
report.zeroLeak = report.postCleanupListenerCount === initialListenerCount;

// 4. Burst Exception Isolation
let executedAfterThrow = 0;
const noisySub1 = i18n.subscribe(() => {{ throw new Error('Simulated burst failure'); }});
const safeSub1 = i18n.subscribe(() => {{ executedAfterThrow++; }});
for (let i = 0; i < 20; i++) {{
  i18n.setLocale(allLocales[i % allLocales.length]);
}}
noisySub1();
safeSub1();
report.executedAfterThrow = executedAfterThrow;

// 5. Ring Buffer History Integrity Across Multi-language Bursts
chatUI.addChatMessage({{ channel: 1, senderName: 'Hero1', displayContent: 'Adversarial Message 1' }});
chatUI.addChatMessage({{ channel: 1, senderName: 'Hero2', displayContent: 'Adversarial Message 2' }});
const countBefore = chatUI.getChannelHistory(1).length;
for (let i = 0; i < 50; i++) {{
  i18n.setLocale(allLocales[i % allLocales.length]);
}}
const countAfter = chatUI.getChannelHistory(1).length;
report.historyPreserved = countBefore === countAfter && countAfter >= 2;

console.log(JSON.stringify(report));
"""

    res = subprocess.run(
        ["node", "--input-type=module", "-e", script],
        capture_output=True,
        text=True,
        encoding="utf-8",
        cwd=str(PROJECT_ROOT),
    )
    if res.returncode != 0:
        raise RuntimeError(f"Node execution failed (code {res.returncode}):\n{res.stderr}\n{res.stdout}")
    for line in reversed(res.stdout.strip().split("\n")):
        line = line.strip()
        if line.startswith("{") and line.endswith("}"):
            return json.loads(line)
    raise ValueError(f"Could not parse JSON report from Node:\n{res.stdout}")


class TestChallengerM2I18nStress(unittest.TestCase):
    """Adversarial unit-level stress testing verifying performance and non-Latin encoding."""

    report: Dict[str, Any] = {}

    @classmethod
    def setUpClass(cls) -> None:
        cls.report = run_node_stress_harness()

    def test_01_one_thousand_switches_under_one_second(self) -> None:
        """1,000 programmatic language switches must complete within 1000ms."""
        dur = self.report["switches1000DurationMs"]
        self.assertLess(dur, 1000.0, f"1000 switches took {dur}ms, exceeded 1000ms SLA")
        self.assertEqual(self.report["finalLocale"], "vi")

    def test_02_chinese_script_veracity(self) -> None:
        """Verifies Chinese Hanzi characters render without corruption."""
        zh = self.report["scriptCheck"]["zh"]
        self.assertEqual(zh["worldTab"], "世界")
        self.assertEqual(zh["sendBtn"], "发送")
        self.assertEqual(zh["badgeLocked"], "已锁定")
        self.assertEqual(zh["rarity5"], "太古")

    def test_03_japanese_kanji_kana_veracity(self) -> None:
        """Verifies Japanese Kanji, Hiragana, and Katakana render cleanly."""
        ja = self.report["scriptCheck"]["ja"]
        self.assertEqual(ja["worldTab"], "ワールド")
        self.assertEqual(ja["sendBtn"], "送信")
        self.assertEqual(ja["badgeLocked"], "ロック")
        self.assertEqual(ja["rarity5"], "太古")

    def test_04_korean_hangul_veracity(self) -> None:
        """Verifies Korean Hangul syllables render cleanly."""
        ko = self.report["scriptCheck"]["ko"]
        self.assertEqual(ko["worldTab"], "월드")
        self.assertEqual(ko["sendBtn"], "전송")
        self.assertEqual(ko["badgeLocked"], "잠김")
        self.assertEqual(ko["rarity5"], "태고")

    def test_05_thai_script_veracity(self) -> None:
        """Verifies Thai script glyphs render cleanly."""
        th = self.report["scriptCheck"]["th"]
        self.assertEqual(th["worldTab"], "โลก")
        self.assertEqual(th["sendBtn"], "ส่ง")
        self.assertEqual(th["badgeLocked"], "ล็อค")
        self.assertEqual(th["rarity5"], "โบราณกาล")

    def test_06_german_umlauts_veracity(self) -> None:
        """Verifies German umlauts (ä, ö, ü) render cleanly."""
        de = self.report["scriptCheck"]["de"]
        self.assertEqual(de["worldTab"], "Welt")
        self.assertEqual(de["sendBtn"], "Senden")
        self.assertEqual(de["badgeLocked"], "Gesperrt")
        self.assertEqual(de["rarity5"], "Uralt")

    def test_07_russian_cyrillic_veracity(self) -> None:
        """Verifies Russian Cyrillic characters render cleanly."""
        ru = self.report["scriptCheck"]["ru"]
        self.assertEqual(ru["worldTab"], "Мир")
        self.assertEqual(ru["sendBtn"], "Отправить")
        self.assertEqual(ru["badgeLocked"], "Блок")
        self.assertEqual(ru["rarity5"], "Древний")

    def test_08_subscriber_leak_free_under_burst(self) -> None:
        """Asserts zero memory/listener leaks after 500 subscriptions and cleanups."""
        self.assertTrue(self.report["zeroLeak"], "Listeners were leaked after unsubscription burst")
        self.assertEqual(self.report["postCleanupListenerCount"], self.report["peakListenerCount"] - 500)

    def test_09_exception_isolation_under_burst(self) -> None:
        """Asserts subscriber throwing errors does not interrupt other listeners."""
        self.assertEqual(self.report["executedAfterThrow"], 20)

    def test_10_chat_history_preservation(self) -> None:
        """Asserts chat ring buffer is preserved intact across rapid switching bursts."""
        self.assertTrue(self.report["historyPreserved"])


if __name__ == "__main__":
    unittest.main()
