from datetime import datetime, date
from decimal import Decimal
from typing import Optional, List
from sqlalchemy import String, DateTime, ForeignKey, Numeric, Integer, Text, Boolean, Date, CheckConstraint, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column, relationship
from database import Base


class MenuSection(Base):
    """Groupings for recipes and dishes (section_type: 'recipe' | 'dish')"""
    __tablename__ = "menu_sections"
    __table_args__ = (UniqueConstraint("kitchen_id", "name", "section_type", name="uq_menu_sections_kitchen_name_type"),)

    id: Mapped[int] = mapped_column(primary_key=True)
    kitchen_id: Mapped[int] = mapped_column(ForeignKey("kitchens.id"), nullable=False)
    name: Mapped[str] = mapped_column(String(100), nullable=False)
    section_type: Mapped[str] = mapped_column(String(20), nullable=False, default="recipe")  # "recipe" | "dish"
    sort_order: Mapped[int] = mapped_column(Integer, default=0)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)

    # Relationships
    kitchen: Mapped["Kitchen"] = relationship("Kitchen")
    recipes: Mapped[List["Recipe"]] = relationship("Recipe", back_populates="menu_section")


class Recipe(Base):
    """Component recipes and dishes"""
    __tablename__ = "recipes"
    __table_args__ = (UniqueConstraint("kitchen_id", "name", name="uq_recipes_kitchen_name"),)

    id: Mapped[int] = mapped_column(primary_key=True)
    kitchen_id: Mapped[int] = mapped_column(ForeignKey("kitchens.id"), nullable=False, index=True)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    recipe_type: Mapped[str] = mapped_column(String(20), nullable=False)  # "component" | "dish"
    menu_section_id: Mapped[Optional[int]] = mapped_column(ForeignKey("menu_sections.id", ondelete="SET NULL"), nullable=True, index=True)
    description: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    batch_portions: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
    batch_output_type: Mapped[str] = mapped_column(String(20), nullable=False, default="portions")  # "portions" | "bulk"
    batch_yield_qty: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 3), nullable=True)
    batch_yield_unit: Mapped[Optional[str]] = mapped_column(String(10), nullable=True)  # g, kg, ml, ltr
    prep_time_minutes: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    cook_time_minutes: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    is_archived: Mapped[bool] = mapped_column(Boolean, default=False)
    gross_sell_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 2), nullable=True)
    kds_menu_item_name: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)  # Phase 7: KDS link
    sambapos_portion_name: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)  # SambaPOS portion selector (e.g. "Beef", "BLT")
    created_by: Mapped[Optional[int]] = mapped_column(ForeignKey("users.id"), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
    updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    # Relationships
    kitchen: Mapped["Kitchen"] = relationship("Kitchen")
    menu_section: Mapped[Optional["MenuSection"]] = relationship("MenuSection", back_populates="recipes")
    created_by_user: Mapped[Optional["User"]] = relationship("User", foreign_keys=[created_by])
    ingredients: Mapped[List["RecipeIngredient"]] = relationship("RecipeIngredient", back_populates="recipe", cascade="all, delete-orphan")
    sub_recipes: Mapped[List["RecipeSubRecipe"]] = relationship("RecipeSubRecipe", back_populates="parent_recipe", foreign_keys="RecipeSubRecipe.parent_recipe_id", cascade="all, delete-orphan")
    used_in_recipes: Mapped[List["RecipeSubRecipe"]] = relationship("RecipeSubRecipe", foreign_keys="RecipeSubRecipe.child_recipe_id")
    steps: Mapped[List["RecipeStep"]] = relationship("RecipeStep", back_populates="recipe", cascade="all, delete-orphan")
    images: Mapped[List["RecipeImage"]] = relationship("RecipeImage", back_populates="recipe", cascade="all, delete-orphan")
    flags: Mapped[List["RecipeFlag"]] = relationship("RecipeFlag", back_populates="recipe", cascade="all, delete-orphan")
    change_log: Mapped[List["RecipeChangeLog"]] = relationship("RecipeChangeLog", back_populates="recipe", cascade="all, delete-orphan")
    cost_snapshots: Mapped[List["RecipeCostSnapshot"]] = relationship("RecipeCostSnapshot", back_populates="recipe", cascade="all, delete-orphan")


class RecipeIngredient(Base):
    """Ingredients used in a recipe"""
    __tablename__ = "recipe_ingredients"

    id: Mapped[int] = mapped_column(primary_key=True)
    recipe_id: Mapped[int] = mapped_column(ForeignKey("recipes.id", ondelete="CASCADE"), nullable=False, index=True)
    ingredient_id: Mapped[int] = mapped_column(ForeignKey("ingredients.id", ondelete="RESTRICT"), nullable=False)
    quantity: Mapped[Decimal] = mapped_column(Numeric(10, 3), nullable=False)
    unit: Mapped[Optional[str]] = mapped_column(String(10), nullable=True)  # override display unit (e.g. kg when std is g)
    yield_percent: Mapped[Decimal] = mapped_column(Numeric(5, 2), default=Decimal("100.00"))
    notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    sort_order: Mapped[int] = mapped_column(Integer, default=0)

    # Relationships
    recipe: Mapped["Recipe"] = relationship("Recipe", back_populates="ingredients")
    ingredient: Mapped["Ingredient"] = relationship("Ingredient")


class RecipeSubRecipe(Base):
    """Sub-recipes used in a recipe (max 5 levels deep)"""
    __tablename__ = "recipe_sub_recipes"

    id: Mapped[int] = mapped_column(primary_key=True)
    parent_recipe_id: Mapped[int] = mapped_column(ForeignKey("recipes.id", ondelete="CASCADE"), nullable=False, index=True)
    child_recipe_id: Mapped[int] = mapped_column(ForeignKey("recipes.id", ondelete="RESTRICT"), nullable=False, index=True)
    portions_needed: Mapped[Decimal] = mapped_column(Numeric(10, 3), nullable=False)
    portions_needed_unit: Mapped[Optional[str]] = mapped_column(String(10), nullable=True)  # override unit (e.g. ml when child yields ltr)
    notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    sort_order: Mapped[int] = mapped_column(Integer, default=0)

    __table_args__ = (
        CheckConstraint("parent_recipe_id != child_recipe_id", name="chk_no_self_reference"),
    )

    # Relationships
    parent_recipe: Mapped["Recipe"] = relationship("Recipe", foreign_keys=[parent_recipe_id], back_populates="sub_recipes")
    child_recipe: Mapped["Recipe"] = relationship("Recipe", foreign_keys=[child_recipe_id], overlaps="used_in_recipes")


class RecipeStep(Base):
    """Cooking instructions"""
    __tablename__ = "recipe_steps"

    id: Mapped[int] = mapped_column(primary_key=True)
    recipe_id: Mapped[int] = mapped_column(ForeignKey("recipes.id", ondelete="CASCADE"), nullable=False, index=True)
    step_number: Mapped[int] = mapped_column(Integer, nullable=False)
    title: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    instruction: Mapped[str] = mapped_column(Text, nullable=False)
    image_path: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)
    duration_minutes: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True)

    # Relationships
    recipe: Mapped["Recipe"] = relationship("Recipe", back_populates="steps")


class RecipeImage(Base):
    """General recipe/plating photos"""
    __tablename__ = "recipe_images"

    id: Mapped[int] = mapped_column(primary_key=True)
    recipe_id: Mapped[int] = mapped_column(ForeignKey("recipes.id", ondelete="CASCADE"), nullable=False, index=True)
    image_path: Mapped[str] = mapped_column(String(500), nullable=False)
    caption: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    image_type: Mapped[str] = mapped_column(String(20), default="general")  # "general" | "plating" | "method"
    sort_order: Mapped[int] = mapped_column(Integer, default=0)
    uploaded_by: Mapped[Optional[int]] = mapped_column(ForeignKey("users.id"), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)

    # Relationships
    recipe: Mapped["Recipe"] = relationship("Recipe", back_populates="images")
    uploaded_by_user: Mapped[Optional["User"]] = relationship("User", foreign_keys=[uploaded_by])


class RecipeChangeLog(Base):
    """Recipe change history"""
    __tablename__ = "recipe_change_log"

    id: Mapped[int] = mapped_column(primary_key=True)
    recipe_id: Mapped[int] = mapped_column(ForeignKey("recipes.id", ondelete="CASCADE"), nullable=False)
    change_summary: Mapped[str] = mapped_column(Text, nullable=False)
    user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("users.id"), nullable=True)
    source_invoice_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("invoices.id", ondelete="SET NULL"), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)

    # Relationships
    recipe: Mapped["Recipe"] = relationship("Recipe", back_populates="change_log")
    user: Mapped[Optional["User"]] = relationship("User", foreign_keys=[user_id])


class RecipeCostSnapshot(Base):
    """Cost trending over time (upsert: one snapshot per recipe per day)"""
    __tablename__ = "recipe_cost_snapshots"
    __table_args__ = (UniqueConstraint("recipe_id", "snapshot_date", name="uq_recipe_cost_snapshots_recipe_date"),)

    id: Mapped[int] = mapped_column(primary_key=True)
    recipe_id: Mapped[int] = mapped_column(ForeignKey("recipes.id", ondelete="CASCADE"), nullable=False, index=True)
    cost_per_portion: Mapped[Decimal] = mapped_column(Numeric(12, 6), nullable=False)
    total_cost: Mapped[Decimal] = mapped_column(Numeric(12, 6), nullable=False)
    snapshot_date: Mapped[date] = mapped_column(Date, nullable=False)
    trigger_source: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)

    # Relationships
    recipe: Mapped["Recipe"] = relationship("Recipe", back_populates="cost_snapshots")


class RecipeTextFlagDismissal(Base):
    """Tracks dismissed allergen keyword suggestions from recipe-level text fields"""
    __tablename__ = "recipe_text_flag_dismissals"
    __table_args__ = (UniqueConstraint("recipe_id", "food_flag_id", name="uq_recipe_text_flag_dismissals_recipe_flag"),)

    id: Mapped[int] = mapped_column(primary_key=True)
    recipe_id: Mapped[int] = mapped_column(ForeignKey("recipes.id", ondelete="CASCADE"), nullable=False, index=True)
    food_flag_id: Mapped[int] = mapped_column(ForeignKey("food_flags.id", ondelete="CASCADE"), nullable=False, index=True)
    dismissed_by_name: Mapped[str] = mapped_column(String(100), nullable=False)
    reason: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    matched_keyword: Mapped[Optional[str]] = mapped_column(String(200), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)

    # Relationships
    recipe: Mapped["Recipe"] = relationship("Recipe")
    food_flag: Mapped["FoodFlag"] = relationship("FoodFlag")


# Forward references
from .user import Kitchen, User
from .ingredient import Ingredient
from .food_flag import RecipeFlag, FoodFlag
