import unittest
from aiotelegram.types import *


class UserTest(unittest.TestCase):
    def test_fromJson_all_fields(self):
        user = User.fromJson('{"id": 1, "first_name": "John", "last_name": "Doe", "username": "@johndoe"}')
        self.assertEqual(user.id, 1)
        self.assertEqual(user.first_name, "John")
        self.assertEqual(user.last_name, "Doe")
        self.assertEqual(user.username, "@johndoe")

    def test_fromJson_without_optional(self):
        user = User.fromJson('{"id": 1, "first_name": "John"}')
        self.assertEqual(user.id, 1)
        self.assertEqual(user.first_name, "John")
        self.assertIsNone(user.last_name)
        self.assertIsNone(user.username)

    def test_init_all_fields(self):
        user = User(1, "John", "Doe", "@johndoe")
        self.assertEqual(user.id, 1)
        self.assertEqual(user.first_name, "John")
        self.assertEqual(user.last_name, "Doe")
        self.assertEqual(user.username, "@johndoe")

    def test_fromJson_forget_required(self):
        self.assertRaises(TypeError, User.fromJson,
                          '{"first_name": "John", "last_name": "Doe", "username": "@johndoe"}')

class ChatTest(unittest.TestCase):
    def test_fromJson_all_fields(self):
        chat = Chat.fromJson(
            '''{"id": 1, "type": "group", "title": "Test group",
             "username": "@johndoe", "first_name": "John", "last_name": "Doe"}'''
        )
        self.assertEqual(chat.id, 1)
        self.assertEqual(chat.type, "group")
        self.assertEqual(chat.title, "Test group")
        self.assertEqual(chat.username, "@johndoe")
        self.assertEqual(chat.first_name, "John")
        self.assertEqual(chat.last_name, "Doe")

    def test_fromJson_without_optional(self):
        chat = Chat.fromJson('{"id": 1, "type": "group"}')
        self.assertEqual(chat.id, 1)
        self.assertEqual(chat.type, "group")
        self.assertIsNone(chat.title)
        self.assertIsNone(chat.username)
        self.assertIsNone(chat.first_name)
        self.assertIsNone(chat.last_name)

    def test_init_all_fields(self):
        chat = Chat(id=1, type="group", title="Test group",
                    username="@johndoe", first_name="John", last_name="Doe")
        self.assertEqual(chat.id, 1)
        self.assertEqual(chat.type, "group")
        self.assertEqual(chat.title, "Test group")
        self.assertEqual(chat.username, "@johndoe")
        self.assertEqual(chat.first_name, "John")
        self.assertEqual(chat.last_name, "Doe")


class PhotoSizeTest(unittest.TestCase):
    def test_fromJson_all_fields(self):
        photo_size = PhotoSize.fromJson(
            '''{"file_id": "id123", "width": 800, "height": 600,
             "file_size": 123456}'''
        )
        self.assertEqual(photo_size.file_id, "id123")
        self.assertEqual(photo_size.width, 800)
        self.assertEqual(photo_size.height, 600)
        self.assertEqual(photo_size.file_size, 123456)

    def test_fromJson_without_optional(self):
        photo_size = PhotoSize.fromJson('{"file_id": "id123", "width": 800, "height": 600}')
        self.assertEqual(photo_size.file_id, "id123")
        self.assertEqual(photo_size.width, 800)
        self.assertEqual(photo_size.height, 600)
        self.assertIsNone(photo_size.file_size)

    def test_init_all_fields(self):
        photo_size = PhotoSize(file_id="id123", width=800, height=600, file_size=123456)
        self.assertEqual(photo_size.file_id, "id123")
        self.assertEqual(photo_size.width, 800)
        self.assertEqual(photo_size.height, 600)
        self.assertEqual(photo_size.file_size, 123456)


class AudioTest(unittest.TestCase):
    def test_fromJson_all_fields(self):
        audio = Audio.fromJson(
            '''{"file_id": "id12345", "duration": 253, "performer": "Amy Nuttall",
             "title": "Greensleeves", "mime_type": "audio/ogg", "file_size": 3940000}'''
        )
        self.assertEqual(audio.file_id, "id12345")
        self.assertEqual(audio.duration, 253)
        self.assertEqual(audio.performer, "Amy Nuttall")
        self.assertEqual(audio.title, "Greensleeves")
        self.assertEqual(audio.mime_type, "audio/ogg")
        self.assertEqual(audio.file_size, 3940000)

    def test_fromJson_without_optional(self):
        audio = Audio.fromJson('{"file_id": "id12345", "duration": 253}')
        self.assertEqual(audio.file_id, "id12345")
        self.assertEqual(audio.duration, 253)
        self.assertIsNone(audio.performer)
        self.assertIsNone(audio.title)
        self.assertIsNone(audio.mime_type)
        self.assertIsNone(audio.file_size)

    def test_init_all_fields(self):
        audio = Audio(file_id="id12345", duration=253, performer="Amy Nuttall",
                      title="Greensleeves", mime_type="audio/ogg", file_size=3940000)
        self.assertEqual(audio.file_id, "id12345")
        self.assertEqual(audio.duration, 253)
        self.assertEqual(audio.performer, "Amy Nuttall")
        self.assertEqual(audio.title, "Greensleeves")
        self.assertEqual(audio.mime_type, "audio/ogg")
        self.assertEqual(audio.file_size, 3940000)


class DocumentTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.photo_size = PhotoSize(file_id="id123", width=800, height=600, file_size=123456)

    def test_fromJson_all_fields(self):
        document = Document.fromJson('''{"file_id": "id12345",
        "thumb": {
            "file_id": "id123", "width": 800, "height": 600,
            "file_size": 123456
        }, "file_name": "document.pdf", "mime_type": "application/pdf", "file_size": 654321}''')
        self.assertEqual(document.file_id, 'id12345')
        self.assertEqual(document.thumb, self.photo_size)
        self.assertEqual(document.file_name, 'document.pdf')
        self.assertEqual(document.mime_type, 'application/pdf')
        self.assertEqual(document.file_size, 654321)

    def test_fromJson_without_optional(self):
        document = Document.fromJson('{"file_id": "id12345"}')
        self.assertEqual(document.file_id, 'id12345')
        self.assertIsNone(document.thumb)
        self.assertIsNone(document.file_name)
        self.assertIsNone(document.mime_type)
        self.assertIsNone(document.file_size)

    def test_init_all_fields(self):
        document = Document(file_id='id12345',
            thumb=self.photo_size, file_name='document.pdf',
            mime_type='application/pdf', file_size=654321)
        self.assertEqual(document.file_id, 'id12345')
        self.assertEqual(document.thumb, self.photo_size)
        self.assertEqual(document.file_name, 'document.pdf')
        self.assertEqual(document.mime_type, 'application/pdf')
        self.assertEqual(document.file_size, 654321)


class StickerTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.photo_size = PhotoSize(file_id="id123", width=800, height=600, file_size=123456)

    def test_fromJson_all_fields(self):
        sticker = Sticker.fromJson('''{"file_id": "id12345",
            "width": 800, "height": 600,
            "thumb": %s, "file_size": 654321}''' % self.photo_size.toJson())
        self.assertEqual(sticker.file_id, 'id12345')
        self.assertEqual(sticker.width, 800)
        self.assertEqual(sticker.height, 600)
        self.assertEqual(sticker.thumb, self.photo_size)
        self.assertEqual(sticker.file_size, 654321)

    def test_fromJson_without_optional(self):
        sticker = Sticker.fromJson('''{"file_id": "id12345",
            "width": 800, "height": 600}''')
        self.assertEqual(sticker.file_id, 'id12345')
        self.assertEqual(sticker.width, 800)
        self.assertEqual(sticker.height, 600)
        self.assertIsNone(sticker.thumb)
        self.assertIsNone(sticker.file_size)


class VideoTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.photo_size = PhotoSize(file_id="id123", width=800, height=600, file_size=123456)

    def test_fromJson_all_fields(self):
        video = Video.fromJson('''{"file_id": "id12345",
            "width": 800, "height": 600, "duration": 120,
            "thumb": %s, "mime_type": "video/mp4", "file_size": 654321}'''
                               % self.photo_size.toJson())
        self.assertEqual(video.file_id, 'id12345')
        self.assertEqual(video.width, 800)
        self.assertEqual(video.height, 600)
        self.assertEqual(video.duration, 120)
        self.assertEqual(video.thumb, self.photo_size)
        self.assertEqual(video.mime_type, "video/mp4")
        self.assertEqual(video.file_size, 654321)

    def test_fromJson_without_optional(self):
        video = Video.fromJson('''{"file_id": "id12345",
            "width": 800, "height": 600, "duration": 120}''')
        self.assertEqual(video.file_id, 'id12345')
        self.assertEqual(video.width, 800)
        self.assertEqual(video.height, 600)
        self.assertEqual(video.duration, 120)
        self.assertIsNone(video.thumb)
        self.assertIsNone(video.mime_type)
        self.assertIsNone(video.file_size)


class VoiceTest(unittest.TestCase):
    def test_fromJson_all_fields(self):
        voice = Voice.fromJson(
            '''{"file_id": "id12345", "duration": 253,
            "mime_type": "audio/ogg", "file_size": 3940000}'''
        )
        self.assertEqual(voice.file_id, "id12345")
        self.assertEqual(voice.duration, 253)
        self.assertEqual(voice.mime_type, "audio/ogg")
        self.assertEqual(voice.file_size, 3940000)

    def test_fromJson_without_optional(self):
        audio = Audio.fromJson('{"file_id": "id12345", "duration": 253}')
        self.assertEqual(audio.file_id, "id12345")
        self.assertEqual(audio.duration, 253)
        self.assertIsNone(audio.mime_type)
        self.assertIsNone(audio.file_size)


class ContactTest(unittest.TestCase):
    def test_fromJson_all_fields(self):
        contact = Contact.fromJson(
            '''{"phone_number": "+12345678", "first_name": "John",
            "last_name": "Doe", "user_id": 1234}'''
        )
        self.assertEqual(contact.phone_number, '+12345678')
        self.assertEqual(contact.first_name, 'John')
        self.assertEqual(contact.last_name, 'Doe')
        self.assertEqual(contact.user_id, 1234)

    def test_fromJson_without_optional(self):
        contact = Contact.fromJson(
            '{"phone_number": "+12345678", "first_name": "John"}'
        )
        self.assertEqual(contact.phone_number, '+12345678')
        self.assertEqual(contact.first_name, 'John')
        self.assertIsNone(contact.last_name)
        self.assertIsNone(contact.user_id)


class LocationTest(unittest.TestCase):
    def test_fromJson_all_fields(self):
        location = Location.fromJson('{"longitude": 29.471111, "latitude": 46.830556}')
        self.assertEqual(location.longitude, 29.471111)
        self.assertEqual(location.latitude, 46.830556)

    def test_fromJson_int_fields(self):
        location = Location.fromJson('{"longitude": 29, "latitude": 46}')
        self.assertEqual(location.longitude, 29)
        self.assertEqual(location.latitude, 46)


class UserProfilePhotosTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.ps1 = PhotoSize(file_id="id1", width=100, height=100, file_size=1000)
        cls.ps2 = PhotoSize(file_id="id2", width=200, height=200, file_size=2000)
        cls.ps3 = PhotoSize(file_id="id3", width=300, height=300, file_size=3000)
        cls.ps4 = PhotoSize(file_id="id4", width=400, height=400, file_size=4000)

    def test_fromJson_all_fields(self):
        upp = UserProfilePhotos.fromJson('''
            {
                "total_count": 2,
                "photos": [[%s, %s], [%s, %s]]
            }
            ''' % (self.ps1.toJson(), self.ps2.toJson(), self.ps3.toJson(), self.ps4.toJson()))
        self.assertEqual(upp.total_count, 2)
        self.assertEqual(upp.photos[0][0], self.ps1)


class FileTest(unittest.TestCase):
    def test_fromJson_all_fields(self):
        f = File.fromJson(
            '''
            {
                "file_id": "id123",
                "file_size": 123456,
                "file_path": "a/file.pdf"
            }
            '''
        )
        self.assertEqual(f.file_id, "id123")
        self.assertEqual(f.file_size, 123456)
        self.assertEqual(f.file_path, "a/file.pdf")

    def test_fromJson_without_optional(self):
        f = File.fromJson('{"file_id": "id123"}')
        self.assertEqual(f.file_id, "id123")
        self.assertIsNone(f.file_size)
        self.assertIsNone(f.file_path)


class ReplyKeyboardMarkupTest(unittest.TestCase):
    def test_fromJson_all_fields(self):
        rkm = ReplyKeyboardMarkup.fromJson(
            '''{
                "keyboard": [["A", "B"], ["C", "D"]],
                "resize_keyboard": true,
                "one_time_keyboard": true,
                "selective": true
            }'''
        )

        self.assertEqual(rkm.keyboard, [['A', 'B'],['C', 'D']])
        self.assertTrue(rkm.resize_keyboard)
        self.assertTrue(rkm.one_time_keyboard)
        self.assertTrue(rkm.selective)

    def test_fromJson_without_optional(self):
        rkm = ReplyKeyboardMarkup.fromJson('{"keyboard": [["A", "B"], ["C", "D"]]}')

        self.assertEqual(rkm.keyboard, [['A', 'B'],['C', 'D']])
        self.assertIsNone(rkm.resize_keyboard)
        self.assertIsNone(rkm.one_time_keyboard)
        self.assertIsNone(rkm.selective)

class ReplyKeyboardHideTest(unittest.TestCase):
     def test_fromJson_all_fields(self):
         rkh = ReplyKeyboardHide.fromJson(
             '''{
                "hide_keyboard": true,
                "selective": true
             }'''
         )
         self.assertTrue(rkh.hide_keyboard)
         self.assertTrue(rkh.selective)

     def test_fromJson_without_optional(self):
         rkh = ReplyKeyboardHide.fromJson('{"hide_keyboard": true}')
         self.assertTrue(rkh.hide_keyboard)
         self.assertIsNone(rkh.selective)

     def test_fromJson_without_optional_hide_false(self):
         with self.assertRaises(ValueError):
             rkh = ReplyKeyboardHide.fromJson('{"hide_keyboard": false}')

class ForceReplyTest(unittest.TestCase):
     def test_fromJson_all_fields(self):
         fr = ForceReply.fromJson(
             '''{
                "force_reply": true,
                "selective": true
             }'''
         )
         self.assertTrue(fr.force_reply)
         self.assertTrue(fr.selective)

     def test_fromJson_without_optional(self):
         fr = ForceReply.fromJson('{"force_reply": true}')
         self.assertTrue(fr.force_reply)
         self.assertIsNone(fr.selective)

     def test_fromJson_without_optional_hide_false(self):
         with self.assertRaises(ValueError):
             ForceReply.fromJson('{"force_reply": false}')


class MessageTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.chat = Chat.fromObject({'id': 1, 'type': 'private'})

    def test_init_without_optional(self):
        msg1 = Message(message_id=1, date=1234, chat=self.chat)
        self.assertEqual(msg1.message_id, 1)
        self.assertEqual(msg1.date, 1234)
        self.assertEqual(msg1.chat, self.chat)

    def test_init_without_optional_other_message(self):
        msg1 = Message(message_id=1, date=1234, chat=self.chat)
        msg2 = Message(message_id=2, date=1235, chat=self.chat, reply_to_message=msg1)
        self.assertEqual(msg2.message_id, 2)
        self.assertEqual(msg2.date, 1235)
        self.assertEqual(msg2.chat, self.chat)
        self.assertEqual(msg2.reply_to_message, msg1)

    def test_init_without_optional_always_true_fields(self):
        self.assertRaises(ValueError, Message,
                          message_id=1, date=1234, chat=self.chat,
                          delete_chat_photo=False)
        self.assertRaises(ValueError, Message,
                          message_id=1, date=1234, chat=self.chat,
                          group_chat_created=False)
        self.assertRaises(ValueError, Message,
                          message_id=1, date=1234, chat=self.chat,
                          supergroup_chat_created=False)
        self.assertRaises(ValueError, Message,
                          message_id=1, date=1234, chat=self.chat,
                          channel_chat_created=False)
