"""SQLAlchemy implementation of RecipeRepository."""

from __future__ import annotations

from typing import List, Optional

from sqlalchemy.orm import Session

from packages.adapters.sqlalchemy_impl.models import RecipeItemModel, RecipeModel
from packages.domain.recipe import Recipe, RecipeItem


class SQLAlchemyRecipeRepository:
    """SQLAlchemy 配方仓储"""

    def __init__(self, session: Session) -> None:
        self.session = session

    def list_by_user(
        self,
        user_id: str,
        *,
        skip: int = 0,
        limit: int = 50,
    ) -> List[Recipe]:
        models = (
            self.session.query(RecipeModel)
            .filter(
                RecipeModel.user_id == user_id,
                RecipeModel.is_active.is_(True),
            )
            .order_by(RecipeModel.created_at.desc())
            .offset(skip)
            .limit(limit)
            .all()
        )
        recipes = [self._model_to_entity(m) for m in models]
        # Load items for each recipe
        for recipe in recipes:
            recipe.items = self.list_items(recipe.id)
        return recipes

    def get(self, recipe_id: str, user_id: str) -> Optional[Recipe]:
        model = (
            self.session.query(RecipeModel)
            .filter(
                RecipeModel.id == recipe_id,
                RecipeModel.user_id == user_id,
            )
            .first()
        )
        if model is None:
            return None
        recipe = self._model_to_entity(model)
        recipe.items = self.list_items(recipe.id)
        return recipe

    def create(self, recipe: Recipe) -> Recipe:
        model = RecipeModel(
            id=recipe.id,
            user_id=recipe.user_id,
            name=recipe.name,
            description=recipe.description,
            template_id=recipe.template_id,
            generation_params=recipe.generation_params,
            is_active=recipe.is_active,
            extra_meta=recipe.metadata_,
        )
        self.session.add(model)
        self.session.commit()
        self.session.refresh(model)
        result = self._model_to_entity(model)
        result.items = recipe.items
        return result

    def update(self, recipe: Recipe) -> Recipe:
        model = (
            self.session.query(RecipeModel)
            .filter(
                RecipeModel.id == recipe.id,
                RecipeModel.user_id == recipe.user_id,
            )
            .first()
        )
        if model is None:
            raise ValueError(f"Recipe {recipe.id} not found")
        model.name = recipe.name
        model.description = recipe.description
        model.template_id = recipe.template_id
        model.generation_params = recipe.generation_params
        model.is_active = recipe.is_active
        model.extra_meta = recipe.metadata_
        self.session.commit()
        self.session.refresh(model)
        result = self._model_to_entity(model)
        result.items = recipe.items
        return result

    def delete(self, recipe_id: str, user_id: str) -> bool:
        model = (
            self.session.query(RecipeModel)
            .filter(
                RecipeModel.id == recipe_id,
                RecipeModel.user_id == user_id,
            )
            .first()
        )
        if model is None:
            return False
        model.is_active = False
        self.session.commit()
        return True

    def count_by_user(self, user_id: str, is_active: bool = True) -> int:
        return (
            self.session.query(RecipeModel)
            .filter(
                RecipeModel.user_id == user_id,
                RecipeModel.is_active == is_active,
            )
            .count()
        )

    def list_items(self, recipe_id: str) -> List[RecipeItem]:
        models = (
            self.session.query(RecipeItemModel)
            .filter(RecipeItemModel.recipe_id == recipe_id)
            .order_by(RecipeItemModel.position)
            .all()
        )
        return [self._item_model_to_entity(m) for m in models]

    def create_items(self, items: List[RecipeItem]) -> List[RecipeItem]:
        for item in items:
            model = RecipeItemModel(
                id=item.id,
                recipe_id=item.recipe_id,
                item_type=item.item_type,
                item_id=item.item_id,
                position=item.position,
                extra_meta=item.metadata_,
            )
            self.session.add(model)
        self.session.commit()
        return items

    def delete_items_by_recipe(self, recipe_id: str) -> int:
        count = self.session.query(RecipeItemModel).filter(RecipeItemModel.recipe_id == recipe_id).delete()
        self.session.commit()
        return count

    @staticmethod
    def _model_to_entity(model: RecipeModel) -> Recipe:
        return Recipe(
            id=model.id,
            user_id=model.user_id,
            name=model.name,
            description=model.description or "",
            template_id=model.template_id or "",
            generation_params=model.generation_params or {},
            is_active=model.is_active,
            metadata_=model.extra_meta or {},
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def _item_model_to_entity(model: RecipeItemModel) -> RecipeItem:
        return RecipeItem(
            id=model.id,
            recipe_id=model.recipe_id,
            item_type=model.item_type,
            item_id=model.item_id,
            position=model.position or 0,
            metadata_=model.extra_meta or {},
        )
