# Path: models.py
# class Address(BaseModel):
#     """
#     The model Address represent a user address.
#     Each address is releated to one user, but one user can have
#     more addresses.
# 
#     Attributes:
#         uuid (UUID): Address unique uuid
#         user (:any:`User`): Foreign key pointing to the user `owner` of the address
#         country (str): Country for the address, i.e. ``Italy``
#         city (str): City name
#         post_code (str): Postal code for the address
#         address (str): Full address for the Address resource
#         phone (str): Phone number for the Address
#     """
#     uuid = UUIDField(unique=True)
#     user = ForeignKeyField(User, related_name='addresses')
#     country = CharField()
#     city = CharField()
#     post_code = CharField()
#     address = CharField()
#     phone = CharField()
# 
#     _schema = AddressSchema
# 
# class User(BaseModel, UserMixin):
#     """
#     User represents an user for the application.
# 
#     Attributes:
#         first_name (str): User's first name
#         last_name (str): User's last name
#         email (str): User's **valid** email
#         password (str): User's password
#         admin (bool): User's admin status. Defaults to ``False``
# 
#     .. NOTE::
#         Each User resource must have an unique `email` field, meaning
#         that there cannot be two user's registered with the same email.
# 
#         For this reason, when checking for user's existence, the server requires
#         either the `uuid` of the user or its `email`.
#     """
#     uuid = UUIDField(unique=True)
#     first_name = CharField()
#     last_name = CharField()
#     email = CharField(unique=True)
#     password = CharField()
#     admin = BooleanField(default=False)
#     _schema = UserSchema
# 
#     @staticmethod
#     def exists(email):
#         """
#         Check that an user exists by checking the email field.
# 
#         Args:
#             email (str): User's email to check
#         """
#         try:
#             User.get(User.email == email)
#         except User.DoesNotExist:
#             return False
#         return True
# 
#     @staticmethod
#     def hash_password(password):
#         """
#         Use passlib to get a crypted password.
# 
#         Args:
#             password (str): password to hash
# 
#         Returns:
#             str: hashed password
#         """
#         return pbkdf2_sha256.hash(password)
# 
#     def verify_password(self, password):
#         """
#         Verify a clear password against the stored hashed password of the user
#         using passlib.
# 
#         Args:
#             password (str): Password to verify against the hashed stored password
#         Returns:
#             bool: wether the given email matches the stored one
#         """
#         return pbkdf2_sha256.verify(password, self.password)
# 
#     def add_favorite(user, item):
#         """Link the favorite item to user."""
#         return Favorite.create(
#             uuid=uuid4(),
#             item=item,
#             user=user,
#         )
# 
#     def delete_favorite(self, obj):
#         obj.delete_instance()
# 
# class Favorite(BaseModel):
#     """ Many to many table to relate an item with a user."""
#     uuid = UUIDField(unique=True)
#     user = ForeignKeyField(User, related_name="favorites")
#     item = ForeignKeyField(Item, related_name="favorites")
#     _schema = FavoriteSchema
# 
# class Item(BaseModel):
#     """
#     Item describes a product for the e-commerce platform.
# 
#     Attributes:
#         uuid (UUID): Item UUID
#         name (str): Name for the product
#         price (decimal.Decimal): Price for a single product
#         description (str): Product description
#         availability (int): Quantity of items available
#         category (str): Category group of the item
# 
#     """
#     uuid = UUIDField(unique=True)
#     name = CharField()
#     price = DecimalField(auto_round=True)
#     description = TextField()
#     availability = IntegerField()
#     category = TextField()
#     _schema = ItemSchema
#     _search_attributes = ['name', 'category', 'description']
# 
#     def __str__(self):
#         return '{}, {}, {}, {}'.format(
#             self.uuid,
#             self.name,
#             self.price,
#             self.description)
# 
#     def is_favorite(self, item):
#         for f in self.favorites:
#             if f.item_id == item.id:
#                 return True
#         return False
# 
# Path: utils.py
# def get_image_folder():
#     return os.path.join(get_project_root(), IMAGE_FOLDER)


from functools import reduce
from base64 import b64encode
from models import Address, User, Favorite, Item
from utils import get_image_folder
import datetime
import inspect
import json
import os
import random
import shutil
import sys
import uuid
# ###########################################################
# Peewee models helpers
# Functions to create new instances with overridable defaults


def add_user(email, password, id=None, first_name='John', last_name='Doe'):
    """
    Create a single user in the test database.
    If an email is provided it will be used, otherwise it will be generated
    by the function before adding the User to the database.
    """
    email = email or 'johndoe{}@email.com'.format(int(random.random() * 100))

    return User.create(
        first_name=first_name,
        last_name=last_name,
        email=email,
        password=User.hash_password(password),
        uuid=id or uuid.uuid4(),
    )


def add_admin_user(email, psw, id=None):
    """
    Create a single user in the test database.
    If an email is provided it will be used, otherwise it will be generated
    by the function before adding the User to the database.
    """
    email = email or 'johndoe{}@email.com'.format(int(random.random() * 100))


# Path: models.py
# class Address(BaseModel):
#     """
#     The model Address represent a user address.
#     Each address is releated to one user, but one user can have
#     more addresses.
# 
#     Attributes:
#         uuid (UUID): Address unique uuid
#         user (:any:`User`): Foreign key pointing to the user `owner` of the address
#         country (str): Country for the address, i.e. ``Italy``
#         city (str): City name
#         post_code (str): Postal code for the address
#         address (str): Full address for the Address resource
#         phone (str): Phone number for the Address
#     """
#     uuid = UUIDField(unique=True)
#     user = ForeignKeyField(User, related_name='addresses')
#     country = CharField()
#     city = CharField()
#     post_code = CharField()
#     address = CharField()
#     phone = CharField()
# 
#     _schema = AddressSchema
# 
# class User(BaseModel, UserMixin):
#     """
#     User represents an user for the application.
# 
#     Attributes:
#         first_name (str): User's first name
#         last_name (str): User's last name
#         email (str): User's **valid** email
#         password (str): User's password
#         admin (bool): User's admin status. Defaults to ``False``
# 
#     .. NOTE::
#         Each User resource must have an unique `email` field, meaning
#         that there cannot be two user's registered with the same email.
# 
#         For this reason, when checking for user's existence, the server requires
#         either the `uuid` of the user or its `email`.
#     """
#     uuid = UUIDField(unique=True)
#     first_name = CharField()
#     last_name = CharField()
#     email = CharField(unique=True)
#     password = CharField()
#     admin = BooleanField(default=False)
#     _schema = UserSchema
# 
#     @staticmethod
#     def exists(email):
#         """
#         Check that an user exists by checking the email field.
# 
#         Args:
#             email (str): User's email to check
#         """
#         try:
#             User.get(User.email == email)
#         except User.DoesNotExist:
#             return False
#         return True
# 
#     @staticmethod
#     def hash_password(password):
#         """
#         Use passlib to get a crypted password.
# 
#         Args:
#             password (str): password to hash
# 
#         Returns:
#             str: hashed password
#         """
#         return pbkdf2_sha256.hash(password)
# 
#     def verify_password(self, password):
#         """
#         Verify a clear password against the stored hashed password of the user
#         using passlib.
# 
#         Args:
#             password (str): Password to verify against the hashed stored password
#         Returns:
#             bool: wether the given email matches the stored one
#         """
#         return pbkdf2_sha256.verify(password, self.password)
# 
#     def add_favorite(user, item):
#         """Link the favorite item to user."""
#         return Favorite.create(
#             uuid=uuid4(),
#             item=item,
#             user=user,
#         )
# 
#     def delete_favorite(self, obj):
#         obj.delete_instance()
# 
# class Favorite(BaseModel):
#     """ Many to many table to relate an item with a user."""
#     uuid = UUIDField(unique=True)
#     user = ForeignKeyField(User, related_name="favorites")
#     item = ForeignKeyField(Item, related_name="favorites")
#     _schema = FavoriteSchema
# 
# class Item(BaseModel):
#     """
#     Item describes a product for the e-commerce platform.
# 
#     Attributes:
#         uuid (UUID): Item UUID
#         name (str): Name for the product
#         price (decimal.Decimal): Price for a single product
#         description (str): Product description
#         availability (int): Quantity of items available
#         category (str): Category group of the item
# 
#     """
#     uuid = UUIDField(unique=True)
#     name = CharField()
#     price = DecimalField(auto_round=True)
#     description = TextField()
#     availability = IntegerField()
#     category = TextField()
#     _schema = ItemSchema
#     _search_attributes = ['name', 'category', 'description']
# 
#     def __str__(self):
#         return '{}, {}, {}, {}'.format(
#             self.uuid,
#             self.name,
#             self.price,
#             self.description)
# 
#     def is_favorite(self, item):
#         for f in self.favorites:
#             if f.item_id == item.id:
#                 return True
#         return False
# 
# Path: utils.py
# def get_image_folder():
#     return os.path.join(get_project_root(), IMAGE_FOLDER)


# Path: tests/test_utils.py
from functools import reduce
from base64 import b64encode
from models import Address, User, Favorite, Item
from utils import get_image_folder
import datetime
import inspect
import json
import os
import random
import shutil
import sys
import uuid

# ###########################################################
# Peewee models helpers
# Functions to create new instances with overridable defaults


def add_user(email, password, id=None, first_name='John', last_name='Doe'):
    """
    Create a single user in the test database.
    If an email is provided it will be used, otherwise it will be generated
    by the function before adding the User to the database.
    """
    email = email or 'johndoe{}@email.com'.format(int(random.random() * 100))

    return User.create(
        first_name=first_name,
        last_name=last_name,
        email=email,
        password=User.hash_password(password),
        uuid=id or uuid.uuid4(),
    )


def add_admin_user(email, psw, id=None):
    """
    Create a single user in the test database.
    If an email is provided it will be used, otherwise it will be generated
    by the function before adding the User to the database.
    """
    email = email or 'johndoe{}@email.com'.format(int(random.random() * 100))


    return User.create(