from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.orm import Session
from typing import Optional, List
from utils.utils import get_db
from . import handler
from .schema import (
    ConversationCreate,
    ConversationUpdate,
    ConversationResponse,
    ConversationDetailResponse,
    MessageCreate,
    MessageUpdate,
    MessageResponse
)

router = APIRouter(prefix="/conversations", tags=["Communication"])


@router.post(
    "/",
    response_model=ConversationResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Conversation",
    description="Creates a new conversation between two users. Validates that both participants exist and are different users. Optionally links the conversation to a listing or order context."
)
def create_conversation_route(data: ConversationCreate, db: Session = Depends(get_db)):
    return handler.create_conversation(db, data)


@router.get(
    "/",
    response_model=List[ConversationResponse],
    summary="List Conversations",
    description="Returns a paginated list of conversations. Supports optional filtering by participant IDs, listing ID, or order ID. Results are ordered by last message timestamp descending."
)
def list_conversations_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    participant1_id: Optional[str] = None,
    participant2_id: Optional[str] = None,
    listing_id: Optional[str] = None,
    order_id: Optional[str] = None,
    db: Session = Depends(get_db)
):
    return handler.list_conversations(db, limit, offset, participant1_id, participant2_id, listing_id, order_id)


@router.get(
    "/{conversation_id}",
    response_model=ConversationResponse,
    summary="Get Conversation",
    description="Returns a single conversation by ID. Returns 404 if the conversation does not exist."
)
def get_conversation_route(conversation_id: str, db: Session = Depends(get_db)):
    return handler.get_conversation(db, conversation_id)


@router.get(
    "/{conversation_id}/details",
    response_model=ConversationDetailResponse,
    summary="Get Conversation Details",
    description="Returns detailed conversation information including both participants, all messages with sender details, and optional listing or order context. All related data is eagerly loaded to avoid N+1 queries."
)
def get_conversation_details_route(conversation_id: str, db: Session = Depends(get_db)):
    return handler.get_conversation_details(db, conversation_id)


@router.put(
    "/{conversation_id}",
    response_model=ConversationResponse,
    summary="Update Conversation",
    description="Updates conversation details. Validates that any new participant IDs, listing ID, or order ID exist in the database. Returns 404 if the conversation does not exist."
)
def update_conversation_route(conversation_id: str, data: ConversationUpdate, db: Session = Depends(get_db)):
    return handler.update_conversation(db, conversation_id, data)


@router.delete(
    "/{conversation_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Conversation",
    description="Deletes a conversation and all associated messages. Returns 404 if the conversation does not exist."
)
def delete_conversation_route(conversation_id: str, db: Session = Depends(get_db)):
    return handler.delete_conversation(db, conversation_id)


@router.get(
    "/users/{user_id}/conversations",
    response_model=List[ConversationResponse],
    summary="Get User Conversations",
    description="Returns all conversations where the specified user is a participant (either participant1 or participant2). Results are ordered by last message timestamp descending."
)
def get_user_conversations_route(
    user_id: str,
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    db: Session = Depends(get_db)
):
    return handler.get_user_conversations(db, user_id, limit, offset)


message_router = APIRouter(prefix="/messages", tags=["Communication"])


@message_router.post(
    "/",
    response_model=MessageResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Message",
    description="Creates a new message in a conversation. Validates that the conversation exists, the sender exists, and the sender is a participant in the conversation. Updates the conversation's last_message_at timestamp."
)
def create_message_route(data: MessageCreate, db: Session = Depends(get_db)):
    return handler.create_message(db, data)


@message_router.get(
    "/",
    response_model=List[MessageResponse],
    summary="List Messages",
    description="Returns a paginated list of messages. Supports optional filtering by conversation ID, sender ID, or read status. Results are ordered by creation timestamp ascending."
)
def list_messages_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    conversation_id: Optional[str] = None,
    sender_id: Optional[str] = None,
    is_read: Optional[bool] = None,
    db: Session = Depends(get_db)
):
    return handler.list_messages(db, limit, offset, conversation_id, sender_id, is_read)


@message_router.get(
    "/{message_id}",
    response_model=MessageResponse,
    summary="Get Message",
    description="Returns a single message by ID. Returns 404 if the message does not exist."
)
def get_message_route(message_id: str, db: Session = Depends(get_db)):
    return handler.get_message(db, message_id)


@message_router.put(
    "/{message_id}",
    response_model=MessageResponse,
    summary="Update Message",
    description="Updates message details. Validates that any new conversation ID or sender ID exists in the database. Returns 404 if the message does not exist."
)
def update_message_route(message_id: str, data: MessageUpdate, db: Session = Depends(get_db)):
    return handler.update_message(db, message_id, data)


@message_router.delete(
    "/{message_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Message",
    description="Deletes a message. Returns 404 if the message does not exist."
)
def delete_message_route(message_id: str, db: Session = Depends(get_db)):
    return handler.delete_message(db, message_id)


@message_router.post(
    "/{message_id}/mark-read",
    response_model=MessageResponse,
    summary="Mark Message As Read",
    description="Marks a message as read by setting is_read to true and recording the read timestamp. If the message is already marked as read, returns the message unchanged."
)
def mark_message_as_read_route(message_id: str, db: Session = Depends(get_db)):
    return handler.mark_message_as_read(db, message_id)


router.include_router(message_router)