import json
import pathlib
import unittest
from unittest.mock import patch

from elironwars.mob import BaseMob, load_character, save_character
from elironwars.mob.default_builder import build_character

ARTHUR_JSON = """{
    "name": "Arthur",
    "max_pv": 100,
    "current_pv": 100,
    "strength": 20,
    "protection": 10,
    "speed": 5,
    "mob_type": 0
}"""

ARTHUR_FILE = pathlib.Path('Arthur.json')


class TestCharacterBuilder(unittest.TestCase):

    @classmethod
    def tearDownClass(cls):
        ARTHUR_FILE.unlink(missing_ok=True)

    @patch("builtins.input")
    def test_build_character(self, mock_input):
        # Arrange
        mock_input.side_effect = [
            "Arthur",  # name
            "100",  # max_pv
            "20",  # strength
            "10",  # protection
            "5"  # speed
        ]

        # Act
        character = build_character()

        # Assert
        self.assertIsInstance(character, BaseMob)
        self.assertEqual(character.name, "Arthur")
        self.assertEqual(character.max_pv, 100)
        self.assertEqual(character.strength, 20)
        self.assertEqual(character.protection, 10)
        self.assertEqual(character.speed, 5)
        self.assertEqual(character.mob_type, 0)

    def test_save_character(self):
        # Arrange
        character = BaseMob(
            name="Arthur",
            max_pv=100,
            strength=20,
            protection=10,
            speed=5,
            mob_type=0,
        )

        # Act
        save_character(character)

        # Assert
        self.assertTrue(ARTHUR_FILE.exists())
        self.assertEqual(ARTHUR_JSON, ARTHUR_FILE.read_text(encoding='utf-8'))

    def test_load_character_file_not_found(self):
        # Act
        result = load_character("Lancelot")

        # Assert
        self.assertIsNone(result)

    def test_load_character_success(self):
        # Arrange
        ARTHUR_FILE.write_text(ARTHUR_JSON, encoding='utf-8')

        # Act
        character = load_character("Arthur")

        # Assert
        self.assertIsNotNone(character)
        self.assertEqual(character.name, "Arthur")
        self.assertEqual(character.max_pv, 100)
        self.assertEqual(character.strength, 20)
        self.assertEqual(character.protection, 10)
        self.assertEqual(character.speed, 5)
        self.assertEqual(character.mob_type, 0)

    def test_load_character_missing_keys(self):
        arthur_dict: dict = json.loads(ARTHUR_JSON)

        for key in arthur_dict:
            with self.subTest(f'test without key "{key}"'):
                # Arrange
                invalid_dict = arthur_dict.copy()
                invalid_dict.pop(key)
                ARTHUR_FILE.write_text(json.dumps(
                    invalid_dict), encoding='utf-8')

                # Act
                result = load_character("Arthur")

                # Assert
                self.assertIsNone(result)

    def test_load_character_invalid_json(self):
        # Arrange
        ARTHUR_FILE.write_text(ARTHUR_JSON[1:], encoding='utf-8')

        # Act
        result = load_character("Arthur")

        # Assert
        self.assertIsNone(result)


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