from test.test_const import CONST_BASE_URL, CONST_PORT, CONST_SSL
from unittest import TestCase

import responses
from requests.exceptions import HTTPError

from pygrocydm import GrocyAPI
from pygrocydm.grocy_datamanager import GrocyDataManager
from pygrocydm.entities.battery import Battery
from pygrocydm.entities.chore import Chore
from pygrocydm.entities.equipment import Equipment
from pygrocydm.entities.location import Location
from pygrocydm.entities.meal_plan import MealPlan
from pygrocydm.entities.product import Product
from pygrocydm.entities.product_group import ProductGroup
from pygrocydm.entities.quantity_unit import QuantityUnit
from pygrocydm.entities.quantity_unit_conversion import QuantityUnitConversion
from pygrocydm.entities.recipe import Recipe
from pygrocydm.entities.recipe_nesting import RecipeNesting
from pygrocydm.entities.recipe_pos import RecipePos
from pygrocydm.entities.shopping_list import ShoppingList, ShoppingListItem
from pygrocydm.entities.task import Task
from pygrocydm.entities.task_category import TaskCategory
from pygrocydm.entities.userentity import UserEntity
from pygrocydm.entities.userfield import Userfield
from pygrocydm.entities.userobject import UserObject


class TestGrocyDataManager(TestCase):

    def setUp(self):
        dummy = GrocyAPI(CONST_BASE_URL, "api_key",  verify_ssl = CONST_SSL, port = CONST_PORT)
        grocyapi = GrocyAPI(CONST_BASE_URL, "demo_mode",  verify_ssl = CONST_SSL, port = CONST_PORT)
        self.gdm = grocyapi.generic_entities()

    def test_init(self):
        assert isinstance(self.gdm, GrocyDataManager)

    def test_products_valid(self):
        products = self.gdm.products().list
        assert isinstance(products, tuple)
        assert len(products) >=1
        for product in products:
            assert isinstance(product, Product)

    @responses.activate
    def test_products_invalid_no_data(self):
        resp = []
        responses.add(responses.GET,
            f"{CONST_BASE_URL}:{CONST_PORT}/api/objects/products",
            json=resp,
            status=200)
        products = self.gdm.products().list
        assert len(products) == 0

    @responses.activate
    def test_products_error(self):
        responses.add(responses.GET,
            f"{CONST_BASE_URL}:{CONST_PORT}/api/objects/products",
            status=400)
        self.assertRaises(HTTPError, self.gdm.products)

    def test_chores_valid(self):
        chores = self.gdm.chores().list
        assert isinstance(chores, tuple)
        assert len(chores) >=1
        for chore in chores:
            assert isinstance(chore, Chore)

    def test_locations_valid(self):
        locations = self.gdm.locations().list
        assert isinstance(locations, tuple)
        assert len(locations) >=1
        for location in locations:
            assert isinstance(location, Location)

    def test_batteries_valid(self):
        batteries = self.gdm.batteries().list
        assert isinstance(batteries, tuple)
        assert len(batteries) >=1
        for battery in batteries:
            assert isinstance(battery, Battery)

    def test_shopping_list_items_valid(self):
        shopping_list_items = self.gdm.shopping_list().list
        assert isinstance(shopping_list_items, tuple)
        assert len(shopping_list_items) >=1
        for items in shopping_list_items:
            assert isinstance(items, ShoppingListItem)

    def test_shopping_lists_valid(self):
        shopping_lists = self.gdm.shopping_lists().list
        assert isinstance(shopping_lists, tuple)
        assert len(shopping_lists) >=1
        for shopping_list in shopping_lists:
            assert isinstance(shopping_list, ShoppingList)

    def test_add_product_valid(self):
        product_list = self.gdm.products()
        old_len = len(product_list.list)
        new_product = {}
        new_product['name'] = 'Test product'
        new_product['location_id'] = 1
        new_product['qu_id_purchase'] = 1
        new_product['qu_id_stock'] = 1
        new_product['qu_factor_purchase_to_stock'] = 1
        new_product_id = product_list.add(new_product)
        new_len = len(product_list.list)
        assert isinstance(new_product_id, int)
        assert new_len == old_len + 1

    def test_add_product_error(self):
        product_list = self.gdm.products()
        new_product = {}
        new_product['name'] = 'Test product'
        self.assertRaises(HTTPError, product_list.add, new_product)

    def test_edit_product_valid(self):
        fields = {}
        fields['name'] = 'Test'
        assert not self.gdm.products().list[-1].edit(fields)

    def test_edit_product_error(self):
        fields = {}
        fields['nam'] = 'Test'
        product = self.gdm.products().list[0]
        self.assertRaises(HTTPError, product.edit, fields)

    def test_product_delete_valid(self):
        product = self.gdm.products().list[-1]
        old_len = len(self.gdm.products().list)
        assert not product.delete()
        self.gdm.products().refresh()
        new_len = len(self.gdm.products().list)
        assert new_len == old_len - 1

    def test_product_delete_error(self):
        product = self.gdm.products().list[-1]
        product.delete()
        self.assertRaises(HTTPError, product.delete)

    def test_search_product_valid(self):
        products = self.gdm.products().search("Co")
        assert isinstance(products, tuple)
        assert len(products) >=1
        for product in products:
            assert isinstance(product, Product)

    def test_search_product_invalid_no_data(self):
        products = self.gdm.products().search("Toto")
        assert products is None

    @responses.activate
    def test_search_product_error(self):
        url = f"{CONST_BASE_URL}:{CONST_PORT}/api/objects/products"
        responses.add_passthru(url)
        responses.add(responses.GET,
            f"{url}/search/error",
            status=400)
        products = self.gdm.products()
        self.assertRaises(HTTPError, products.search, "error")

    def test_quantity_units_valid(self):
        quantity_units = self.gdm.quantity_units().list
        assert isinstance(quantity_units, tuple)
        assert len(quantity_units) >=1
        for quantity_unit in quantity_units:
            assert isinstance(quantity_unit, QuantityUnit)

    def test_tasks_valid(self):
        tasks = self.gdm.tasks().list
        assert isinstance(tasks, tuple)
        assert len(tasks) >=1
        for task in tasks:
            assert isinstance(task, Task)

    def test_task_categories_valid(self):
        task_categories = self.gdm.task_categories().list
        assert isinstance(task_categories, tuple)
        assert len(task_categories) >=1
        for task_category in task_categories:
            assert isinstance(task_category, TaskCategory)

    def test_product_groups_valid(self):
        product_groups = self.gdm.product_groups().list
        assert isinstance(product_groups, tuple)
        assert len(product_groups) >=1
        for product_group in product_groups:
            assert isinstance(product_group, ProductGroup)

    def test_quantity_unit_conversions_valid(self):
        quantity_unit_conversions = self.gdm.quantity_unit_conversions().list
        assert isinstance(quantity_unit_conversions, tuple)
        assert len(quantity_unit_conversions) >=1
        for quantity_unit_conversion in quantity_unit_conversions:
            assert isinstance(quantity_unit_conversion, QuantityUnitConversion)

    def test_equipment_valid(self):
        equipments = self.gdm.equipment().list
        assert isinstance(equipments, tuple)
        assert len(equipments) >=1
        for equipment in equipments:
            assert isinstance(equipment, Equipment)

    def test_userfields_valid(self):
        userfields = self.gdm.userfields().list
        assert isinstance(userfields, tuple)
        assert len(userfields) >=1
        for userfield in userfields:
            assert isinstance(userfield, Userfield)

    def test_userentities_valid(self):
        userentities = self.gdm.userentities().list
        assert isinstance(userentities, tuple)
        assert len(userentities) >=1
        for userentity in userentities:
            assert isinstance(userentity, UserEntity)

    def test_userobjects_valid(self):
        userobjects = self.gdm.userobjects().list
        assert isinstance(userobjects, tuple)
        assert len(userobjects) >=1
        for userobject in userobjects:
            assert isinstance(userobject, UserObject)

    def test_meal_plan_valid(self):
        userobjects = self.gdm.meal_plan().list
        assert isinstance(userobjects, tuple)
        assert len(userobjects) >=1
        for userobject in userobjects:
            assert isinstance(userobject, MealPlan)

    def test_recipes_valid(self):
        recipes = self.gdm.recipes().list
        assert isinstance(recipes, tuple)
        assert len(recipes) >=1
        for recipe in recipes:
            assert isinstance(recipe, Recipe)

    def test_recipes_pos_valid(self):
        recipes_pos = self.gdm.recipes_pos().list
        assert isinstance(recipes_pos, tuple)
        assert len(recipes_pos) >=1
        for recipe_pos in recipes_pos:
            assert isinstance(recipe_pos, RecipePos)

    def test_recipes_nestings_valid(self):
        recipes_nestings = self.gdm.recipes_nestings().list
        assert isinstance(recipes_nestings, tuple)
        assert len(recipes_nestings) >=1
        for recipe_nesting in recipes_nestings:
            assert isinstance(recipe_nesting, RecipeNesting)

    @responses.activate
    def test_get_userfields_valid(self):
        base_url = f"{CONST_BASE_URL}:{CONST_PORT}/api"
        resp =  {
                "uf1": 0,
                "uf2": "string"
            }
        userfields_url = f"{base_url}/userfields/products/1"
        responses.add(responses.GET, userfields_url, json=resp, status=200)
        responses.add_passthru(f"{base_url}/objects/products")
        product = self.gdm.products().list[0]

        product_uf = product.get_userfields()

        assert product_uf['uf1'] == 0

    def test_get_userfields_invalid_no_data(self):
        assert not self.gdm.products().list[0].get_userfields()

    @responses.activate
    def test_set_userfields_valid(self):
        base_url = f"{CONST_BASE_URL}:{CONST_PORT}/api"
        responses.add_passthru(f"{base_url}/objects/products")
        product = self.gdm.products().list[0]
        userfields_url = f"{base_url}/userfields/products/1"
        responses.add(responses.PUT, userfields_url, status=204)
        assert not product.set_userfields("auserfield", "value")

    @responses.activate
    def test_set_userfields_error(self):
        base_url = f"{CONST_BASE_URL}:{CONST_PORT}/api"
        responses.add_passthru(f"{base_url}/objects/products")
        product = self.gdm.products().list[0]
        userfields_url = f"{base_url}/userfields/products/1"
        responses.add(responses.PUT, userfields_url, status=400)
        self.assertRaises(HTTPError, product.set_userfields, "auserfield", "value")
