import pytest
from unittest.mock import patch
from foods.sources.usda import (
    USDAFoodAPI,
    NutritionCalculator,
)


class TestUSDAFoodAPI:
    @pytest.fixture
    def usda_api(self):
        with patch("vrobbler.apps.foods.sources.usda.settings") as mock_settings:
            mock_settings.USDA_API_KEY = "test_api_key"
            return USDAFoodAPI(api_key="test_api_key")

    def test_extract_nutrients_with_nutrient_number(self, usda_api):
        food_data = {
            "description": "Test Food",
            "foodNutrients": [
                {
                    "nutrientNumber": "203",
                    "nutrientName": "Protein",
                    "value": 10.0,
                },
                {
                    "nutrientNumber": "204",
                    "nutrientName": "Total lipid (fat)",
                    "value": 5.0,
                },
                {
                    "nutrientNumber": "205",
                    "nutrientName": "Carbohydrate, by difference",
                    "value": 20.0,
                },
                {
                    "nutrientNumber": "208",
                    "nutrientName": "Energy",
                    "value": 150.0,
                },
                {
                    "nutrientNumber": "269",
                    "nutrientName": "Sugars, total",
                    "value": 5.0,
                },
            ],
        }
        result = usda_api.extract_nutrients(food_data)
        assert result["protein"] == 10.0
        assert result["fat"] == 5.0
        assert result["carbohydrates"] == 20.0
        assert result["calories"] == 150.0
        assert result["sugar"] == 5.0

    def test_extract_nutrients_with_nested_nutrient(self, usda_api):
        food_data = {
            "description": "Test Food",
            "foodNutrients": [
                {
                    "nutrient": {"id": 203, "name": "Protein"},
                    "value": 10.0,
                },
            ],
        }
        result = usda_api.extract_nutrients(food_data)
        assert result["protein"] == 10.0

    def test_extract_nutrients_with_empty_nutrients(self, usda_api):
        food_data = {"description": "Test Food", "foodNutrients": []}
        result = usda_api.extract_nutrients(food_data)
        assert result["protein"] == 0
        assert result["calories"] == 0

    def test_extract_nutrients_with_no_nutrients_key(self, usda_api):
        food_data = {"description": "Test Food"}
        result = usda_api.extract_nutrients(food_data)
        assert result["protein"] == 0


class TestNutritionCalculator:
    @pytest.fixture
    def calculator(self):
        with patch("vrobbler.apps.foods.sources.usda.USDAFoodAPI"):
            return NutritionCalculator()

    def test_parse_ingredient_with_fraction(self, calculator):
        result = calculator.parse_ingredient("1/2 cup flour")
        assert result["quantity"] == 0.5
        assert result["unit"] == "cup"
        assert result["ingredient"] == "flour"

    def test_parse_ingredient_with_mixed_number(self, calculator):
        result = calculator.parse_ingredient("1 1/2 cups sugar")
        assert result["quantity"] == 1.5
        assert result["unit"] == "cups"
        assert result["ingredient"] == "sugar"

    def test_parse_ingredient_with_decimal(self, calculator):
        result = calculator.parse_ingredient("0.5 tsp salt")
        assert result["quantity"] == 0.5
        assert result["unit"] == "tsp"
        assert result["ingredient"] == "salt"

    def test_parse_ingredient_with_whole_number(self, calculator):
        result = calculator.parse_ingredient("3 eggs")
        assert result["quantity"] == 3
        assert result["unit"] is None
        assert result["ingredient"] == "eggs"

    def test_parse_ingredient_with_no_quantity(self, calculator):
        result = calculator.parse_ingredient("salt to taste")
        assert result["quantity"] == 1

    def test_clean_ingredient_name_removes_modifiers(self, calculator):
        result = calculator._clean_ingredient_name("fresh chopped onions")
        assert "fresh" not in result.lower()
        assert "chopped" not in result.lower()

    def test_clean_ingredient_name_removes_parentheses(self, calculator):
        result = calculator._clean_ingredient_name("flour (sifted)")
        assert "(" not in result
        assert ")" not in result

    def test_convert_to_grams_cup(self, calculator):
        result = calculator._convert_to_grams(2, "cups", "flour")
        assert result == 480

    def test_convert_to_grams_tablespoon(self, calculator):
        result = calculator._convert_to_grams(3, "tbsp", "olive oil")
        assert result == 45

    def test_convert_to_grams_unknown_unit(self, calculator):
        result = calculator._convert_to_grams(1, "unknown", "something")
        assert result == 100
