"""
Adversarial Stress Testing & Empirical Verification Suite:
Spawner Gating, Transition Drop Flushing & Portal Traversal (Milestone 2).

Integrates empirical Node.js execution harness with server-side spatial authority
to verify zero hostile entity leaks in Safe Havens, 100% drop & projectile flushing
across zone boundaries, and reliable 6-portal map device traversal.
"""

from __future__ import annotations
import json
import os
from pathlib import Path
import subprocess
from typing import Any, Dict
import pytest

from server.world.spatial_grid import Entity
from server.world.zone_engine import ZoneEngine

NODE_HARNESS_SCRIPT = """
import fs from 'fs';
import vm from 'vm';
import path from 'path';
import { pathToFileURL } from 'url';

const projectRoot = process.cwd();
const createMockElement = () => ({
  id: '', className: '', innerHTML: '', innerText: '', style: {},
  classList: { toggle: () => {}, add: () => {}, remove: () => {}, contains: () => false },
  appendChild: () => {}, querySelector: () => null, addEventListener: () => {}
});

globalThis.window = globalThis;
globalThis.addEventListener = () => {};
globalThis.removeEventListener = () => {};
globalThis.document = {
  getElementById: () => createMockElement(),
  createElement: () => createMockElement(),
  body: createMockElement(),
  addEventListener: () => {}
};
globalThis.showNoticeModal = () => {};
globalThis.alert = () => {};
globalThis.groundDrops = [];
globalThis.vfx_slashes = [];
globalThis.vfx_spikes = [];
globalThis.vfx_lightnings = [];
globalThis.particles = [];
globalThis.damageTexts = [];
globalThis.player = { wx: 0, wy: 0, facing: 1, maxHp: 100, hp: 100 };
console.warn = () => {};

const loadScript = (rel) => vm.runInThisContext(fs.readFileSync(path.join(projectRoot, rel), 'utf8'));
loadScript('client/webapp/js/data/monster_catalog.js');
loadScript('client/webapp/js/engine/monster_loot_dropper.js');
loadScript('client/webapp/js/engine/vfx_renderer.js');
loadScript('client/webapp/js/engine/monster_system.js');

const worldmapModule = await import(pathToFileURL(path.join(projectRoot, 'client/webapp/js/ui/worldmap_dungeons.js')).href);
const hideoutModule = await import(pathToFileURL(path.join(projectRoot, 'client/webapp/js/ui/hideout_gates.js')).href);

const teleportToZone = worldmapModule.teleportToZone;
const enterMapPortal = hideoutModule.enterMapPortal;
const activateMapDevice = hideoutModule.activateMapDevice;
const hideoutState = hideoutModule.hideoutState;

const results = {
  test1_spawner_bypass: { passed: true, details: [] },
  test2_drop_flush: { passed: true, details: {} },
  test3_portal_traversal: { passed: true, details: {} },
  test4_stress_rapid_cycle: { passed: true }
};

// 1. Spawner Bypass Attempts
const safeHavens = ['zone_player_hideout', 'zone_boundless_sanctuary'];
const attackVectors = [
  ['spawnQAEnemy', 'boss'], ['spawnQAEnemy', 'pack'],
  ['spawnQAEnemy', 'hound'], ['spawnQAEnemy', 'skeleton'],
  ['spawnSpecificMonster', 'mob_feral_hellhound'],
  ['spawnSpecificMonster', 'mob_skeleton_warrior'],
  ['spawnSpecificMonster', 'boss_abyssal_tyrant']
];

for (const zone of safeHavens) {
  teleportToZone(zone);
  for (const [fn, arg] of attackVectors) {
    let ret = (fn === 'spawnQAEnemy') ? globalThis.spawnQAEnemy(arg) : globalThis.spawnSpecificMonster(arg);
    const hostiles = globalThis.activeMonsters.filter(m => !m.isDummy);
    const ok = (hostiles.length === 0 && (fn === 'spawnQAEnemy' || ret === null));
    results.test1_spawner_bypass.details.push({ zone, fn, arg, ok, hostilesCount: hostiles.length });
    if (!ok) results.test1_spawner_bypass.passed = false;
  }
  globalThis.spawnQAEnemy('dummy');
  const dummyOk = globalThis.activeMonsters.every(m => m.isDummy);
  results.test1_spawner_bypass.details.push({ zone, fn: 'spawnQAEnemy', arg: 'dummy', ok: dummyOk });
  if (!dummyOk) results.test1_spawner_bypass.passed = false;
}

// 2. Drop & Projectile Flush
teleportToZone('zone_tang_kiem_nhai');
for (let i = 0; i < 500; i++) globalThis.groundDrops.push({ id: `drop_${i}`, wx: i, wy: i });
for (let i = 0; i < 100; i++) {
  globalThis.vfx_slashes.push({ id: i });
  globalThis.vfx_spikes.push({ id: i });
  globalThis.vfx_lightnings.push({ id: i });
  globalThis.particles.push({ id: i });
  globalThis.damageTexts.push({ id: i });
}
const preCounts = { drops: globalThis.groundDrops.length, slashes: globalThis.vfx_slashes.length };
teleportToZone('zone_player_hideout');
const postCounts = {
  drops: globalThis.groundDrops.length,
  slashes: globalThis.vfx_slashes.length,
  spikes: globalThis.vfx_spikes.length,
  lightnings: globalThis.vfx_lightnings.length,
  particles: globalThis.particles.length,
  texts: globalThis.damageTexts.length
};
const allZero = Object.values(postCounts).every(c => c === 0);
results.test2_drop_flush.passed = (preCounts.drops === 500 && allZero);
results.test2_drop_flush.details = { preCounts, postCounts, allZero };

// 3. Portal Traversal Stress
teleportToZone('zone_player_hideout');
hideoutState.mapDevice.targetZoneId = 'zone_tang_kiem_nhai';
activateMapDevice();
const portalHistory = [];
for (let p = 6; p >= 1; p--) {
  teleportToZone('zone_player_hideout');
  enterMapPortal();
  portalHistory.push({
    p, zone: globalThis.currentZoneId,
    rem: hideoutState.mapDevice.portalsRemaining,
    wildMobs: globalThis.activeMonsters.some(m => !m.isDummy)
  });
}
teleportToZone('zone_player_hideout');
enterMapPortal();
const attempt7 = {
  zone: globalThis.currentZoneId,
  rem: hideoutState.mapDevice.portalsRemaining,
  act: hideoutState.mapDevice.active
};
results.test3_portal_traversal.passed = (
  portalHistory.length === 6 &&
  portalHistory.every(h => h.zone === 'zone_tang_kiem_nhai' && h.wildMobs) &&
  attempt7.rem === 0 && attempt7.act === false && attempt7.zone === 'zone_player_hideout'
);
results.test3_portal_traversal.details = { portalHistory, attempt7 };

// 4. Rapid Zone Transition Stress
for (let r = 0; r < 50; r++) {
  const t = (r % 2 === 0) ? 'zone_player_hideout' : 'zone_tang_kiem_nhai';
  globalThis.groundDrops.push({ id: r });
  teleportToZone(t);
  if (t === 'zone_player_hideout') {
    if (globalThis.activeMonsters.some(m => !m.isDummy) || globalThis.groundDrops.length !== 0) {
      results.test4_stress_rapid_cycle.passed = false;
      break;
    }
  }
}

process.stdout.write(JSON.stringify(results));
"""


@pytest.fixture(scope="module")
def client_harness_results() -> Dict[str, Any]:
    """Executes empirical Node.js adversarial harness and parses JSON."""
    proc = subprocess.run(
        ["node", "--input-type=module", "-e", NODE_HARNESS_SCRIPT],
        capture_output=True,
        text=True,
        check=True,
    )
    stdout_raw = proc.stdout
    start = stdout_raw.find("{")
    end = stdout_raw.rfind("}")
    assert start != -1 and end != -1, f"Invalid JSON output: {stdout_raw}"
    return json.loads(stdout_raw[start : end + 1])


class TestEmpiricalSpawnerGatingAndDropFlushingAdversarial:
    """Empirical adversarial stress test harness for Milestone 2."""

    def test_client_spawner_bypass_in_safe_havens_100_percent_rejected(
        self, client_harness_results: Dict[str, Any]
    ) -> None:
        """Verifies 100% rejection of hostile QA & specific monster spawns in safe havens."""
        t1 = client_harness_results["test1_spawner_bypass"]
        assert t1["passed"] is True, f"Spawner bypass allowed hostile entity! {t1}"
        for item in t1["details"]:
            assert item["ok"] is True, f"Failed vector: {item}"
            if "hostilesCount" in item:
                assert item["hostilesCount"] == 0

    def test_client_transition_drop_and_projectile_flush_500_items(
        self, client_harness_results: Dict[str, Any]
    ) -> None:
        """Verifies 500 ground drops and all flying projectiles are flushed on transition."""
        t2 = client_harness_results["test2_drop_flush"]
        assert t2["passed"] is True, f"Drop/projectile flush failed: {t2}"
        details = t2["details"]
        assert details["preCounts"]["drops"] == 500
        assert details["allZero"] is True
        for key, val in details["postCounts"].items():
            assert val == 0, f"Residual {key} count after teleport: {val}"

    def test_client_map_portal_traversal_stress_and_monster_refresh(
        self, client_harness_results: Dict[str, Any]
    ) -> None:
        """Verifies 6-portal cycle: depletion, map teleport, mob refresh, 7th rejection."""
        t3 = client_harness_results["test3_portal_traversal"]
        assert t3["passed"] is True, f"Portal traversal stress failed: {t3}"
        details = t3["details"]
        history = details["portalHistory"]
        assert len(history) == 6
        for idx, entry in enumerate(history):
            assert entry["zone"] == "zone_tang_kiem_nhai"
            assert entry["wildMobs"] is True
            assert entry["rem"] == 5 - idx
        assert details["attempt7"]["zone"] == "zone_player_hideout"
        assert details["attempt7"]["rem"] == 0
        assert details["attempt7"]["act"] is False

    def test_client_rapid_transition_endurance_50_cycles(
        self, client_harness_results: Dict[str, Any]
    ) -> None:
        """Verifies 50 rapid back-and-forth zone transitions maintain zero drop/mob leakage."""
        t4 = client_harness_results["test4_stress_rapid_cycle"]
        assert t4["passed"] is True, "Rapid zone transition endurance failed!"

    def test_server_authoritative_spawn_rejection_fuzzing(self) -> None:
        """Validates that ZoneEngine authoritative validation rejects hostile mobs."""
        engine = ZoneEngine()
        for zid in ["zone_player_hideout", "zone_boundless_sanctuary"]:
            allowed_mob, reason_mob = engine.validate_monster_spawn(zid, is_dummy=False)
            assert allowed_mob is False
            assert "An Toàn" in reason_mob or "Hideout" in reason_mob or "Sanctuary" in reason_mob
            allowed_dummy, _ = engine.validate_monster_spawn(zid, is_dummy=True)
            assert allowed_dummy is True

    def test_server_spatial_grid_drop_isolation_on_transition(self) -> None:
        """Validates spatial grid boundary isolation between wilderness and hideout."""
        engine = ZoneEngine()
        wild_grid = engine.zone_spatial_grids["zone_tang_kiem_nhai"]
        hideout_grid = engine.zone_spatial_grids["zone_player_hideout"]
        for i in range(500):
            wild_grid.add_entity(Entity(entity_id=90000 + i, x=float(i % 50), y=float(i // 50)))
        assert len(wild_grid.entities) >= 500
        assert len(hideout_grid.entities) == 0
        assert len(hideout_grid.get_entities_in_aoi(0.0, 0.0, radius_cells=10)) == 0
