"""
Recipe management API endpoints.
"""

import logging
from typing import List, Optional
from datetime import datetime

from fastapi import APIRouter, HTTPException, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func

from ....shared.database import get_db
from ....shared.models.recipe import Recipe
from ....shared.schemas.recipe import (
    RecipeCreate, RecipeUpdate, RecipeResponse, RecipeList, RecipeSummary
)


logger = logging.getLogger(__name__)

router = APIRouter()


@router.get("/", response_model=RecipeList)
async def list_recipes(
    skip: int = Query(0, ge=0, description="Number of recipes to skip"),
    limit: int = Query(50, ge=1, le=100, description="Maximum number of recipes to return"),
    active_only: bool = Query(False, description="Return only active recipes"),
    search: Optional[str] = Query(None, description="Search recipes by name"),
    db: AsyncSession = Depends(get_db)
):
    """Get list of recipes with pagination and filtering."""
    try:
        # Build query
        query = select(Recipe)
        
        if active_only:
            query = query.where(Recipe.is_active == True)
        
        if search:
            query = query.where(Recipe.name.ilike(f"%{search}%"))
        
        # Get total count
        count_query = select(func.count(Recipe.id))
        if active_only:
            count_query = count_query.where(Recipe.is_active == True)
        if search:
            count_query = count_query.where(Recipe.name.ilike(f"%{search}%"))
        
        total_result = await db.execute(count_query)
        total = total_result.scalar() or 0
        
        # Get paginated results
        query = query.order_by(Recipe.created_at.desc()).offset(skip).limit(limit)
        result = await db.execute(query)
        recipes = result.scalars().all()
        
        return RecipeList(
            recipes=[RecipeResponse.from_orm(recipe) for recipe in recipes],
            total=total,
            page=(skip // limit) + 1,
            per_page=limit
        )
        
    except Exception as e:
        logger.error(f"Error listing recipes: {e}")
        raise HTTPException(status_code=500, detail="Failed to retrieve recipes")


@router.post("/", response_model=RecipeResponse, status_code=201)
async def create_recipe(
    recipe_data: RecipeCreate,
    db: AsyncSession = Depends(get_db)
):
    """Create a new recipe."""
    try:
        # Check if recipe name already exists
        existing_query = select(Recipe).where(Recipe.name == recipe_data.name)
        existing_result = await db.execute(existing_query)
        existing_recipe = existing_result.scalar_one_or_none()
        
        if existing_recipe:
            raise HTTPException(
                status_code=409, 
                detail=f"Recipe with name '{recipe_data.name}' already exists"
            )
        
        # Create new recipe
        new_recipe = Recipe(
            name=recipe_data.name,
            description=recipe_data.description,
            heating_goal=recipe_data.heating_goal,
            cooling_goal=recipe_data.cooling_goal,
            pouring_goal=recipe_data.pouring_goal,
            tank_temp=recipe_data.tank_temp,
            fountain_temp=recipe_data.fountain_temp,
            mixer_enabled=recipe_data.mixer_enabled,
            fountain_enabled=recipe_data.fountain_enabled,
            mold_heater_enabled=recipe_data.mold_heater_enabled,
            vibration_enabled=recipe_data.vibration_enabled,
            vib_heater_enabled=recipe_data.vib_heater_enabled,
            pedal_control_enabled=recipe_data.pedal_control_enabled,
            pedal_on_time=recipe_data.pedal_on_time,
            pedal_off_time=recipe_data.pedal_off_time,
            created_at=datetime.now(),
        )
        
        # Validate recipe parameters
        if not new_recipe.validate_temperatures():
            raise HTTPException(
                status_code=400,
                detail="Invalid temperature parameters"
            )
        
        db.add(new_recipe)
        await db.commit()
        await db.refresh(new_recipe)
        
        logger.info(f"Created new recipe: {new_recipe.name} (ID: {new_recipe.id})")
        
        return RecipeResponse.from_orm(new_recipe)
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error creating recipe: {e}")
        await db.rollback()
        raise HTTPException(status_code=500, detail="Failed to create recipe")


@router.get("/{recipe_id}", response_model=RecipeResponse)
async def get_recipe(
    recipe_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Get a specific recipe by ID."""
    try:
        query = select(Recipe).where(Recipe.id == recipe_id)
        result = await db.execute(query)
        recipe = result.scalar_one_or_none()
        
        if not recipe:
            raise HTTPException(status_code=404, detail="Recipe not found")
        
        return RecipeResponse.from_orm(recipe)
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error retrieving recipe {recipe_id}: {e}")
        raise HTTPException(status_code=500, detail="Failed to retrieve recipe")


@router.put("/{recipe_id}", response_model=RecipeResponse)
async def update_recipe(
    recipe_id: int,
    recipe_update: RecipeUpdate,
    db: AsyncSession = Depends(get_db)
):
    """Update an existing recipe."""
    try:
        # Get existing recipe
        query = select(Recipe).where(Recipe.id == recipe_id)
        result = await db.execute(query)
        recipe = result.scalar_one_or_none()
        
        if not recipe:
            raise HTTPException(status_code=404, detail="Recipe not found")
        
        # Update fields that are provided
        update_data = recipe_update.dict(exclude_unset=True)
        
        for field, value in update_data.items():
            setattr(recipe, field, value)
        
        # Update metadata
        recipe.updated_at = datetime.now()
        recipe.version += 1
        
        # Validate updated recipe
        if not recipe.validate_temperatures():
            raise HTTPException(
                status_code=400,
                detail="Invalid temperature parameters"
            )
        
        await db.commit()
        await db.refresh(recipe)
        
        logger.info(f"Updated recipe: {recipe.name} (ID: {recipe.id})")
        
        return RecipeResponse.from_orm(recipe)
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error updating recipe {recipe_id}: {e}")
        await db.rollback()
        raise HTTPException(status_code=500, detail="Failed to update recipe")


@router.delete("/{recipe_id}", status_code=204)
async def delete_recipe(
    recipe_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Delete a recipe (soft delete by setting inactive)."""
    try:
        # Get existing recipe
        query = select(Recipe).where(Recipe.id == recipe_id)
        result = await db.execute(query)
        recipe = result.scalar_one_or_none()
        
        if not recipe:
            raise HTTPException(status_code=404, detail="Recipe not found")
        
        # Soft delete by setting inactive
        recipe.is_active = False
        recipe.updated_at = datetime.now()
        
        await db.commit()
        
        logger.info(f"Deleted recipe: {recipe.name} (ID: {recipe.id})")
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error deleting recipe {recipe_id}: {e}")
        await db.rollback()
        raise HTTPException(status_code=500, detail="Failed to delete recipe")


@router.post("/{recipe_id}/duplicate", response_model=RecipeResponse, status_code=201)
async def duplicate_recipe(
    recipe_id: int,
    new_name: str = Query(..., description="Name for the duplicated recipe"),
    db: AsyncSession = Depends(get_db)
):
    """Duplicate an existing recipe with a new name."""
    try:
        # Get source recipe
        query = select(Recipe).where(Recipe.id == recipe_id)
        result = await db.execute(query)
        source_recipe = result.scalar_one_or_none()
        
        if not source_recipe:
            raise HTTPException(status_code=404, detail="Source recipe not found")
        
        # Check if new name already exists
        name_query = select(Recipe).where(Recipe.name == new_name)
        name_result = await db.execute(name_query)
        existing_recipe = name_result.scalar_one_or_none()
        
        if existing_recipe:
            raise HTTPException(
                status_code=409,
                detail=f"Recipe with name '{new_name}' already exists"
            )
        
        # Create duplicate
        duplicate_recipe = Recipe(
            name=new_name,
            description=f"Copy of {source_recipe.name}",
            heating_goal=source_recipe.heating_goal,
            cooling_goal=source_recipe.cooling_goal,
            pouring_goal=source_recipe.pouring_goal,
            tank_temp=source_recipe.tank_temp,
            fountain_temp=source_recipe.fountain_temp,
            mixer_enabled=source_recipe.mixer_enabled,
            fountain_enabled=source_recipe.fountain_enabled,
            mold_heater_enabled=source_recipe.mold_heater_enabled,
            vibration_enabled=source_recipe.vibration_enabled,
            vib_heater_enabled=source_recipe.vib_heater_enabled,
            pedal_control_enabled=source_recipe.pedal_control_enabled,
            pedal_on_time=source_recipe.pedal_on_time,
            pedal_off_time=source_recipe.pedal_off_time,
            created_at=datetime.now(),
        )
        
        db.add(duplicate_recipe)
        await db.commit()
        await db.refresh(duplicate_recipe)
        
        logger.info(f"Duplicated recipe: {source_recipe.name} -> {new_name} (ID: {duplicate_recipe.id})")
        
        return RecipeResponse.from_orm(duplicate_recipe)
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error duplicating recipe {recipe_id}: {e}")
        await db.rollback()
        raise HTTPException(status_code=500, detail="Failed to duplicate recipe")


@router.get("/{recipe_id}/validate")
async def validate_recipe(
    recipe_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Validate a recipe's parameters."""
    try:
        query = select(Recipe).where(Recipe.id == recipe_id)
        result = await db.execute(query)
        recipe = result.scalar_one_or_none()
        
        if not recipe:
            raise HTTPException(status_code=404, detail="Recipe not found")
        
        # Validate recipe
        is_valid = recipe.validate_temperatures()
        
        validation_result = {
            "recipe_id": recipe_id,
            "is_valid": is_valid,
            "checks": {
                "temperature_ranges": True,  # Would implement detailed checks
                "cooling_less_than_heating": recipe.cooling_goal < recipe.heating_goal,
                "pouring_within_range": (
                    recipe.pouring_goal is None or
                    (recipe.cooling_goal <= recipe.pouring_goal <= recipe.heating_goal)
                ),
            }
        }
        
        if not is_valid:
            validation_result["errors"] = [
                "Temperature parameters are invalid"
            ]
        
        return validation_result
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error validating recipe {recipe_id}: {e}")
        raise HTTPException(status_code=500, detail="Failed to validate recipe")


@router.get("/summary/active", response_model=List[RecipeSummary])
async def get_active_recipes_summary(
    db: AsyncSession = Depends(get_db)
):
    """Get summary of all active recipes."""
    try:
        query = select(Recipe).where(Recipe.is_active == True).order_by(Recipe.name)
        result = await db.execute(query)
        recipes = result.scalars().all()
        
        return [RecipeSummary.from_orm(recipe) for recipe in recipes]
        
    except Exception as e:
        logger.error(f"Error getting active recipes summary: {e}")
        raise HTTPException(status_code=500, detail="Failed to get active recipes")