"""Recipe CRUD + use routes."""

from __future__ import annotations

from app.auth import AuthenticatedUser, get_current_user
from app.dependencies import get_db_session, get_user_repository
from app.schemas.recipe import (
    CreateRecipeRequest,
    ListRecipesResponse,
    RecipeItemResponse,
    RecipeResponse,
    UpdateRecipeRequest,
    UseRecipeResponse,
)
from fastapi import APIRouter, Depends, HTTPException, Query, Response, status
from sqlalchemy.orm import Session

from packages.adapters.sqlalchemy_impl.recipe_repository import SQLAlchemyRecipeRepository
from packages.application.recipe.commands import (
    CreateRecipeCommand,
    RecipeItemCommand,
    UpdateRecipeCommand,
)
from packages.application.recipe.use_cases import (
    CreateRecipeUseCase,
    DeleteRecipeUseCase,
    FeatureDisabledError,
    GetRecipeUseCase,
    ListRecipesUseCase,
    NotFoundError,
    UpdateRecipeUseCase,
    UseRecipeUseCase,
)
from packages.ports.user_repository import UserRepository

router = APIRouter()


def _get_recipe_repository(session: Session = Depends(get_db_session)) -> SQLAlchemyRecipeRepository:
    return SQLAlchemyRecipeRepository(session)


def _get_user_plan(user_id: str, user_repository: UserRepository) -> str:
    user = user_repository.find_by_id(user_id)
    if user is None:
        return "free"
    return getattr(user, "subscription_plan", "free") or "free"


def _item_to_response(item) -> RecipeItemResponse:
    return RecipeItemResponse(
        id=item.id,
        recipe_id=item.recipe_id,
        item_type=item.item_type,
        item_id=item.item_id,
        position=item.position,
        metadata=item.metadata_,
    )


def _to_response(recipe) -> RecipeResponse:
    return RecipeResponse(
        id=recipe.id,
        user_id=recipe.user_id,
        name=recipe.name,
        description=recipe.description,
        template_id=recipe.template_id,
        generation_params=recipe.generation_params,
        items=[_item_to_response(i) for i in getattr(recipe, "items", [])],
        is_active=recipe.is_active,
        metadata=recipe.metadata_,
        created_at=recipe.created_at,
        updated_at=recipe.updated_at,
    )


@router.get("", response_model=ListRecipesResponse)
def list_recipes(
    skip: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=200),
    authenticated_user: AuthenticatedUser = Depends(get_current_user),
    recipe_repository: SQLAlchemyRecipeRepository = Depends(_get_recipe_repository),
) -> ListRecipesResponse:
    user_id = authenticated_user.user.id
    use_case = ListRecipesUseCase(recipe_repository)
    recipes = use_case.execute(user_id, skip=skip, limit=limit)
    total = recipe_repository.count_by_user(user_id)
    return ListRecipesResponse(
        items=[_to_response(r) for r in recipes],
        total=total,
    )


@router.get("/{recipe_id}", response_model=RecipeResponse)
def get_recipe(
    recipe_id: str,
    authenticated_user: AuthenticatedUser = Depends(get_current_user),
    recipe_repository: SQLAlchemyRecipeRepository = Depends(_get_recipe_repository),
) -> RecipeResponse:
    user_id = authenticated_user.user.id
    use_case = GetRecipeUseCase(recipe_repository)
    recipe = use_case.execute(recipe_id, user_id)
    if recipe is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Recipe not found")
    return _to_response(recipe)


@router.post("", response_model=RecipeResponse, status_code=status.HTTP_201_CREATED)
def create_recipe(
    request: CreateRecipeRequest,
    authenticated_user: AuthenticatedUser = Depends(get_current_user),
    recipe_repository: SQLAlchemyRecipeRepository = Depends(_get_recipe_repository),
) -> RecipeResponse:
    user_id = authenticated_user.user.id
    command = CreateRecipeCommand(
        user_id=user_id,
        name=request.name,
        description=request.description,
        template_id=request.template_id,
        generation_params=request.generation_params,
        items=[
            RecipeItemCommand(
                item_type=ic.item_type,
                item_id=ic.item_id,
                position=ic.position,
                metadata_=ic.metadata_,
            )
            for ic in request.items
        ],
        metadata_=request.metadata_,
    )
    use_case = CreateRecipeUseCase(recipe_repository)
    recipe = use_case.execute(command)
    return _to_response(recipe)


@router.patch("/{recipe_id}", response_model=RecipeResponse)
def update_recipe(
    recipe_id: str,
    request: UpdateRecipeRequest,
    authenticated_user: AuthenticatedUser = Depends(get_current_user),
    recipe_repository: SQLAlchemyRecipeRepository = Depends(_get_recipe_repository),
) -> RecipeResponse:
    user_id = authenticated_user.user.id
    command = UpdateRecipeCommand(
        recipe_id=recipe_id,
        user_id=user_id,
        name=request.name,
        description=request.description,
        template_id=request.template_id,
        generation_params=request.generation_params,
        items=(
            [
                RecipeItemCommand(
                    item_type=ic.item_type,
                    item_id=ic.item_id,
                    position=ic.position,
                    metadata_=ic.metadata_,
                )
                for ic in request.items
            ]
            if request.items is not None
            else None
        ),
        metadata_=request.metadata_,
    )
    use_case = UpdateRecipeUseCase(recipe_repository)
    try:
        recipe = use_case.execute(command)
    except NotFoundError:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Recipe not found")
    return _to_response(recipe)


@router.delete("/{recipe_id}", status_code=status.HTTP_204_NO_CONTENT, response_model=None)
def delete_recipe(
    recipe_id: str,
    authenticated_user: AuthenticatedUser = Depends(get_current_user),
    recipe_repository: SQLAlchemyRecipeRepository = Depends(_get_recipe_repository),
) -> Response:
    user_id = authenticated_user.user.id
    use_case = DeleteRecipeUseCase(recipe_repository)
    deleted = use_case.execute(recipe_id, user_id)
    if not deleted:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Recipe not found")
    return Response(status_code=204)


@router.post("/{recipe_id}/use", response_model=UseRecipeResponse)
def use_recipe(
    recipe_id: str,
    authenticated_user: AuthenticatedUser = Depends(get_current_user),
    recipe_repository: SQLAlchemyRecipeRepository = Depends(_get_recipe_repository),
    user_repository: UserRepository = Depends(get_user_repository),
) -> UseRecipeResponse:
    user_id = authenticated_user.user.id
    plan_name = _get_user_plan(user_id, user_repository)
    use_case = UseRecipeUseCase(recipe_repository)
    try:
        result = use_case.execute(recipe_id, user_id, user_plan=plan_name)
    except FeatureDisabledError as exc:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=str(exc),
        )
    except NotFoundError:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Recipe not found")

    return UseRecipeResponse(
        recipe=_to_response(result.recipe),
        warnings=[{"item_type": w.item_type, "item_id": w.item_id, "position": w.position} for w in result.warnings],
    )
