import os
import re
import json
from datetime import datetime
from typing import Dict, List, Optional
from pydantic import BaseModel, Field
import pypdf
import random
import string
import traceback

# ------------------------------------------------------------------------------
# Helper function for generating unique meal IDs
# ------------------------------------------------------------------------------
def generate_meal_id() -> str:
    """Generate a 5-character alphanumeric ID (e.g., 'A3F9B')."""
    return ''.join(random.choices(string.ascii_uppercase + string.digits, k=5))

# ------------------------------------------------------------------------------
# Pydantic Models
# ------------------------------------------------------------------------------
class Ingredient(BaseModel):
    name: str
    quantity: Optional[str] = Field(default="some", description="Quantity of the ingredient, e.g., '100g'")
    icon: str = Field(default="🍽️", description="Emoji icon for the ingredient")

class Macronutrients(BaseModel):
    carbohydrates: float
    protein: float
    fat: float

class Meal(BaseModel):
    id: str = Field(default_factory=generate_meal_id, description="Unique 5-character meal ID")
    meal_name: str
    category: str  
    sub_category: str  
    total_calories: float
    macronutrients: Macronutrients
    description: str
    ingredients: List[Ingredient]
    number_of_servings: int = 1
    image: Optional[str] = None

class MealPlanResponse(BaseModel):
    user_id: str
    blood_type: str
    diet_type: str
    total_daily_calories: Optional[int] = None
    total_daily_macronutrients: Optional[Macronutrients] = None
    breakfast_options: Dict[str, List[Meal]]
    lunch_options: Dict[str, List[Meal]]
    dinner_options: Dict[str, List[Meal]]
    breakfast_image: Optional[str] = None
    lunch_image: Optional[str] = None
    dinner_image: Optional[str] = None
    breakfast_image_id: Optional[str] = None
    lunch_image_id: Optional[str] = None
    dinner_image_id: Optional[str] = None
    meal_calorie_distribution: Optional[Dict[str, int]] = None

class SwapMealRequest(BaseModel):
    user_id: str
    blood_type: str
    diet_type: str
    category: str
    sub_category: str
    current_calories: int
    country: Optional[str] = ""
    allergies: Optional[str] = ""
    food_dislikes: Optional[str] = ""

class SwapMealResponse(BaseModel):
    alternatives: List[Meal]
    original_category: str
    original_sub_category: str
    target_calories: int

class MealImageRequest(BaseModel):
    id: Optional[str] = None  # Optional meal ID for tracking
    meal_name: str
    description: str
    ingredients: List[Ingredient]

class MealImageResponse(BaseModel):
    id: Optional[str] = None    # return the ID
    meal_image_base64: Optional[str] = None

class HarmfulIngredient(BaseModel):
    name: str
    reason: str
    category: str   

class NeutralIngredient(BaseModel):
    name: str


class SafeIngredient(BaseModel):
    name: str

class FoodTypeInfo(BaseModel):
    """Legend entry for Beneficial / Neutral / Avoid in scan-food responses."""
    key: str
    title: str
    description: str


def default_food_types() -> List[FoodTypeInfo]:
    # Titles/keys only — description is always generated by AI at scan time
    return [
        FoodTypeInfo(key="beneficial", title="Beneficial", description=""),
        FoodTypeInfo(key="neutral", title="Neutral", description=""),
        FoodTypeInfo(key="avoid", title="Avoid", description=""),
    ]


def food_types_for_scan(
    *,
    has_beneficial: bool = False,
    has_neutral: bool = False,
    has_avoid: bool = False,
) -> List[FoodTypeInfo]:
    """
    Return only the single best-matching type for this scan.
    Priority: Avoid > Beneficial > Neutral.
    """
    by_key = {t.key: t for t in default_food_types()}
    if has_avoid:
        return [by_key["avoid"]]
    if has_beneficial:
        return [by_key["beneficial"]]
    if has_neutral:
        return [by_key["neutral"]]
    return []


class FoodScanResponse(BaseModel):
    identified_ingredients: List[str]
    harmful_ingredients: List[HarmfulIngredient]
    neutral_ingredients: List[NeutralIngredient]      
    safe_ingredients: List[SafeIngredient]
    warning_message: str
    neutral_message: str                           
    safe_message: str
    # Single best-matching type; description is AI-generated
    food_types: List[FoodTypeInfo] = Field(default_factory=list)

class DailyNutritionResponse(BaseModel):
    user_id: str
    calculation_timestamp: Optional[datetime] = None
    total_daily_calories: int
    total_daily_macronutrients: Macronutrients
    meal_calorie_distribution: Optional[Dict[str, int]] = None

