# app/api/v1/endpoints/chores.py
import logging
from typing import List as PyList, Optional

from fastapi import APIRouter, Depends, HTTPException, status, Response
from sqlalchemy.ext.asyncio import AsyncSession

from app.database import get_transactional_session, get_session
from app.auth import current_active_user
from app.models import User as UserModel, Chore as ChoreModel, ChoreTypeEnum
from app.schemas.chore import ChoreCreate, ChoreUpdate, ChorePublic, ChoreAssignmentCreate, ChoreAssignmentUpdate, ChoreAssignmentPublic
from app.crud import chore as crud_chore
from app.core.exceptions import ChoreNotFoundError, PermissionDeniedError, GroupNotFoundError, DatabaseIntegrityError

logger = logging.getLogger(__name__)
router = APIRouter()

# Add this new endpoint before the personal chores section
@router.get(
    "/all",
    response_model=PyList[ChorePublic],
    summary="List All Chores",
    tags=["Chores"]
)
async def list_all_chores(
    db: AsyncSession = Depends(get_session),  # Use read-only session for GET
    current_user: UserModel = Depends(current_active_user),
):
    """Retrieves all chores (personal and group) for the current user in a single optimized request."""
    logger.info(f"User {current_user.email} listing all their chores")
    
    # Use the optimized function that reduces database queries
    all_chores = await crud_chore.get_all_user_chores(db=db, user_id=current_user.id)
    
    return all_chores

# --- Personal Chores Endpoints ---

@router.post(
    "/personal",
    response_model=ChorePublic,
    status_code=status.HTTP_201_CREATED,
    summary="Create Personal Chore",
    tags=["Chores", "Personal Chores"]
)
async def create_personal_chore(
    chore_in: ChoreCreate,
    db: AsyncSession = Depends(get_transactional_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Creates a new personal chore for the current user."""
    logger.info(f"User {current_user.email} creating personal chore: {chore_in.name}")
    if chore_in.type != ChoreTypeEnum.personal:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Chore type must be personal.")
    if chore_in.group_id is not None:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="group_id must be null for personal chores.")
    try:
        return await crud_chore.create_chore(db=db, chore_in=chore_in, user_id=current_user.id)
    except ValueError as e:
        logger.warning(f"ValueError creating personal chore for user {current_user.email}: {str(e)}")
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except DatabaseIntegrityError as e:
        logger.error(f"DatabaseIntegrityError creating personal chore for {current_user.email}: {e.detail}", exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=e.detail)

@router.get(
    "/personal",
    response_model=PyList[ChorePublic],
    summary="List Personal Chores",
    tags=["Chores", "Personal Chores"]
)
async def list_personal_chores(
    db: AsyncSession = Depends(get_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Retrieves all personal chores for the current user."""
    logger.info(f"User {current_user.email} listing their personal chores")
    return await crud_chore.get_personal_chores(db=db, user_id=current_user.id)

@router.put(
    "/personal/{chore_id}",
    response_model=ChorePublic,
    summary="Update Personal Chore",
    tags=["Chores", "Personal Chores"]
)
async def update_personal_chore(
    chore_id: int,
    chore_in: ChoreUpdate,
    db: AsyncSession = Depends(get_transactional_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Updates a personal chore for the current user."""
    logger.info(f"User {current_user.email} updating personal chore ID: {chore_id}")
    if chore_in.type is not None and chore_in.type != ChoreTypeEnum.personal:
         raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot change chore type to group via this endpoint.")
    if chore_in.group_id is not None:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="group_id must be null for personal chores.")
    try:
        updated_chore = await crud_chore.update_chore(db=db, chore_id=chore_id, chore_in=chore_in, user_id=current_user.id, group_id=None)
        if not updated_chore:
            raise ChoreNotFoundError(chore_id=chore_id)
        if updated_chore.type != ChoreTypeEnum.personal or updated_chore.created_by_id != current_user.id:
            # This should ideally be caught by the CRUD layer permission checks
            raise PermissionDeniedError(detail="Chore is not a personal chore of the current user or does not exist.")
        return updated_chore
    except ChoreNotFoundError as e:
        logger.warning(f"Personal chore {e.chore_id} not found for user {current_user.email} during update.")
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=e.detail)
    except PermissionDeniedError as e:
        logger.warning(f"Permission denied for user {current_user.email} updating personal chore {chore_id}: {e.detail}")
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=e.detail)
    except ValueError as e:
        logger.warning(f"ValueError updating personal chore {chore_id} for user {current_user.email}: {str(e)}")
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except DatabaseIntegrityError as e:
        logger.error(f"DatabaseIntegrityError updating personal chore {chore_id} for {current_user.email}: {e.detail}", exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=e.detail)

@router.delete(
    "/personal/{chore_id}",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Delete Personal Chore",
    tags=["Chores", "Personal Chores"]
)
async def delete_personal_chore(
    chore_id: int,
    db: AsyncSession = Depends(get_transactional_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Deletes a personal chore for the current user."""
    logger.info(f"User {current_user.email} deleting personal chore ID: {chore_id}")
    try:
        # First, verify it's a personal chore belonging to the user
        chore_to_delete = await crud_chore.get_chore_by_id(db, chore_id)
        if not chore_to_delete or chore_to_delete.type != ChoreTypeEnum.personal or chore_to_delete.created_by_id != current_user.id:
            raise ChoreNotFoundError(chore_id=chore_id, detail="Personal chore not found or not owned by user.")

        success = await crud_chore.delete_chore(db=db, chore_id=chore_id, user_id=current_user.id, group_id=None)
        if not success:
            # This case should be rare if the above check passes and DB is consistent
            raise ChoreNotFoundError(chore_id=chore_id)
        return Response(status_code=status.HTTP_204_NO_CONTENT)
    except ChoreNotFoundError as e:
        logger.warning(f"Personal chore {e.chore_id} not found for user {current_user.email} during delete.")
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=e.detail)
    except PermissionDeniedError as e: # Should be caught by the check above
        logger.warning(f"Permission denied for user {current_user.email} deleting personal chore {chore_id}: {e.detail}")
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=e.detail)
    except DatabaseIntegrityError as e:
        logger.error(f"DatabaseIntegrityError deleting personal chore {chore_id} for {current_user.email}: {e.detail}", exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=e.detail)

# --- Group Chores Endpoints ---
# (These would be similar to what you might have had before, but now explicitly part of this router)

@router.post(
    "/groups/{group_id}/chores",
    response_model=ChorePublic,
    status_code=status.HTTP_201_CREATED,
    summary="Create Group Chore",
    tags=["Chores", "Group Chores"]
)
async def create_group_chore(
    group_id: int,
    chore_in: ChoreCreate,
    db: AsyncSession = Depends(get_transactional_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Creates a new chore within a specific group."""
    logger.info(f"User {current_user.email} creating chore in group {group_id}: {chore_in.name}")
    if chore_in.type != ChoreTypeEnum.group:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Chore type must be group.")
    if chore_in.group_id != group_id and chore_in.group_id is not None: # Make sure chore_in.group_id matches path if provided
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Chore's group_id ({chore_in.group_id}) must match path group_id ({group_id}) or be omitted.")
    
    # Ensure chore_in has the correct group_id and type for the CRUD operation
    chore_payload = chore_in.model_copy(update={"group_id": group_id, "type": ChoreTypeEnum.group})

    try:
        return await crud_chore.create_chore(db=db, chore_in=chore_payload, user_id=current_user.id, group_id=group_id)
    except GroupNotFoundError as e:
        logger.warning(f"Group {e.group_id} not found for chore creation by user {current_user.email}.")
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=e.detail)
    except PermissionDeniedError as e:
        logger.warning(f"Permission denied for user {current_user.email} in group {group_id} for chore creation: {e.detail}")
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=e.detail)
    except ValueError as e:
        logger.warning(f"ValueError creating group chore for user {current_user.email} in group {group_id}: {str(e)}")
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except DatabaseIntegrityError as e:
        logger.error(f"DatabaseIntegrityError creating group chore for {current_user.email} in group {group_id}: {e.detail}", exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=e.detail)

@router.get(
    "/groups/{group_id}/chores",
    response_model=PyList[ChorePublic],
    summary="List Group Chores",
    tags=["Chores", "Group Chores"]
)
async def list_group_chores(
    group_id: int,
    db: AsyncSession = Depends(get_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Retrieves all chores for a specific group, if the user is a member."""
    logger.info(f"User {current_user.email} listing chores for group {group_id}")
    try:
        return await crud_chore.get_chores_by_group_id(db=db, group_id=group_id, user_id=current_user.id)
    except PermissionDeniedError as e:
        logger.warning(f"Permission denied for user {current_user.email} accessing chores for group {group_id}: {e.detail}")
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=e.detail)

@router.put(
    "/groups/{group_id}/chores/{chore_id}",
    response_model=ChorePublic,
    summary="Update Group Chore",
    tags=["Chores", "Group Chores"]
)
async def update_group_chore(
    group_id: int,
    chore_id: int,
    chore_in: ChoreUpdate,
    db: AsyncSession = Depends(get_transactional_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Updates a chore's details within a specific group."""
    logger.info(f"User {current_user.email} updating chore ID {chore_id} in group {group_id}")
    if chore_in.type is not None and chore_in.type != ChoreTypeEnum.group:
         raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot change chore type to personal via this endpoint.")
    if chore_in.group_id is not None and chore_in.group_id != group_id:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Chore's group_id if provided must match path group_id ({group_id}).")

    # Ensure chore_in has the correct type for the CRUD operation
    chore_payload = chore_in.model_copy(update={"type": ChoreTypeEnum.group, "group_id": group_id} if chore_in.type is None else chore_in)

    try:
        updated_chore = await crud_chore.update_chore(db=db, chore_id=chore_id, chore_in=chore_payload, user_id=current_user.id, group_id=group_id)
        if not updated_chore:
            raise ChoreNotFoundError(chore_id=chore_id, group_id=group_id)
        return updated_chore
    except ChoreNotFoundError as e:
        logger.warning(f"Chore {e.chore_id} in group {e.group_id} not found for user {current_user.email} during update.")
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=e.detail)
    except PermissionDeniedError as e:
        logger.warning(f"Permission denied for user {current_user.email} updating chore {chore_id} in group {group_id}: {e.detail}")
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=e.detail)
    except ValueError as e:
        logger.warning(f"ValueError updating group chore {chore_id} for user {current_user.email} in group {group_id}: {str(e)}")
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except DatabaseIntegrityError as e:
        logger.error(f"DatabaseIntegrityError updating group chore {chore_id} for {current_user.email}: {e.detail}", exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=e.detail)

@router.delete(
    "/groups/{group_id}/chores/{chore_id}",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Delete Group Chore",
    tags=["Chores", "Group Chores"]
)
async def delete_group_chore(
    group_id: int,
    chore_id: int,
    db: AsyncSession = Depends(get_transactional_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Deletes a chore from a group, ensuring user has permission."""
    logger.info(f"User {current_user.email} deleting chore ID {chore_id} from group {group_id}")
    try:
        # Verify chore exists and belongs to the group before attempting deletion via CRUD
        # This gives a more precise error if the chore exists but isn't in this group.
        chore_to_delete = await crud_chore.get_chore_by_id_and_group(db, chore_id, group_id, current_user.id) # checks permission too
        if not chore_to_delete : # get_chore_by_id_and_group will raise PermissionDeniedError if user not member
             raise ChoreNotFoundError(chore_id=chore_id, group_id=group_id)

        success = await crud_chore.delete_chore(db=db, chore_id=chore_id, user_id=current_user.id, group_id=group_id)
        if not success:
             # This case should be rare if the above check passes and DB is consistent
            raise ChoreNotFoundError(chore_id=chore_id, group_id=group_id)
        return Response(status_code=status.HTTP_204_NO_CONTENT)
    except ChoreNotFoundError as e:
        logger.warning(f"Chore {e.chore_id} in group {e.group_id} not found for user {current_user.email} during delete.")
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=e.detail)
    except PermissionDeniedError as e:
        logger.warning(f"Permission denied for user {current_user.email} deleting chore {chore_id} in group {group_id}: {e.detail}")
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=e.detail)
    except DatabaseIntegrityError as e:
        logger.error(f"DatabaseIntegrityError deleting group chore {chore_id} for {current_user.email}: {e.detail}", exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=e.detail)

# === CHORE ASSIGNMENT ENDPOINTS ===

@router.post(
    "/assignments",
    response_model=ChoreAssignmentPublic,
    status_code=status.HTTP_201_CREATED,
    summary="Create Chore Assignment",
    tags=["Chore Assignments"]
)
async def create_chore_assignment(
    assignment_in: ChoreAssignmentCreate,
    db: AsyncSession = Depends(get_transactional_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Creates a new chore assignment. User must have permission to manage the chore."""
    logger.info(f"User {current_user.email} creating assignment for chore {assignment_in.chore_id}")
    try:
        return await crud_chore.create_chore_assignment(db=db, assignment_in=assignment_in, user_id=current_user.id)
    except ChoreNotFoundError as e:
        logger.warning(f"Chore {e.chore_id} not found for assignment creation by user {current_user.email}.")
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=e.detail)
    except PermissionDeniedError as e:
        logger.warning(f"Permission denied for user {current_user.email} creating assignment: {e.detail}")
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=e.detail)
    except ValueError as e:
        logger.warning(f"ValueError creating assignment for user {current_user.email}: {str(e)}")
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except DatabaseIntegrityError as e:
        logger.error(f"DatabaseIntegrityError creating assignment for {current_user.email}: {e.detail}", exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=e.detail)

@router.get(
    "/assignments/my",
    response_model=PyList[ChoreAssignmentPublic],
    summary="List My Chore Assignments",
    tags=["Chore Assignments"]
)
async def list_my_assignments(
    include_completed: bool = False,
    db: AsyncSession = Depends(get_session),  # Use read-only session for GET
    current_user: UserModel = Depends(current_active_user),
):
    """Retrieves all chore assignments for the current user."""
    logger.info(f"User {current_user.email} listing their assignments (include_completed={include_completed})")
    try:
        return await crud_chore.get_user_assignments(db=db, user_id=current_user.id, include_completed=include_completed)
    except Exception as e:
        logger.error(f"Error listing assignments for user {current_user.email}: {e}", exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to retrieve assignments")

@router.get(
    "/chores/{chore_id}/assignments",
    response_model=PyList[ChoreAssignmentPublic],
    summary="List Chore Assignments",
    tags=["Chore Assignments"]
)
async def list_chore_assignments(
    chore_id: int,
    db: AsyncSession = Depends(get_session),  # Use read-only session for GET
    current_user: UserModel = Depends(current_active_user),
):
    """Retrieves all assignments for a specific chore."""
    logger.info(f"User {current_user.email} listing assignments for chore {chore_id}")
    try:
        return await crud_chore.get_chore_assignments(db=db, chore_id=chore_id, user_id=current_user.id)
    except ChoreNotFoundError as e:
        logger.warning(f"Chore {e.chore_id} not found for assignment listing by user {current_user.email}.")
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=e.detail)
    except PermissionDeniedError as e:
        logger.warning(f"Permission denied for user {current_user.email} listing assignments for chore {chore_id}: {e.detail}")
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=e.detail)

@router.put(
    "/assignments/{assignment_id}",
    response_model=ChoreAssignmentPublic,
    summary="Update Chore Assignment",
    tags=["Chore Assignments"]
)
async def update_chore_assignment(
    assignment_id: int,
    assignment_in: ChoreAssignmentUpdate,
    db: AsyncSession = Depends(get_transactional_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Updates a chore assignment. Only assignee can mark complete, managers can reschedule."""
    logger.info(f"User {current_user.email} updating assignment {assignment_id}")
    try:
        updated_assignment = await crud_chore.update_chore_assignment(
            db=db, assignment_id=assignment_id, assignment_in=assignment_in, user_id=current_user.id
        )
        if not updated_assignment:
            raise ChoreNotFoundError(assignment_id=assignment_id)
        return updated_assignment
    except ChoreNotFoundError as e:
        logger.warning(f"Assignment {assignment_id} not found for user {current_user.email} during update.")
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=e.detail)
    except PermissionDeniedError as e:
        logger.warning(f"Permission denied for user {current_user.email} updating assignment {assignment_id}: {e.detail}")
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=e.detail)
    except ValueError as e:
        logger.warning(f"ValueError updating assignment {assignment_id} for user {current_user.email}: {str(e)}")
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except DatabaseIntegrityError as e:
        logger.error(f"DatabaseIntegrityError updating assignment {assignment_id} for {current_user.email}: {e.detail}", exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=e.detail)

@router.delete(
    "/assignments/{assignment_id}",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Delete Chore Assignment",
    tags=["Chore Assignments"]
)
async def delete_chore_assignment(
    assignment_id: int,
    db: AsyncSession = Depends(get_transactional_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Deletes a chore assignment. User must have permission to manage the chore."""
    logger.info(f"User {current_user.email} deleting assignment {assignment_id}")
    try:
        success = await crud_chore.delete_chore_assignment(db=db, assignment_id=assignment_id, user_id=current_user.id)
        if not success:
            raise ChoreNotFoundError(assignment_id=assignment_id)
        return Response(status_code=status.HTTP_204_NO_CONTENT)
    except ChoreNotFoundError as e:
        logger.warning(f"Assignment {assignment_id} not found for user {current_user.email} during delete.")
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=e.detail)
    except PermissionDeniedError as e:
        logger.warning(f"Permission denied for user {current_user.email} deleting assignment {assignment_id}: {e.detail}")
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=e.detail)
    except DatabaseIntegrityError as e:
        logger.error(f"DatabaseIntegrityError deleting assignment {assignment_id} for {current_user.email}: {e.detail}", exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=e.detail)

@router.patch(
    "/assignments/{assignment_id}/complete",
    response_model=ChoreAssignmentPublic,
    summary="Mark Assignment Complete",
    tags=["Chore Assignments"]
)
async def complete_chore_assignment(
    assignment_id: int,
    db: AsyncSession = Depends(get_transactional_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Convenience endpoint to mark an assignment as complete."""
    logger.info(f"User {current_user.email} marking assignment {assignment_id} as complete")
    assignment_update = ChoreAssignmentUpdate(is_complete=True)
    try:
        updated_assignment = await crud_chore.update_chore_assignment(
            db=db, assignment_id=assignment_id, assignment_in=assignment_update, user_id=current_user.id
        )
        if not updated_assignment:
            raise ChoreNotFoundError(assignment_id=assignment_id)
        return updated_assignment
    except ChoreNotFoundError as e:
        logger.warning(f"Assignment {assignment_id} not found for user {current_user.email} during completion.")
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=e.detail)
    except PermissionDeniedError as e:
        logger.warning(f"Permission denied for user {current_user.email} completing assignment {assignment_id}: {e.detail}")
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=e.detail)
    except DatabaseIntegrityError as e:
        logger.error(f"DatabaseIntegrityError completing assignment {assignment_id} for {current_user.email}: {e.detail}", exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=e.detail)