# shared/clients/recipes_client.py
"""
Recipes Service Client for Inter-Service Communication
Provides access to recipe and ingredient requirements from other services
"""

import structlog
from typing import Dict, Any, Optional, List
from uuid import UUID
from shared.clients.base_service_client import BaseServiceClient
from shared.config.base import BaseServiceSettings

logger = structlog.get_logger()


class RecipesServiceClient(BaseServiceClient):
    """Client for communicating with the Recipes Service"""
    
    def __init__(self, config: BaseServiceSettings, calling_service_name: str = "unknown"):
        super().__init__(calling_service_name, config)
    
    def get_service_base_path(self) -> str:
        return "/api/v1"
    
    # ================================================================
    # RECIPE MANAGEMENT
    # ================================================================
    
    async def get_recipe_by_id(self, tenant_id: str, recipe_id: str) -> Optional[Dict[str, Any]]:
        """Get recipe details by ID"""
        try:
            result = await self.get(f"recipes/{recipe_id}", tenant_id=tenant_id)
            if result:
                logger.info("Retrieved recipe details from recipes service", 
                          recipe_id=recipe_id, tenant_id=tenant_id)
            return result
        except Exception as e:
            logger.error("Error getting recipe details", 
                        error=str(e), recipe_id=recipe_id, tenant_id=tenant_id)
            return None
    
    async def get_recipes_by_product_ids(self, tenant_id: str, product_ids: List[str]) -> Optional[List[Dict[str, Any]]]:
        """Get recipes for multiple products"""
        try:
            params = {"product_ids": ",".join(product_ids)}
            result = await self.get("recipes/by-products", tenant_id=tenant_id, params=params)
            recipes = result.get('recipes', []) if result else []
            logger.info("Retrieved recipes by product IDs from recipes service", 
                      product_ids_count=len(product_ids), 
                      recipes_count=len(recipes),
                      tenant_id=tenant_id)
            return recipes
        except Exception as e:
            logger.error("Error getting recipes by product IDs", 
                        error=str(e), tenant_id=tenant_id)
            return []
    
    async def get_all_recipes(self, tenant_id: str, is_active: Optional[bool] = True) -> Optional[List[Dict[str, Any]]]:
        """Get all recipes for a tenant"""
        try:
            params = {}
            if is_active is not None:
                params["is_active"] = is_active
                
            result = await self.get_paginated("recipes", tenant_id=tenant_id, params=params)
            logger.info("Retrieved all recipes from recipes service", 
                      recipes_count=len(result), tenant_id=tenant_id)
            return result
        except Exception as e:
            logger.error("Error getting all recipes", 
                        error=str(e), tenant_id=tenant_id)
            return []
    
    # ================================================================
    # INGREDIENT REQUIREMENTS
    # ================================================================
    
    async def get_recipe_requirements(self, tenant_id: str, recipe_ids: Optional[List[str]] = None) -> Optional[Dict[str, Any]]:
        """Get ingredient requirements for recipes"""
        try:
            params = {}
            if recipe_ids:
                params["recipe_ids"] = ",".join(recipe_ids)
                
            result = await self.get("recipes/requirements", tenant_id=tenant_id, params=params)
            if result:
                logger.info("Retrieved recipe requirements from recipes service", 
                          recipe_ids_count=len(recipe_ids) if recipe_ids else 0,
                          tenant_id=tenant_id)
            return result
        except Exception as e:
            logger.error("Error getting recipe requirements", 
                        error=str(e), tenant_id=tenant_id)
            return None
    
    async def get_ingredient_requirements(self, tenant_id: str, product_ids: Optional[List[str]] = None) -> Optional[Dict[str, Any]]:
        """Get ingredient requirements for production planning"""
        try:
            params = {}
            if product_ids:
                params["product_ids"] = ",".join(product_ids)
                
            result = await self.get("recipes/ingredient-requirements", tenant_id=tenant_id, params=params)
            if result:
                logger.info("Retrieved ingredient requirements from recipes service", 
                          product_ids_count=len(product_ids) if product_ids else 0,
                          tenant_id=tenant_id)
            return result
        except Exception as e:
            logger.error("Error getting ingredient requirements", 
                        error=str(e), tenant_id=tenant_id)
            return None
    
    async def calculate_ingredients_for_quantity(self, tenant_id: str, recipe_id: str, quantity: float) -> Optional[Dict[str, Any]]:
        """Calculate ingredient quantities needed for a specific production quantity"""
        try:
            data = {
                "recipe_id": recipe_id,
                "quantity": quantity
            }
            result = await self.post("recipes/operations/calculate-ingredients", data=data, tenant_id=tenant_id)
            if result:
                logger.info("Calculated ingredient quantities from recipes service", 
                          recipe_id=recipe_id, quantity=quantity, tenant_id=tenant_id)
            return result
        except Exception as e:
            logger.error("Error calculating ingredient quantities", 
                        error=str(e), recipe_id=recipe_id, tenant_id=tenant_id)
            return None
    
    async def calculate_batch_ingredients(self, tenant_id: str, production_requests: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
        """Calculate total ingredient requirements for multiple production batches"""
        try:
            data = {"production_requests": production_requests}
            result = await self.post("recipes/operations/calculate-batch-ingredients", data=data, tenant_id=tenant_id)
            if result:
                logger.info("Calculated batch ingredient requirements from recipes service", 
                          batches_count=len(production_requests), tenant_id=tenant_id)
            return result
        except Exception as e:
            logger.error("Error calculating batch ingredient requirements", 
                        error=str(e), tenant_id=tenant_id)
            return None
    
    # ================================================================
    # PRODUCTION SUPPORT
    # ================================================================
    
    async def get_production_instructions(self, tenant_id: str, recipe_id: str) -> Optional[Dict[str, Any]]:
        """Get detailed production instructions for a recipe"""
        try:
            result = await self.get(f"recipes/{recipe_id}/production-instructions", tenant_id=tenant_id)
            if result:
                logger.info("Retrieved production instructions from recipes service", 
                          recipe_id=recipe_id, tenant_id=tenant_id)
            return result
        except Exception as e:
            logger.error("Error getting production instructions", 
                        error=str(e), recipe_id=recipe_id, tenant_id=tenant_id)
            return None
    
    async def get_recipe_yield_info(self, tenant_id: str, recipe_id: str) -> Optional[Dict[str, Any]]:
        """Get yield information for a recipe"""
        try:
            result = await self.get(f"recipes/{recipe_id}/yield", tenant_id=tenant_id)
            if result:
                logger.info("Retrieved recipe yield info from recipes service", 
                          recipe_id=recipe_id, tenant_id=tenant_id)
            return result
        except Exception as e:
            logger.error("Error getting recipe yield info", 
                        error=str(e), recipe_id=recipe_id, tenant_id=tenant_id)
            return None
    
    async def validate_recipe_feasibility(self, tenant_id: str, recipe_id: str, quantity: float) -> Optional[Dict[str, Any]]:
        """Validate if a recipe can be produced in the requested quantity"""
        try:
            data = {
                "recipe_id": recipe_id,
                "quantity": quantity
            }
            result = await self.post("recipes/operations/validate-feasibility", data=data, tenant_id=tenant_id)
            if result:
                logger.info("Validated recipe feasibility from recipes service", 
                          recipe_id=recipe_id, quantity=quantity, tenant_id=tenant_id)
            return result
        except Exception as e:
            logger.error("Error validating recipe feasibility", 
                        error=str(e), recipe_id=recipe_id, tenant_id=tenant_id)
            return None
    
    # ================================================================
    # ANALYTICS AND OPTIMIZATION
    # ================================================================
    
    async def get_recipe_cost_analysis(self, tenant_id: str, recipe_id: str) -> Optional[Dict[str, Any]]:
        """Get cost analysis for a recipe"""
        try:
            result = await self.get(f"recipes/{recipe_id}/cost-analysis", tenant_id=tenant_id)
            if result:
                logger.info("Retrieved recipe cost analysis from recipes service", 
                          recipe_id=recipe_id, tenant_id=tenant_id)
            return result
        except Exception as e:
            logger.error("Error getting recipe cost analysis", 
                        error=str(e), recipe_id=recipe_id, tenant_id=tenant_id)
            return None
    
    async def optimize_production_batch(self, tenant_id: str, requirements: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
        """Optimize production batch to minimize waste and cost"""
        try:
            data = {"requirements": requirements}
            result = await self.post("recipes/operations/optimize-batch", data=data, tenant_id=tenant_id)
            if result:
                logger.info("Optimized production batch from recipes service", 
                          requirements_count=len(requirements), tenant_id=tenant_id)
            return result
        except Exception as e:
            logger.error("Error optimizing production batch", 
                        error=str(e), tenant_id=tenant_id)
            return None
    
    # ================================================================
    # DASHBOARD AND ANALYTICS
    # ================================================================
    
    async def get_dashboard_summary(self, tenant_id: str) -> Optional[Dict[str, Any]]:
        """Get recipes dashboard summary data"""
        try:
            result = await self.get("recipes/dashboard/summary", tenant_id=tenant_id)
            if result:
                logger.info("Retrieved recipes dashboard summary", 
                          tenant_id=tenant_id)
            return result
        except Exception as e:
            logger.error("Error getting recipes dashboard summary", 
                        error=str(e), tenant_id=tenant_id)
            return None
    
    async def get_popular_recipes(self, tenant_id: str, period: str = "last_30_days") -> Optional[List[Dict[str, Any]]]:
        """Get most popular recipes based on production frequency"""
        try:
            params = {"period": period}
            result = await self.get("recipes/analytics/popular-recipes", tenant_id=tenant_id, params=params)
            recipes = result.get('recipes', []) if result else []
            logger.info("Retrieved popular recipes from recipes service", 
                      period=period, recipes_count=len(recipes), tenant_id=tenant_id)
            return recipes
        except Exception as e:
            logger.error("Error getting popular recipes", 
                        error=str(e), tenant_id=tenant_id)
            return []
    
    # ================================================================
    # COUNT AND STATISTICS
    # ================================================================

    async def count_recipes(self, tenant_id: str) -> int:
        """
        Get the count of recipes for a tenant
        Used for subscription limit tracking

        Returns:
            int: Number of recipes for the tenant
        """
        try:
            result = await self.get("recipes/count", tenant_id=tenant_id)
            count = result.get('count', 0) if result else 0
            logger.info("Retrieved recipe count from recipes service",
                      count=count, tenant_id=tenant_id)
            return count
        except Exception as e:
            logger.error("Error getting recipe count",
                        error=str(e), tenant_id=tenant_id)
            return 0

    # ================================================================
    # UTILITY METHODS
    # ================================================================

    async def health_check(self) -> bool:
        """Check if recipes service is healthy"""
        try:
            result = await self.get("../health")  # Health endpoint is not tenant-scoped
            return result is not None
        except Exception as e:
            logger.error("Recipes service health check failed", error=str(e))
            return False


# Factory function for dependency injection
def create_recipes_client(config: BaseServiceSettings, service_name: str = "unknown") -> RecipesServiceClient:
    """Create recipes service client instance"""
    return RecipesServiceClient(config, calling_service_name=service_name)