from __future__ import annotations

from datetime import date, datetime
from decimal import Decimal
from enum import Enum
from typing import Any, Dict, List, Optional
from uuid import UUID

from pydantic import BaseModel, Field, model_validator

# Re-export from submodules so forward references resolve
from .recipe import (
    RecipeBase,
    RecipeCreate,
    RecipeIngredientRef,
    RecipeRead,
    RecipeUpdate,
    ResolveIngredientCandidate,
    ResolveIngredientRequest,
    ResolveIngredientResponse,
)

# These may be referenced by other models; re-export as aliases if needed.
RecipeResponse = RecipeRead


class FamilyMemberRole(str, Enum):
    adult = "adult"
    child = "child"


class MealType(str, Enum):
    breakfast = "breakfast"
    lunch = "lunch"
    dinner = "dinner"


class MealPlanStatus(str, Enum):
    draft = "draft"
    pending_approval = "pending_approval"
    approved = "approved"
    locked = "locked"


class MealPlanItemStatus(str, Enum):
    pending = "pending"
    approved = "approved"
    denied = "denied"
    swapped = "swapped"


class DenialReason(str, Enum):
    too_expensive = "too_expensive"
    boring = "boring"
    disliked_ingredient = "disliked_ingredient"
    cultural = "cultural"
    other = "other"


class NeverSuggestReason(str, Enum):
    allergy = "allergy"
    dislike = "dislike"
    tried_too_much = "tried_too_much"
    other = "other"


class IngredientBase(BaseModel):
    name: str
    name_lower: str
    plural_name: Optional[str] = None
    aisle: Optional[str] = None
    typical_price: Optional[float] = None
    unit: Optional[str] = None
    season_months: Optional[List[int]] = None


class IngredientResponse(IngredientBase):
    id: UUID
    created_at: Optional[datetime] = None

    class Config:
        from_attributes = True


class IngredientCreate(IngredientBase):
    pass


class FamilyMemberBase(BaseModel):
    name: str
    email: Optional[str] = None
    role: FamilyMemberRole
    likes_mushrooms: bool = False


class FamilyMemberResponse(FamilyMemberBase):
    id: UUID
    family_profile_id: UUID
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = None

    class Config:
        from_attributes = True


class FamilyMemberCreate(FamilyMemberBase):
    pass


class FamilyProfileBase(BaseModel):
    name: str
    household_size: int
    adult_count: int
    child_count: int
    dietary_notes: Optional[str] = None
    budget_per_meal: float = 50.00


class FamilyProfileResponse(BaseModel):
    id: UUID
    name: str
    household_size: int
    adult_count: int
    child_count: int
    dietary_notes: Optional[str] = None
    budget_per_meal: float = 50.00
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = None
    members: List[FamilyMemberResponse] = []
    planner_config: Optional[dict] = None

    class Config:
        from_attributes = True


class PlannerConfigOverride(BaseModel):
    recency_weeks: Optional[int] = Field(default=None, ge=0)
    calorie_tolerance_pct: Optional[int] = Field(default=None, ge=0, le=100)
    max_total_minutes: Optional[int] = Field(default=None, ge=0)
    max_meal_cost: Optional[float] = Field(default=None, ge=0)
    w_savings: Optional[float] = Field(default=None, ge=0, le=1)
    w_coverage: Optional[float] = Field(default=None, ge=0, le=1)
    w_pantry: Optional[float] = Field(default=None, ge=0, le=1)
    w_time: Optional[float] = Field(default=None, ge=0, le=1)
    w_recency: Optional[float] = Field(default=None, ge=0, le=1)
    time_ideal_minutes: Optional[int] = Field(default=None, ge=0)
    time_full_minutes: Optional[int] = Field(default=None, ge=0)
    recency_full_weeks: Optional[int] = Field(default=None, ge=0)
    top_k: Optional[int] = Field(default=None, ge=1)
    set_size: Optional[int] = Field(default=None, ge=1)
    p_protein: Optional[float] = Field(default=None, ge=0)
    p_cuisine: Optional[float] = Field(default=None, ge=0)


class PlannerConfigResponse(BaseModel):
    recency_weeks: int
    calorie_tolerance_pct: int
    max_total_minutes: int
    max_meal_cost: float
    w_savings: float
    w_coverage: float
    w_pantry: float
    w_time: float
    w_recency: float
    time_ideal_minutes: int
    time_full_minutes: int
    recency_full_weeks: int
    top_k: int
    set_size: int
    p_protein: float
    p_cuisine: float
    source: str = "default"


class PlannerConfigUpdateRequest(BaseModel):
    planner_config: PlannerConfigOverride


class FamilyProfileCreate(FamilyProfileBase):
    pass


class FamilyProfileUpdate(BaseModel):
    name: Optional[str] = None
    household_size: Optional[int] = None
    adult_count: Optional[int] = None
    child_count: Optional[int] = None
    dietary_notes: Optional[str] = None
    budget_per_meal: Optional[float] = None
    planner_config: Optional[dict] = None


class RecipeCreate(RecipeBase):
    pass


class MealPlanItemBase(BaseModel):
    recipe_id: UUID
    day_of_week: int = Field(..., ge=1, le=7)
    meal_type: MealType
    estimated_cost: Optional[float] = None


class MealPlanItemResponse(MealPlanItemBase):
    id: UUID
    meal_plan_id: UUID
    approval_status: MealPlanItemStatus = MealPlanItemStatus.pending
    denial_reason: Optional[DenialReason] = None
    denial_details: Optional[str] = None
    used_pantry_items: Optional[List[UUID]] = []
    score: Optional[float] = None
    components: Optional[Dict[str, float]] = None
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = None
    recipe: Optional[RecipeResponse] = None

    class Config:
        from_attributes = True


class MealPlanItemCreate(MealPlanItemBase):
    pass


class MealPlanBase(BaseModel):
    week_start_date: date
    status: MealPlanStatus = MealPlanStatus.draft
    approval_deadline: Optional[datetime] = None
    notes: Optional[str] = None


class MealPlanResponse(MealPlanBase):
    id: UUID
    family_profile_id: UUID
    total_estimated_cost: Optional[float] = None
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = None
    items: List[MealPlanItemResponse] = []

    class Config:
        from_attributes = True


class MealPlanCreate(MealPlanBase):
    items: List[MealPlanItemCreate] = []


class VoteRequest(BaseModel):
    vote: bool
    denial_reason: Optional[DenialReason] = None
    denial_details: Optional[str] = None


class VoteResponse(BaseModel):
    id: UUID
    meal_plan_item_id: UUID
    family_member_id: UUID
    vote: bool
    voted_at: Optional[datetime] = None

    class Config:
        from_attributes = True


class HomePantryBase(BaseModel):
    ingredient_id: UUID
    quantity: Optional[float] = None
    unit: Optional[str] = None
    expires_at: Optional[date] = None


class HomePantryResponse(HomePantryBase):
    id: UUID
    family_profile_id: UUID
    added_at: Optional[datetime] = None
    created_at: Optional[datetime] = None
    ingredient: Optional[IngredientResponse] = None

    class Config:
        from_attributes = True


class HomePantryCreate(HomePantryBase):
    pass


class FeedbackBase(BaseModel):
    rating: Optional[int] = Field(None, ge=1, le=5)
    never_suggest: bool = False
    denial_reason: Optional[DenialReason] = None
    feedback_text: Optional[str] = None


class FeedbackResponse(FeedbackBase):
    id: UUID
    family_profile_id: UUID
    family_member_id: Optional[UUID] = None
    meal_plan_item_id: UUID
    created_at: Optional[datetime] = None

    class Config:
        from_attributes = True


class FeedbackCreate(FeedbackBase):
    meal_plan_item_id: UUID


class ShoppingListItem(BaseModel):
    ingredient_id: Optional[UUID] = None
    name: str
    quantity: Optional[float] = None
    unit: Optional[str] = None
    aisle: Optional[str] = None
    estimated_price: Optional[float] = None
    is_on_sale: bool = False
    sale_price: Optional[float] = None
    in_season: bool = False
    in_pantry: bool = False


class ShoppingListResponse(BaseModel):
    week_start_date: date
    items: List[ShoppingListItem]
    total_estimated_cost: float
    sale_items_count: int
    by_aisle: dict[str, List[ShoppingListItem]]