class GameWorldTest(unittest.TestCase):
    def setUp(self):
        self.game_registry = GameRegistry(generate_test_db())
        self.event_system = MockEventSystem()
        self.handler = GameHandler(self.game_registry, self.event_system)

    def test_get_world_from_non_existant_game_returns_not_found(self):
        with self.assertRaises(ResourceNotFoundException) as context:
            self.handler.get_world(Request(CLIENT_ID, {"game_id": GAME_ID}))

        self.assertEqual("Game not found", context.exception.message)

    def test_get_world_for_game_we_are_not_part_of_returns_not_found(self):
        self.game_registry.create_game("123", GAME_ID)

        with self.assertRaises(ResourceNotFoundException) as context:
            self.handler.get_world(Request(CLIENT_ID, {"game_id": GAME_ID}))

        self.assertEqual("Game not found", context.exception.message)

    def test_get_world_with_initialised_data(self):
        game = self.game_registry.create_game(CLIENT_ID, GAME_ID)
        world = game.get_world()
        world.set_size(5, 5)
        world.persist()

        resp = self.handler.get_world(Request(CLIENT_ID, {"game_id": GAME_ID}))

        expected_tiles = [
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
        ]
        self.assertEqual(expected_tiles, resp["tileData"])
class DeforestTest(unittest.TestCase):
    def setUp(self):
        self.game_registry = GameRegistry(generate_test_db())
        self.event_system = MockEventSystem()
        self.handler = GameHandler(self.game_registry, self.event_system)

    def test_deforest_from_non_existant_game_returns_not_found(self):
        with self.assertRaises(ResourceNotFoundException) as context:
            self.handler.action_deforest(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "y": 0
                }))

        self.assertEqual("Game not found", context.exception.message)

    def test_deforest_for_game_we_are_not_part_of_returns_not_found(self):
        self.game_registry.create_game("123", GAME_ID)

        with self.assertRaises(ResourceNotFoundException) as context:
            self.handler.action_deforest(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "y": 0
                }))

        self.assertEqual("Game not found", context.exception.message)

    def test_deforest_with_non_int_parameter_returns_bad_request(self):
        self.game_registry.create_game(CLIENT_ID, GAME_ID)

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_deforest(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": "0",
                    "y": 0
                }))
        self.assertEqual("Invalid parameters", context.exception.message)

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_deforest(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "y": "0"
                }))
        self.assertEqual("Invalid parameters", context.exception.message)

    def test_deforest_with_missing_parameter_returns_bad_request(self):
        self.game_registry.create_game(CLIENT_ID, GAME_ID)

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_deforest(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {"y": 0}))
        self.assertEqual("Invalid parameters", context.exception.message)

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_deforest(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {"x": 0}))
        self.assertEqual("Invalid parameters", context.exception.message)

    def test_deforest_removes_forest_for_that_tile_and_increments_player_wood(
            self):
        game = self.game_registry.create_game(CLIENT_ID, GAME_ID)
        world = game.get_world()
        world.set_size(5, 5)
        world.persist()

        resp = self.handler.action_deforest(
            Request(CLIENT_ID, {"game_id": GAME_ID}, {
                "x": 0,
                "y": 0
            }))

        self.assertEqual(resp, {})
        game = self.game_registry.get_game_for_id(GAME_ID)
        player = game.get_player_for_client_id(CLIENT_ID)
        self.assertEqual(10, player.stats.wood)
        resp = self.handler.get_world(Request(CLIENT_ID, {"game_id": GAME_ID}))
        expected_tiles = [
            [2, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
        ]
        self.assertEqual(expected_tiles, resp["tileData"])
class BuildTest(unittest.TestCase):
    def setUp(self):
        self.game_registry = GameRegistry(generate_test_db())
        self.event_system = MockEventSystem()
        self.handler = GameHandler(self.game_registry, self.event_system)

    def test_build_from_non_existant_game_returns_not_found(self):
        with self.assertRaises(ResourceNotFoundException) as context:
            self.handler.action_build(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "y": 0,
                    "building_id": 1
                }))

        self.assertEqual("Game not found", context.exception.message)

    def test_build_for_game_we_are_not_part_of_returns_not_found(self):
        self.game_registry.create_game("123", GAME_ID)

        with self.assertRaises(ResourceNotFoundException) as context:
            self.handler.action_build(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "y": 0,
                    "building_id": 1
                }))

        self.assertEqual("Game not found", context.exception.message)

    def test_build_missing_parameters_returns_bad_request(self):
        self.game_registry.create_game(CLIENT_ID, GAME_ID)

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_build(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "y": 0,
                    "building_id": 1
                }))
        self.assertEqual("Invalid parameters", context.exception.message)

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_build(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "building_id": 0
                }))
        self.assertEqual("Invalid parameters", context.exception.message)

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_build(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "y": 0
                }))
        self.assertEqual("Invalid parameters", context.exception.message)

    def test_build_for_non_int_parameters_returns_bad_request(self):
        self.game_registry.create_game(CLIENT_ID, GAME_ID)

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_build(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "y": 0,
                    "building_id": "1"
                }))
        self.assertEqual("Invalid parameters", context.exception.message)

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_build(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "y": "0",
                    "building_id": 0
                }))
        self.assertEqual("Invalid parameters", context.exception.message)

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_build(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": "0",
                    "y": 0,
                    "building_id": 0
                }))
        self.assertEqual("Invalid parameters", context.exception.message)

    def test_build_for_non_existant_building_returns_not_found(self):
        self.game_registry.create_game(CLIENT_ID, GAME_ID)

        with self.assertRaises(ResourceNotFoundException) as context:
            self.handler.action_build(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "y": 0,
                    "building_id": 99
                }))
        self.assertEqual("Building not found: 99", context.exception.message)

    def test_build_on_non_clearing_returns_bad_request(self):
        game = self.game_registry.create_game(CLIENT_ID, GAME_ID)
        world = game.get_world()
        world.set_size(5, 5)
        world.persist()
        player = game.get_player_for_client_id(CLIENT_ID)
        player.stats.wood = 40
        player.persist()

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_build(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "y": 0,
                    "building_id": 1
                }))
        self.assertEqual("Tile is not a clearing", context.exception.message)

    def test_build_on_existing_building_returns_bad_request(self):
        game = self.game_registry.create_game(CLIENT_ID, GAME_ID)
        world = game.get_world()
        world.set_size(5, 5)
        world.set_tile_at(0, 0, 2)
        world.set_building_at(0, 0, 1, "123")
        world.persist()
        player = game.get_player_for_client_id(CLIENT_ID)
        player.stats.wood = 40
        player.persist()

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_build(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "y": 0,
                    "building_id": 1
                }))
        self.assertEqual("Tile already contains building",
                         context.exception.message)

    def test_build_with_not_enough_money_returns_bad_request(self):
        game = self.game_registry.create_game(CLIENT_ID, GAME_ID)
        world = game.get_world()
        world.set_size(5, 5)
        world.set_tile_at(0, 0, 2)
        world.persist()
        player = game.get_player_for_client_id(CLIENT_ID)
        player.stats.wood = 10
        player.persist()

        with self.assertRaises(BadRequestException) as context:
            self.handler.action_build(
                Request(CLIENT_ID, {"game_id": GAME_ID}, {
                    "x": 0,
                    "y": 0,
                    "building_id": 1
                }))
        self.assertEqual("Not enough money", context.exception.message)

    def test_build_removes_clearing_for_that_tile_and_sets_building_and_decrements_player_resource(
            self):
        game = self.game_registry.create_game(CLIENT_ID, GAME_ID)
        world = game.get_world()
        world.set_size(5, 5)
        world.set_tile_at(0, 0, 2)
        world.persist()
        player = game.get_player_for_client_id(CLIENT_ID)
        player.stats.wood = 40
        player.persist()

        resp = self.handler.action_build(
            Request(CLIENT_ID, {"game_id": GAME_ID}, {
                "x": 0,
                "y": 0,
                "building_id": 1
            }))

        self.assertEqual(resp, {})
        game = self.game_registry.get_game_for_id(GAME_ID)
        player = game.get_player_for_client_id(CLIENT_ID)
        self.assertEqual(20, player.stats.wood)
        resp = self.handler.get_world(Request(CLIENT_ID, {"game_id": GAME_ID}))
        expected_tiles = [
            [0, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
        ]
        self.assertEqual(expected_tiles, resp["tileData"])
        expected_buildings = [{"x": 0, "y": 0, "id": 1, "owner_id": "0"}]
        self.assertEqual(expected_buildings, resp["buildings"])