def run_tests():
    """Test Catalogue class."""

    # Test empty Catalogue (defaults)
    print("Test empty Catalogue:")
    catalogue = Catalogue()
    assert not catalogue.stores  # an empty list is considered False

    # Test loading stores
    print("\nTest loading Stores:")
    catalogue.load_stores('store_saves.csv')

    for shop in catalogue.list_stores():
        print(f'\n{shop}')

        print("\nTest listing shop inventory")
        for item in shop.inventory.list_items():
            print(item)
    assert catalogue.stores  # assuming CSV file is non-empty, non-empty list is considered True

    # Test adding a new Shop with values
    print("\nTest adding new Shop:")
    catalogue.add_store(Store("Squelons Wood", 300, 500, "I sell wood!"))
    for shop in catalogue.list_stores():
        print(shop)

    # Test saving Stores (check CSV file manually to see results)
    catalogue.save_stores('test.csv')
async def update_store(ctx, *, details):
    store_details = details.split(':')
    if len(store_details) == 5:  # Correct number of arguments provided
        old_store_name = store_details[0].strip()
        new_store_name = store_details[1].strip()
        new_store_location_x = store_details[2].strip()
        new_store_location_z = store_details[3].strip()
        new_store_description = store_details[4].strip()
        catalogue = Catalogue()
        catalogue.load_stores(PATH_TO_DATA_FILE)

        # Attempt to remove old store from catalogue.
        is_removed = catalogue.remove_store(old_store_name)
        if not is_removed:
            embed = discord.Embed(
                title=f'Store: \'{old_store_name}\' cannot be found',
                color=13424046)
            await ctx.send(embed=embed)
        else:
            # Add updated store
            updated_store = Store(new_store_name, new_store_location_x,
                                  new_store_location_z, new_store_description)
            catalogue.add_store(updated_store)

            # Update save file
            catalogue.save_stores(PATH_TO_DATA_FILE)
            embed = discord.Embed(title='Store Updated Successfully',
                                  color=13424046)
            await ctx.send(embed=embed)
        await stores(ctx)
    else:
        embed = discord.Embed(title='Error: Please use the following format',
                              color=13424046)
        await ctx.send(embed=embed)
        await help(ctx, 'update_store')
async def stores(ctx):
    catalogue = Catalogue()
    catalogue.load_stores(PATH_TO_DATA_FILE)
    embed = discord.Embed(title='MelonCraft Stores', color=13424046)
    for store in catalogue.list_stores():
        embed.add_field(
            name=store.name,
            value=
            f'{store.description} ({store.location_x}, {store.location_z})',
            inline=False)
    await ctx.send(embed=embed)
async def update_item(ctx, *, details):
    item_details = details.split(':')
    embed = discord.Embed()
    if len(item_details) == 5:  # Correct number of arguments provided
        store_name = item_details[0].strip()
        old_item_name = item_details[1].strip()
        new_item_name = item_details[2].strip()
        new_item_quantity = item_details[3].strip()
        new_item_cost = int(item_details[4].strip())

        catalogue = Catalogue()
        catalogue.load_stores(PATH_TO_DATA_FILE)
        is_valid_store_name = False
        for store in catalogue.list_stores():
            if store.name.lower() == store_name.lower():
                is_valid_store_name = True
                # Attempt to remove old Item from inventory
                is_removed = store.inventory.remove_item(old_item_name)
                if not is_removed:
                    embed = discord.Embed(
                        title=f'Item: \'{old_item_name}\' cannot be found',
                        color=13424046)
                else:
                    # Add updated Item
                    updated_item = Item(new_item_name, new_item_quantity,
                                        new_item_cost)
                    store.inventory.add_item(updated_item)

                    # Update save file
                    catalogue.save_stores(PATH_TO_DATA_FILE)
                    embed = discord.Embed(title='Item Updated Successfully',
                                          color=13424046)
                    embed.add_field(
                        name=f'{new_item_name}',
                        value=f'{new_item_quantity} / {new_item_cost}D')

        if not is_valid_store_name:
            embed = discord.Embed(
                title=f'Store: \'{store_name}\' cannot be found',
                color=13424046)
    else:
        embed = discord.Embed(title='Error: Please use the following format',
                              color=13424046)
        embed.add_field(
            name=
            '.update_item <Store_Name> : <Old_Item_Name> : <New_Item_Name> : <New_Item_Quantity> : '
            '<New_Item_Cost>',
            value=
            '\t.update_item All Australian Wool : Red Wool : Blue Wool : 2 Stacks : 1',
            inline=False)
        embed.add_field(name='Blue Wool', value='2 Stacks / 1D')
    await ctx.send(embed=embed)
async def remove_store(ctx, *, store_name):
    catalogue = Catalogue()
    catalogue.load_stores(PATH_TO_DATA_FILE)
    # Attempt to remove store from catalogue.
    is_removed = catalogue.remove_store(store_name)
    if not is_removed:
        embed = discord.Embed(title=f'Store: \'{store_name}\' cannot be found',
                              color=13424046)
        await ctx.send(embed=embed)
    else:
        # Update save file
        catalogue.save_stores(PATH_TO_DATA_FILE)
        await ctx.send('Store removed successfully!')
        await stores(ctx)
async def add_store(ctx, *, details):
    store_details = details.split(':')
    if len(store_details) != 4:
        await ctx.send('Error: Incorrect Formatting')
        await help(ctx, 'add_store')
    else:
        store_name = store_details[0].strip()
        store_location_x = store_details[1].strip()
        store_location_z = store_details[2].strip()
        store_description = store_details[3].strip()
        catalogue = Catalogue()
        catalogue.load_stores(PATH_TO_DATA_FILE)
        catalogue.add_store(
            Store(store_name, store_location_x, store_location_z,
                  store_description))
        catalogue.save_stores(PATH_TO_DATA_FILE)
        await ctx.send('Store added successfully!')
        await stores(ctx)
async def add_item(ctx, *, details):
    item_details = details.split(':')
    embed = discord.Embed()
    if len(item_details) == 4:  # Correct number of arguments given
        store_name = item_details[0].strip()
        item_name = item_details[1].strip()
        item_quantity = item_details[2].strip()
        item_cost = item_details[3].strip()

        catalogue = Catalogue()
        catalogue.load_stores(PATH_TO_DATA_FILE)
        is_valid_store_name = False
        for store in catalogue.list_stores():
            if store.name.lower() == store_name.lower():
                is_valid_store_name = True

                # Add new Item to store inventory
                new_item = Item(item_name, item_quantity, int(item_cost))
                store.inventory.add_item(new_item)

                # Update save file
                catalogue.save_stores(PATH_TO_DATA_FILE)
                embed = discord.Embed(title='Item Added Successfully',
                                      color=13424046)
                embed.add_field(name=f'{item_name}',
                                value=f'{item_quantity} / {item_cost}D')

        if not is_valid_store_name:
            embed = discord.Embed(
                title=f'Store: \'{store_name}\' cannot be found',
                color=13424046)
    else:
        embed = discord.Embed(title='Error: Please use the following format',
                              color=13424046)
        embed.add_field(
            name=
            '.sell <Store_Name> : <Item_Name> : <Quantity> : <Cost_in_Diamonds>',
            value='e.g. .sell All Australian Wool : Red Wool : 2 Stacks : 1',
            inline=False)
        embed.add_field(name='Red Wool', value='2 Stacks / 1D')
    await ctx.send(embed=embed)
async def list_inventory(ctx, *, store_name):
    catalogue = Catalogue()
    catalogue.load_stores(PATH_TO_DATA_FILE)
    is_valid_store = False
    for store in catalogue.list_stores():
        if store.name.lower() == store_name.lower():
            is_valid_store = True
            embed = discord.Embed(title=f'{store.name}', color=13424046)
            if store.inventory.__len__() == 0:
                embed.add_field(name='Currently has no Stock!',
                                value='Please check back later.',
                                inline=False)
            else:
                for item in store.inventory.list_items():
                    embed.add_field(name=item.name,
                                    value=f'{item.quantity} / {item.cost}D',
                                    inline=False)
            await ctx.send(embed=embed)
    if not is_valid_store:
        await ctx.send(f'\'{store_name}\' could not be found.')
        await stores(ctx)
async def find_item(ctx, *, item_name):
    number_of_instances_found = 0
    catalogue = Catalogue()
    catalogue.load_stores(PATH_TO_DATA_FILE)

    embed = discord.Embed(title=f'\'{item_name}\' was found in stock at:',
                          color=13424046)
    for store in catalogue.list_stores():
        for item in store.inventory.list_items():
            if calculate_similarity(item_name.lower(),
                                    item.name.lower()) > .5:  # Matching item
                number_of_instances_found += 1
                embed.add_field(
                    name=
                    f'{store.name} - ({store.location_x}, {store.location_z})',
                    value=f'{item.name} - {item.quantity} / {item.cost}D',
                    inline=False)

    if number_of_instances_found == 0:  # No matching items found
        embed = discord.Embed(
            title=f'\'{item_name}\' was not found in stock anywhere!',
            color=13424046)
    await ctx.send(embed=embed)
async def remove_item(ctx, *, details):
    item_details = details.split(':')
    embed = discord.Embed()
    if len(item_details) == 2:  # Correct number of arguments given
        store_name = item_details[0].strip()
        item_name = item_details[1].strip()

        catalogue = Catalogue()
        catalogue.load_stores(PATH_TO_DATA_FILE)
        is_valid_store_name = False
        for store in catalogue.list_stores():
            if store.name.lower() == store_name.lower():
                is_valid_store_name = True
                # Attempt to remove Item from store inventory
                is_removed = store.inventory.remove_item(item_name)
                if not is_removed:
                    embed = discord.Embed(
                        title=f'Item: \'{item_name}\' cannot be found',
                        color=13424046)
                else:
                    # Update save file
                    catalogue.save_stores(PATH_TO_DATA_FILE)
                    embed = discord.Embed(title='Item Removed Successfully',
                                          color=13424046)

        if not is_valid_store_name:
            embed = discord.Embed(
                title=f'Store Name: \'{store_name}\' cannot be found',
                color=13424046)
    else:
        embed = discord.Embed(title='Error: Please use the following format',
                              color=13424046)
        embed.add_field(
            name='.remove_item <Store_Name> : <Item_Name>',
            value='\te.g. .remove_item All Australian Wool : Red Wool',
            inline=False)
    await ctx.send(embed=embed)