import json


class PermissionnMixin:

    def __init__(self):
        self.permissions = set()

    def grant_permission(self, permission):
        self.permissions.add(permission)

    def revoke_permission(self, permission):
        self.permissions.discard(permission)

    def has_permission(self, permission):
        return permission in self.permissions
    

class User(PermissionnMixin):

    def __init__(self, name, email):
        super().__init__()
        self.name = name
        self.email = email

# --------------------------------------------------

class JsonSerializableMixin:

    def to_json(self):
        return json.dumps(self.__dict__)


class Car(JsonSerializableMixin):
    def __init__(self, make: str, color: str):
        self.make = make
        self.color = color

# --------------------------------------------------

class DictMixin:

    def to_dict(self):
        foo = json.dumps(self, default = lambda x:x.__dict__)
        return json.loads(foo)

class Phone(DictMixin):
    def __init__(self, number):
        self.number = number

class Person(DictMixin):
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address


class Address(DictMixin):
    def __init__(self, street, city, state, zip_code):
        self.street = street
        self.city = city
        self.state = state
        self.zip_code = zip_code


class Company(DictMixin):
    def __init__(self, name, address):
        self.name = name
        self.address = address


def main():

    # car = Car("Toyota", "red")
    # print(car.__dict__)
    # print(vars(car))
    # # print(car.to_json())
    # assert car.to_json() == '{"make": "Toyota", "color": "red"}'

    address = Address("123 Main St", "Anytown", "CA", "12345")
    john_doe = Person("John Doe", 30, address)

    john_doe_dict = john_doe.to_dict()

    print(john_doe_dict)
    print(type(john_doe_dict))

    assert john_doe_dict == {
        'name': 'John Doe',
        'age': 30,
        'address': {
            'street': '123 Main St',
            'city': 'Anytown',
            'state': 'CA',
            'zip_code': '12345'
        }
    }

    address = Address("123 Main St", "Albuquerque", "NM", "987654")
    assert address.to_dict() == {
        'street': '123 Main St',
        'city': 'Albuquerque',
        'state': 'NM',
        'zip_code': '987654'
    }
    walter = Person("Walter White", 30, address)
    assert walter.to_dict() == {'address': {'city': 'Albuquerque',
                                            'state': 'NM',
                                            'street': '123 Main St',
                                            'zip_code': '987654'},
                                'age': 30,
                                'name': 'Walter White'}

    walter_phone = Phone("555-1234")
    walter.phone = walter_phone
    assert walter.to_dict() == {'address': {'city': 'Albuquerque',
                                            'state': 'NM',
                                            'street': '123 Main St',
                                            'zip_code': '987654'},
                                'age': 30,
                                'name': 'Walter White',
                                'phone': {'number': '555-1234'}}

    company_address = Address("3828 Piermont Dr", "Albuquerque", "NM", "12345")
    company = Company("SCHOOL", company_address)

    assert company.to_dict() == {'address': {'city': 'Albuquerque',
                                            'state': 'NM',
                                            'street': '3828 Piermont Dr',
                                            'zip_code': '12345'},
                                'name': 'SCHOOL'}

    jesse_address = Address("456 Oak St", "Albuquerque", "NM", "12345")
    jesse = Person("Jesse Bruce Pinkman", 27, jesse_address)
    jesse.phone = Phone("555-5678")

    fring = Person("Gustavo Fring", 55, Address("Los Pollos Hermanos", "Albuquerque", "NM", "12345"))
    fring.friends = [walter, jesse]

    assert fring.to_dict() == {'address': {'city': 'Albuquerque',
                                        'state': 'NM',
                                        'street': 'Los Pollos Hermanos',
                                        'zip_code': '12345'},
                            'age': 55,
                            'friends': [{'address': {'city': 'Albuquerque',
                                                        'state': 'NM',
                                                        'street': '123 Main St',
                                                        'zip_code': '987654'},
                                            'age': 30,
                                            'name': 'Walter White',
                                            'phone': {'number': '555-1234'}},
                                        {'address': {'city': 'Albuquerque',
                                                        'state': 'NM',
                                                        'street': '456 Oak St',
                                                        'zip_code': '12345'},
                                            'age': 27,
                                            'name': 'Jesse Bruce Pinkman',
                                            'phone': {'number': '555-5678'}}],
                            'name': 'Gustavo Fring'}

    print('Good')

    '''
    assert john_doe_dict == {
        'name': 'John Doe',
        'age': 30,
        'address': {
            'street': '123 Main St',
            'city': 'Anytown',
            'state': 'CA',
            'zip_code': '12345'
        }
    }
    '''

    '''
    user1 = User('Alice', 'alice@example.com')
    user2 = User('Bob', 'bob@example.com')

    assert user1.email == 'alice@example.com'
    assert user1.name == 'Alice'
    assert user1.permissions == set()

    assert user2.email == 'bob@example.com'
    assert user2.name == 'Bob'
    assert user2.permissions == set()

    user1.grant_permission('read')
    user1.grant_permission('write')
    user2.grant_permission('read')
    assert user1.permissions == {'read', 'write'}
    assert user2.permissions == {'read'}

    assert user1.has_permission('read') is True
    assert user1.has_permission('write') is True
    assert user1.has_permission('execute') is False

    assert user2.has_permission('read') is True
    assert user2.has_permission('write') is False
    assert user2.has_permission('execute') is False

    user1.revoke_permission('write')
    user1.revoke_permission('execute')

    assert user1.has_permission('read') is True
    assert user1.has_permission('write') is False
    assert user1.has_permission('execute') is False

    print('Good')
    '''


if __name__ == '__main__':
    main()