# app/api/v1/endpoints/invites.py
import logging
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession

from app.database import get_transactional_session
from app.auth import current_active_user
from app.models import User as UserModel, UserRoleEnum
from app.schemas.invite import InviteAccept
from app.schemas.message import Message
from app.schemas.group import GroupPublic
from app.crud import invite as crud_invite
from app.crud import group as crud_group
from app.core.exceptions import (
    InviteNotFoundError,
    InviteExpiredError,
    InviteAlreadyUsedError,
    InviteCreationError,
    GroupNotFoundError,
    GroupMembershipError,
    GroupOperationError
)

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

@router.post(
    "/accept", # Route relative to prefix "/invites"
    response_model=GroupPublic,
    summary="Accept Group Invite",
    tags=["Invites"]
)
async def accept_invite(
    invite_in: InviteAccept,
    db: AsyncSession = Depends(get_transactional_session),
    current_user: UserModel = Depends(current_active_user),
):
    """Accepts a group invite using the provided invite code."""
    logger.info(f"User {current_user.email} attempting to accept invite code: {invite_in.code}")
    
    # Get the invite - this function should only return valid, active invites
    invite = await crud_invite.get_active_invite_by_code(db, code=invite_in.code)
    if not invite:
        logger.warning(f"Invalid or inactive invite code attempted by user {current_user.email}: {invite_in.code}")
        # We can use a more generic error or a specific one. InviteNotFound is reasonable.
        raise InviteNotFoundError(invite_in.code)

    # Check if group still exists
    group = await crud_group.get_group_by_id(db, group_id=invite.group_id)
    if not group:
        logger.error(f"Group {invite.group_id} not found for invite {invite_in.code}")
        raise GroupNotFoundError(invite.group_id)

    # Check if user is already a member
    is_member = await crud_group.is_user_member(db, group_id=invite.group_id, user_id=current_user.id)
    if is_member:
        logger.warning(f"User {current_user.email} already a member of group {invite.group_id}")
        raise GroupMembershipError(invite.group_id, "join (already a member)")

    # Add user to the group
    added_to_group = await crud_group.add_user_to_group(db, group_id=invite.group_id, user_id=current_user.id)
    if not added_to_group:
        logger.error(f"Failed to add user {current_user.email} to group {invite.group_id} during invite acceptance.")
        # This could be a race condition or other issue, treat as an operational error.
        raise GroupOperationError("Failed to add user to group.")

    # Deactivate the invite so it cannot be used again
    await crud_invite.deactivate_invite(db, invite=invite)
    
    logger.info(f"User {current_user.email} successfully joined group {invite.group_id} via invite {invite_in.code}")
    
    # Re-fetch the group to get the updated member list
    updated_group = await crud_group.get_group_by_id(db, group_id=invite.group_id)
    if not updated_group:
        # This should ideally not happen as we found it before
        logger.error(f"Could not re-fetch group {invite.group_id} after user {current_user.email} joined.")
        raise GroupNotFoundError(invite.group_id)
        
    return updated_group