"""
Draft complementary unit tests for test_wilderness_map_generator.py
to independently verify edge case detection and fix efficacy.
"""
from __future__ import annotations
import shutil
import subprocess
import pytest

from server.world.map_data_types import TileType
from server.world.wilderness_map_generator import WildernessMapGenerator
from server.world.map_binary_serializer import (
    serialize_map_grid,
    deserialize_map_grid,
)


class TestComplementaryMapBinarySerializerEdgeCases:
    """Verifies truncation at all offsets and unknown tile fallback in Python."""

    def test_binary_truncation_across_all_sections(self) -> None:
        gen = WildernessMapGenerator.for_zone("zone_tang_kiem_nhai")
        valid_buf = serialize_map_grid(gen.generate(seed=42))
        total_len = len(valid_buf)

        # Truncations at 16 (header only, missing tables), POI offset, encounter offset, grid offsets
        cut_offsets = [16, 20, 25, total_len - 1, total_len - 50]
        for cut in cut_offsets:
            with pytest.raises(ValueError, match="Buffer truncated"):
                deserialize_map_grid(valid_buf[:cut])

    def test_unknown_tile_value_fallback_to_wall(self) -> None:
        gen = WildernessMapGenerator.for_zone("zone_tang_kiem_nhai")
        raw = bytearray(serialize_map_grid(gen.generate(seed=7)))
        raw[-1] = 99  # unknown tile code
        restored = deserialize_map_grid(bytes(raw))
        assert restored.tiles[-1][-1].tile_type == TileType.WALL


class TestComplementaryClientTileGridLoaderEdgeCases:
    """Verifies client JS loader clean import, non-finite getTileAt, setTileAt, and buffer validation."""

    @staticmethod
    def _run_node(script: str) -> subprocess.CompletedProcess[str]:
        return subprocess.run(
            ["node", "-e", script],
            capture_output=True,
            text=True,
            cwd=r"c:\Projects\FreeExile",
        )

    def test_node_loader_clean_import_without_window(self) -> None:
        if not shutil.which("node"):
            pytest.skip("Node.js runtime not installed")
        script = """
        const { TileGridLoader, BIOME_CODES } = require('./client/webapp/js/engine/tile_grid_loader.js');
        if (!TileGridLoader || !BIOME_CODES) process.exit(1);
        """
        res = self._run_node(script)
        assert res.returncode == 0, f"Clean Node require failed: {res.stderr}"

    def test_node_get_tile_at_non_finite_and_oob(self) -> None:
        if not shutil.which("node"):
            pytest.skip("Node.js runtime not installed")
        script = """
        const { TileGridLoader } = require('./client/webapp/js/engine/tile_grid_loader.js');
        TileGridLoader.loadFallbackGrid(60, 45, 1);
        const badCoords = [NaN, undefined, -1, 60, Infinity, -Infinity, "invalid"];
        for (const c of badCoords) {
            if (TileGridLoader.getTileAt(c, 0) !== 2 || TileGridLoader.getTileAt(0, c) !== 2) {
                console.error("Failed for coord:", c, "got:", TileGridLoader.getTileAt(c, 0));
                process.exit(1);
            }
        }
        if (TileGridLoader.getTileAt(NaN, NaN) !== 2) process.exit(2);
        if (TileGridLoader.getTileAt(0.9, 0.9) !== 1) process.exit(3);
        process.exit(0);
        """
        res = self._run_node(script)
        assert res.returncode == 0, f"getTileAt non-finite/OOB failed: {res.stderr}"

    def test_node_set_tile_at_mutation_and_guards(self) -> None:
        if not shutil.which("node"):
            pytest.skip("Node.js runtime not installed")
        script = """
        const { TileGridLoader } = require('./client/webapp/js/engine/tile_grid_loader.js');
        TileGridLoader.loadFallbackGrid(10, 10, 1);
        if (!TileGridLoader.setTileAt(5, 5, 10) || TileGridLoader.getTileAt(5, 5) !== 10) process.exit(1);
        if (!TileGridLoader.setTileAt(5, 5, 1) || TileGridLoader.getTileAt(5, 5) !== 1) process.exit(2);
        for (const bad of [-1, 10, NaN, Infinity]) {
            if (TileGridLoader.setTileAt(bad, 0, 1) !== false) process.exit(3);
        }
        process.exit(0);
        """
        res = self._run_node(script)
        assert res.returncode == 0, f"setTileAt mutation or guard failed: {res.stderr}"

    def test_node_loader_truncated_and_corrupt_buffers(self, tmp_path) -> None:
        if not shutil.which("node"):
            pytest.skip("Node.js runtime not installed")
        gen = WildernessMapGenerator.for_zone("zone_tang_kiem_nhai")
        bin_path = tmp_path / "valid.bin"
        bin_path.write_bytes(serialize_map_grid(gen.generate(seed=42)))
        bin_str = str(bin_path).replace("\\", "/")

        script = f"""
        const fs = require('fs');
        const {{ TileGridLoader }} = require('./client/webapp/js/engine/tile_grid_loader.js');
        if (TileGridLoader.loadBinaryMap(null) !== null) process.exit(1);
        if (TileGridLoader.loadBinaryMap(Buffer.alloc(0)) !== null) process.exit(2);
        if (TileGridLoader.loadBinaryMap(Buffer.alloc(15)) !== null) process.exit(3);

        const valid = fs.readFileSync('{bin_str}');
        const corrupt = Buffer.from(valid); corrupt[0] = 88; corrupt[1] = 88;
        if (TileGridLoader.loadBinaryMap(corrupt) !== null) process.exit(4);

        for (const cut of [16, 20, valid.length - 1]) {{
            if (TileGridLoader.loadBinaryMap(valid.subarray(0, cut)) !== null) process.exit(5);
        }}

        const fake = Buffer.alloc(16);
        fake.write("FE", 0, 2, 'ascii'); fake.writeUInt8(1, 2); fake.writeUInt8(1, 3);
        fake.writeUInt16LE(0, 4); fake.writeUInt16LE(0, 6); fake.writeUInt8(10, 12);
        if (TileGridLoader.loadBinaryMap(fake) !== null) process.exit(6);

        process.exit(0);
        """
        res = self._run_node(script)
        assert res.returncode == 0, f"Node buffer rejection failed: {res.stderr}"
