from fastapi import APIRouter, Depends, HTTPException, status, Query
from ...shared.utils.response_helpers import success_response, error_response
from sqlalchemy.orm import Session, joinedload
from sqlalchemy import func
from typing import Optional
from ...shared.config.database import get_db
from ...shared.config.logging_config import get_logger
from ...security.middleware.auth import get_current_user, authorize_roles
from ...auth.models.user import User
from ..models.review import Review, ReviewStatus
from ...rooms.models.room import Room
from ..schemas.review import CreateReviewRequest

logger = get_logger(__name__)
router = APIRouter(prefix='/reviews', tags=['reviews'])

@router.get('/room/{room_id}')
async def get_room_reviews(
    room_id: int,
    page: int = Query(1, ge=1),
    limit: int = Query(10, ge=1, le=100),
    db: Session = Depends(get_db)
):
    try:
        # Calculate average rating and total reviews for approved reviews
        stats = db.query(
            func.avg(Review.rating).label('average_rating'),
            func.count(Review.id).label('total_reviews')
        ).filter(
            Review.room_id == room_id,
            Review.status == ReviewStatus.approved
        ).first()
        
        average_rating = round(float(stats.average_rating or 0), 1) if stats and stats.average_rating else 0
        total_reviews = stats.total_reviews or 0 if stats else 0
        
        query = db.query(Review).options(
            joinedload(Review.user)
        ).filter(Review.room_id == room_id, Review.status == ReviewStatus.approved)
        total = query.count()
        offset = (page - 1) * limit
        reviews = query.order_by(Review.created_at.desc()).offset(offset).limit(limit).all()
        result = []
        for review in reviews:
            review_dict = {
                'id': review.id, 
                'user_id': review.user_id, 
                'room_id': review.room_id, 
                'rating': review.rating, 
                'comment': review.comment, 
                'status': review.status.value if isinstance(review.status, ReviewStatus) else review.status, 
                'created_at': review.created_at.isoformat() if review.created_at else None
            }
            if review.user:
                review_dict['user'] = {
                    'id': review.user.id, 
                    'full_name': review.user.full_name, 
                    'name': review.user.full_name,  # Add name alias for compatibility
                    'email': review.user.email
                }
            result.append(review_dict)
        return {
            'status': 'success',
            'data': {
                'reviews': result,
                'average_rating': average_rating,
                'total_reviews': total_reviews,
                'pagination': {
                    'total': total,
                    'page': page,
                    'limit': limit,
                    'totalPages': (total + limit - 1) // limit
                }
            }
        }
    except Exception as e:
        db.rollback()
        logger.error(f'Error fetching room reviews: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

@router.get('/', dependencies=[Depends(authorize_roles('admin'))])
async def get_all_reviews(status_filter: Optional[str]=Query(None, alias='status'), page: int=Query(1, ge=1), limit: int=Query(10, ge=1, le=100), current_user: User=Depends(authorize_roles('admin')), db: Session=Depends(get_db)):
    try:
        query = db.query(Review).options(
            joinedload(Review.user),
            joinedload(Review.room).joinedload(Room.room_type)
        )
        if status_filter:
            try:
                query = query.filter(Review.status == ReviewStatus(status_filter))
            except ValueError:
                pass
        total = query.count()
        offset = (page - 1) * limit
        reviews = query.order_by(Review.created_at.desc()).offset(offset).limit(limit).all()
        result = []
        for review in reviews:
            review_dict = {'id': review.id, 'user_id': review.user_id, 'room_id': review.room_id, 'rating': review.rating, 'comment': review.comment, 'status': review.status.value if isinstance(review.status, ReviewStatus) else review.status, 'created_at': review.created_at.isoformat() if review.created_at else None}
            if review.user:
                review_dict['user'] = {
                    'id': review.user.id, 
                    'full_name': review.user.full_name, 
                    'name': review.user.full_name,  # Add name alias for frontend compatibility
                    'email': review.user.email, 
                    'phone': review.user.phone
                }
            if review.room:
                room_dict = {
                    'id': review.room.id, 
                    'room_number': review.room.room_number
                }
                # Include room type if available
                if review.room.room_type:
                    room_dict['room_type'] = {
                        'id': review.room.room_type.id,
                        'name': review.room.room_type.name
                    }
                review_dict['room'] = room_dict
            result.append(review_dict)
        return {'status': 'success', 'data': {'reviews': result, 'pagination': {'total': total, 'page': page, 'limit': limit, 'totalPages': (total + limit - 1) // limit}}}
    except Exception as e:
        db.rollback()
        logger.error(f'Error fetching all reviews: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

@router.post('/')
async def create_review(review_data: CreateReviewRequest, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
    try:
        room_id = review_data.room_id
        rating = review_data.rating
        # Ensure comment is a string (not None) since the model requires it
        comment = review_data.comment if review_data.comment else ''
        
        room = db.query(Room).filter(Room.id == room_id).first()
        if not room:
            raise HTTPException(
                status_code=404, 
                detail=error_response(message='Room not found')
            )
        
        existing = db.query(Review).filter(Review.user_id == current_user.id, Review.room_id == room_id).first()
        if existing:
            raise HTTPException(
                status_code=400, 
                detail=error_response(message='You have already reviewed this room')
            )
        
        review = Review(
            user_id=current_user.id, 
            room_id=room_id, 
            rating=rating, 
            comment=comment or '',  # Ensure comment is a string
            status=ReviewStatus.pending
        )
        db.add(review)
        db.commit()
        db.refresh(review)
        
        review_dict = {
            'id': review.id,
            'user_id': review.user_id,
            'room_id': review.room_id,
            'rating': review.rating,
            'comment': review.comment,
            'status': review.status.value if isinstance(review.status, ReviewStatus) else review.status,
            'created_at': review.created_at.isoformat() if review.created_at else None
        }
        
        return success_response(
            data={'review': review_dict},
            message='Review submitted successfully and is pending approval'
        )
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f'Error creating review: {str(e)}', exc_info=True)
        raise HTTPException(
            status_code=500, 
            detail=error_response(message='An error occurred while creating the review')
        )

@router.patch('/{id}/approve', dependencies=[Depends(authorize_roles('admin'))])
async def approve_review(id: int, current_user: User=Depends(authorize_roles('admin')), db: Session=Depends(get_db)):
    try:
        review = db.query(Review).filter(Review.id == id).first()
        if not review:
            raise HTTPException(
                status_code=404, 
                detail=error_response(message='Review not found')
            )
        review.status = ReviewStatus.approved
        db.commit()
        db.refresh(review)
        
        review_dict = {
            'id': review.id,
            'user_id': review.user_id,
            'room_id': review.room_id,
            'rating': review.rating,
            'comment': review.comment,
            'status': review.status.value if isinstance(review.status, ReviewStatus) else review.status,
            'created_at': review.created_at.isoformat() if review.created_at else None
        }
        
        return success_response(
            data={'review': review_dict},
            message='Review approved successfully'
        )
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f'Error approving review: {str(e)}', exc_info=True)
        raise HTTPException(
            status_code=500, 
            detail=error_response(message='An error occurred while approving the review')
        )

@router.patch('/{id}/reject', dependencies=[Depends(authorize_roles('admin'))])
async def reject_review(id: int, current_user: User=Depends(authorize_roles('admin')), db: Session=Depends(get_db)):
    try:
        review = db.query(Review).filter(Review.id == id).first()
        if not review:
            raise HTTPException(
                status_code=404, 
                detail=error_response(message='Review not found')
            )
        review.status = ReviewStatus.rejected
        db.commit()
        db.refresh(review)
        
        review_dict = {
            'id': review.id,
            'user_id': review.user_id,
            'room_id': review.room_id,
            'rating': review.rating,
            'comment': review.comment,
            'status': review.status.value if isinstance(review.status, ReviewStatus) else review.status,
            'created_at': review.created_at.isoformat() if review.created_at else None
        }
        
        return success_response(
            data={'review': review_dict},
            message='Review rejected successfully'
        )
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f'Error rejecting review: {str(e)}', exc_info=True)
        raise HTTPException(
            status_code=500, 
            detail=error_response(message='An error occurred while rejecting the review')
        )

@router.delete('/{id}', dependencies=[Depends(authorize_roles('admin'))])
async def delete_review(id: int, current_user: User=Depends(authorize_roles('admin')), db: Session=Depends(get_db)):
    try:
        review = db.query(Review).filter(Review.id == id).first()
        if not review:
            raise HTTPException(status_code=404, detail='Review not found')
        db.delete(review)
        db.commit()
        return {'status': 'success', 'message': 'Review deleted successfully'}
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f'Error deleting review: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))