import uuid

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session

from app.api.deps import get_current_principal, get_project_or_404, require_role
from app.db.session import get_db
from app.models.dataset import Dataset, DatasetExample, ExampleStatus
from app.models.org import User, UserRole
from app.models.prompt import Prompt
from app.models.stubs import Conversation
from app.schemas.conversation import (
    ConversationOut,
    CreateConversationRequest,
    FeedbackRequest,
    PromoteRequest,
    SendMessageRequest,
)
from app.schemas.dataset import DatasetExampleOut
from app.services.conversation import send_message

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


def _get_conversation_or_404(conversation_id: uuid.UUID, db: Session, current_user: User) -> Conversation:
    conversation = db.get(Conversation, conversation_id)
    if conversation is None:
        raise HTTPException(status_code=404, detail="Conversation not found")
    get_project_or_404(conversation.project_id, db, current_user)
    return conversation


@router.post("", response_model=ConversationOut, status_code=201)
def create_conversation(
    payload: CreateConversationRequest,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_role(UserRole.editor)),
):
    get_project_or_404(payload.project_id, db, current_user)

    system_prompt = payload.system_prompt_override
    if payload.prompt_id:
        prompt = db.get(Prompt, payload.prompt_id)
        if prompt is None or prompt.org_id != current_user.org_id:
            raise HTTPException(status_code=404, detail="Prompt not found")
        system_prompt = prompt.content

    messages = [{"role": "system", "content": system_prompt}] if system_prompt else []

    conversation = Conversation(
        project_id=payload.project_id,
        user_id=current_user.id,
        model_name=payload.model_name,
        title=payload.title,
        messages=messages,
    )
    db.add(conversation)
    db.commit()
    db.refresh(conversation)
    return conversation


@router.get("", response_model=list[ConversationOut])
def list_conversations(
    project_id: uuid.UUID = Query(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_principal),
):
    get_project_or_404(project_id, db, current_user)
    return (
        db.query(Conversation)
        .filter(Conversation.project_id == project_id)
        .order_by(Conversation.updated_at.desc())
        .all()
    )


@router.get("/{conversation_id}", response_model=ConversationOut)
def get_conversation(
    conversation_id: uuid.UUID, db: Session = Depends(get_db), current_user: User = Depends(get_current_principal)
):
    return _get_conversation_or_404(conversation_id, db, current_user)


@router.post("/{conversation_id}/messages", response_model=ConversationOut)
def post_message(
    conversation_id: uuid.UUID,
    payload: SendMessageRequest,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_role(UserRole.editor)),
):
    conversation = _get_conversation_or_404(conversation_id, db, current_user)

    history = list(conversation.messages) + [{"role": "user", "content": payload.content}]
    assistant_message = send_message(db, conversation.project_id, conversation.model_name, history, payload.use_rag)
    history.append(assistant_message)

    conversation.messages = history
    if conversation.title is None:
        conversation.title = payload.content[:80]
    db.commit()
    db.refresh(conversation)
    return conversation


@router.patch("/{conversation_id}/feedback", response_model=ConversationOut)
def submit_feedback(
    conversation_id: uuid.UUID,
    payload: FeedbackRequest,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_principal),
):
    conversation = _get_conversation_or_404(conversation_id, db, current_user)
    feedback = dict(conversation.feedback or {})
    events = list(feedback.get("events", []))
    events.append(
        {
            "rating": payload.rating,
            "message_index": payload.message_index,
            "notes": payload.notes,
            "user_id": str(current_user.id),
        }
    )
    feedback["events"] = events
    conversation.feedback = feedback
    db.commit()
    db.refresh(conversation)
    return conversation


@router.post("/{conversation_id}/promote", response_model=DatasetExampleOut, status_code=201)
def promote_to_dataset(
    conversation_id: uuid.UUID,
    payload: PromoteRequest,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_role(UserRole.editor)),
):
    """Continuous Learning (Module 15): turn a good conversation turn into a candidate
    training example, routed through the same review queue as generated examples."""
    conversation = _get_conversation_or_404(conversation_id, db, current_user)

    if payload.message_index < 0 or payload.message_index >= len(conversation.messages):
        raise HTTPException(status_code=400, detail="message_index out of range")
    assistant_message = conversation.messages[payload.message_index]
    if assistant_message.get("role") != "assistant":
        raise HTTPException(status_code=400, detail="message_index must point to an assistant message")

    user_message = next(
        (m for m in reversed(conversation.messages[: payload.message_index]) if m.get("role") == "user"), None
    )
    if user_message is None:
        raise HTTPException(status_code=400, detail="No preceding user message found for this turn")

    dataset = db.get(Dataset, payload.dataset_id)
    if dataset is None or dataset.project_id != conversation.project_id:
        raise HTTPException(status_code=404, detail="Dataset not found in this project")

    example = DatasetExample(
        dataset_id=dataset.id,
        instruction=user_message["content"],
        output=assistant_message["content"],
        status=ExampleStatus.pending,
        generated_by="continuous-learning",
        source_conversation_id=conversation.id,
    )
    db.add(example)
    db.commit()
    db.refresh(example)
    return example


@router.get("/stats/promoted", response_model=dict)
def promoted_stats(
    project_id: uuid.UUID = Query(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_principal),
):
    get_project_or_404(project_id, db, current_user)
    rows = (
        db.query(DatasetExample)
        .join(Dataset, Dataset.id == DatasetExample.dataset_id)
        .filter(Dataset.project_id == project_id, DatasetExample.source_conversation_id.isnot(None))
        .all()
    )
    by_status: dict[str, int] = {}
    for row in rows:
        by_status[row.status.value] = by_status.get(row.status.value, 0) + 1
    return {"total_promoted": len(rows), "by_status": by_status}


@router.delete("/{conversation_id}", status_code=204)
def delete_conversation(
    conversation_id: uuid.UUID, db: Session = Depends(get_db), current_user: User = Depends(require_role(UserRole.editor))
):
    conversation = _get_conversation_or_404(conversation_id, db, current_user)
    db.delete(conversation)
    db.commit()
