"""
双人对练房间 API

功能：
- 房间创建、加入、退出
- 房间状态查询
- 实时消息推送（SSE）
- 消息发送
"""
import asyncio
import logging
from datetime import datetime
from typing import Optional, List
from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi.responses import StreamingResponse
from sqlalchemy.ext.asyncio import AsyncSession
from pydantic import BaseModel, Field

from app.core.deps import get_db, get_current_user
from app.models.user import User
from app.services.practice_room_service import PracticeRoomService

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/practice/rooms", tags=["双人对练房间"])


# ==================== Schema 定义 ====================

class CreateRoomRequest(BaseModel):
    """创建房间请求"""
    scene_id: Optional[int] = Field(None, description="场景ID")
    scene_name: Optional[str] = Field(None, description="场景名称")
    scene_type: Optional[str] = Field(None, description="场景类型")
    scene_background: Optional[str] = Field(None, description="场景背景")
    role_a_name: str = Field("销售顾问", description="角色A名称")
    role_b_name: str = Field("顾客", description="角色B名称")
    role_a_description: Optional[str] = Field(None, description="角色A描述")
    role_b_description: Optional[str] = Field(None, description="角色B描述")
    host_role: str = Field("A", description="房主选择的角色(A/B)")
    room_name: Optional[str] = Field(None, description="房间名称")


class JoinRoomRequest(BaseModel):
    """加入房间请求"""
    room_code: str = Field(..., description="房间码")


class SendMessageRequest(BaseModel):
    """发送消息请求"""
    content: str = Field(..., description="消息内容")
    source: Optional[str] = Field("text", description="消息来源: text/voice")


class WebRTCSignalRequest(BaseModel):
    """WebRTC 信令请求"""
    signal_type: str = Field(..., description="信令类型: voice_offer/voice_answer/ice_candidate/voice_start/voice_end")
    payload: dict = Field(..., description="信令数据（SDP/ICE候选等）")


class RoomResponse(BaseModel):
    """房间响应"""
    id: int
    room_code: str
    room_name: Optional[str]
    scene_id: Optional[int]
    scene_name: Optional[str]
    scene_type: Optional[str]
    role_a_name: str
    role_b_name: str
    host_user_id: int
    guest_user_id: Optional[int]
    host_role: str
    status: str
    created_at: datetime
    started_at: Optional[datetime]
    ended_at: Optional[datetime]
    duration_seconds: int
    total_turns: int

    class Config:
        from_attributes = True


class RoomDetailResponse(BaseModel):
    """房间详情响应（包含用户信息）"""
    room: RoomResponse
    host_user: Optional[dict]
    guest_user: Optional[dict]
    host_role_name: Optional[str]
    guest_role_name: Optional[str]
    my_role: Optional[str]
    my_role_name: Optional[str]


class MessageResponse(BaseModel):
    """消息响应"""
    id: int
    room_id: int
    user_id: Optional[int]
    message_type: str
    content: Optional[str]
    role_name: Optional[str]
    sequence: int
    created_at: datetime

    class Config:
        from_attributes = True


# ==================== API 端点 ====================

@router.post("", summary="创建房间")
async def create_room(
    request: CreateRoomRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    创建双人对练房间
    
    - 返回房间码，可分享给对方加入
    - 房主可选择扮演角色A或B
    """
    service = PracticeRoomService(db)
    
    try:
        room = await service.create_room(
            host_user_id=current_user.id,
            scene_id=request.scene_id,
            scene_name=request.scene_name,
            scene_type=request.scene_type,
            scene_background=request.scene_background,
            role_a_name=request.role_a_name,
            role_b_name=request.role_b_name,
            role_a_description=request.role_a_description,
            role_b_description=request.role_b_description,
            host_role=request.host_role,
            room_name=request.room_name
        )
        
        return {
            "code": 200,
            "message": "房间创建成功",
            "data": {
                "room_code": room.room_code,
                "room_id": room.id,
                "room_name": room.room_name,
                "my_role": room.host_role,
                "my_role_name": room.get_role_name(room.host_role)
            }
        }
    except Exception as e:
        logger.error(f"创建房间失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/join", summary="加入房间")
async def join_room(
    request: JoinRoomRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    通过房间码加入房间
    
    - 房间最多容纳2人
    - 加入后自动分配对方角色
    """
    service = PracticeRoomService(db)
    
    try:
        room = await service.join_room(
            room_code=request.room_code.upper(),
            user_id=current_user.id
        )
        
        my_role = room.get_user_role(current_user.id)
        
        return {
            "code": 200,
            "message": "加入房间成功",
            "data": {
                "room_code": room.room_code,
                "room_id": room.id,
                "room_name": room.room_name,
                "status": room.status,
                "my_role": my_role,
                "my_role_name": room.get_role_name(my_role)
            }
        }
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"加入房间失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/{room_code}", summary="获取房间详情")
async def get_room(
    room_code: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    获取房间详情，包含参与者信息
    """
    service = PracticeRoomService(db)
    
    room_data = await service.get_room_with_users(room_code.upper())
    if not room_data:
        raise HTTPException(status_code=404, detail="房间不存在")
    
    room = room_data["room"]
    host_user = room_data["host_user"]
    guest_user = room_data["guest_user"]
    
    my_role = room.get_user_role(current_user.id)
    
    return {
        "code": 200,
        "message": "success",
        "data": {
            "room": {
                "id": room.id,
                "room_code": room.room_code,
                "room_name": room.room_name,
                "scene_id": room.scene_id,
                "scene_name": room.scene_name,
                "scene_type": room.scene_type,
                "scene_background": room.scene_background,
                "role_a_name": room.role_a_name,
                "role_b_name": room.role_b_name,
                "role_a_description": room.role_a_description,
                "role_b_description": room.role_b_description,
                "host_role": room.host_role,
                "status": room.status,
                "created_at": room.created_at.isoformat() if room.created_at else None,
                "started_at": room.started_at.isoformat() if room.started_at else None,
                "ended_at": room.ended_at.isoformat() if room.ended_at else None,
                "duration_seconds": room.duration_seconds,
                "total_turns": room.total_turns,
                "role_a_turns": room.role_a_turns,
                "role_b_turns": room.role_b_turns
            },
            "host_user": {
                "id": host_user.id,
                "username": host_user.username,
                "full_name": host_user.full_name,
                "avatar_url": host_user.avatar_url
            } if host_user else None,
            "guest_user": {
                "id": guest_user.id,
                "username": guest_user.username,
                "full_name": guest_user.full_name,
                "avatar_url": guest_user.avatar_url
            } if guest_user else None,
            "host_role_name": room_data["host_role_name"],
            "guest_role_name": room_data["guest_role_name"],
            "my_role": my_role,
            "my_role_name": room.get_role_name(my_role) if my_role else None,
            "is_host": current_user.id == room.host_user_id
        }
    }


@router.post("/{room_code}/start", summary="开始对练")
async def start_practice(
    room_code: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    开始对练（仅房主可操作）
    
    - 需要房间状态为 ready（双方都已加入）
    """
    service = PracticeRoomService(db)
    
    try:
        room = await service.start_practice(
            room_code=room_code.upper(),
            user_id=current_user.id
        )
        
        return {
            "code": 200,
            "message": "对练已开始",
            "data": {
                "room_code": room.room_code,
                "status": room.status,
                "started_at": room.started_at.isoformat() if room.started_at else None
            }
        }
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"开始对练失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/{room_code}/end", summary="结束对练")
async def end_practice(
    room_code: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    结束对练
    
    - 任意参与者都可结束
    - 结束后可查看分析报告
    """
    service = PracticeRoomService(db)
    
    try:
        room = await service.end_practice(
            room_code=room_code.upper(),
            user_id=current_user.id
        )
        
        return {
            "code": 200,
            "message": "对练已结束",
            "data": {
                "room_code": room.room_code,
                "room_id": room.id,
                "status": room.status,
                "duration_seconds": room.duration_seconds,
                "total_turns": room.total_turns
            }
        }
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"结束对练失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/{room_code}/leave", summary="离开房间")
async def leave_room(
    room_code: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    离开房间
    
    - 房主离开则关闭房间
    - 嘉宾离开则房间回到等待状态
    """
    service = PracticeRoomService(db)
    
    success = await service.leave_room(
        room_code=room_code.upper(),
        user_id=current_user.id
    )
    
    if not success:
        raise HTTPException(status_code=400, detail="离开房间失败")
    
    return {
        "code": 200,
        "message": "已离开房间"
    }


@router.post("/{room_code}/message", summary="发送消息")
async def send_message(
    room_code: str,
    request: SendMessageRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    发送聊天消息
    
    - 仅对练中状态可发送
    """
    service = PracticeRoomService(db)
    
    # 获取房间
    room = await service.get_room_by_code(room_code.upper())
    if not room:
        raise HTTPException(status_code=404, detail="房间不存在")
    
    if room.status != "practicing":
        raise HTTPException(status_code=400, detail="对练未在进行中")
    
    # 获取用户角色
    role_name = room.get_user_role_name(current_user.id)
    if not role_name:
        raise HTTPException(status_code=403, detail="您不是房间参与者")
    
    # 发送消息
    message = await service.send_message(
        room_id=room.id,
        user_id=current_user.id,
        content=request.content,
        role_name=role_name
    )
    
    return {
        "code": 200,
        "message": "发送成功",
        "data": message.to_dict()
    }


@router.post("/{room_code}/signal", summary="发送WebRTC信令")
async def send_signal(
    room_code: str,
    request: WebRTCSignalRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    发送 WebRTC 信令消息
    
    信令类型：
    - voice_start: 发起语音通话
    - voice_offer: SDP Offer
    - voice_answer: SDP Answer
    - ice_candidate: ICE 候选
    - voice_end: 结束语音通话
    """
    service = PracticeRoomService(db)
    
    # 获取房间
    room = await service.get_room_by_code(room_code.upper())
    if not room:
        raise HTTPException(status_code=404, detail="房间不存在")
    
    # 检查用户是否在房间中
    user_role = room.get_user_role(current_user.id)
    if not user_role:
        raise HTTPException(status_code=403, detail="您不是房间参与者")
    
    # 验证信令类型
    valid_signal_types = ["voice_start", "voice_offer", "voice_answer", "ice_candidate", "voice_end"]
    if request.signal_type not in valid_signal_types:
        raise HTTPException(status_code=400, detail=f"无效的信令类型，必须是: {', '.join(valid_signal_types)}")
    
    # 发送信令消息（作为系统消息存储，用于 SSE 推送）
    message = await service.send_message(
        room_id=room.id,
        user_id=current_user.id,
        content=None,  # 信令消息不需要文本内容
        role_name=None,
        message_type=request.signal_type,
        extra_data=request.payload
    )
    
    return {
        "code": 200,
        "message": "信令发送成功",
        "data": {
            "signal_type": request.signal_type,
            "sequence": message.sequence
        }
    }


@router.get("/{room_code}/messages", summary="获取消息列表")
async def get_messages(
    room_code: str,
    since_sequence: int = Query(0, description="从该序号之后开始获取"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    获取房间消息列表
    
    - 用于轮询获取新消息
    - 传入 since_sequence 只获取新消息
    """
    service = PracticeRoomService(db)
    
    room = await service.get_room_by_code(room_code.upper())
    if not room:
        raise HTTPException(status_code=404, detail="房间不存在")
    
    messages = await service.get_messages(
        room_id=room.id,
        since_sequence=since_sequence
    )
    
    return {
        "code": 200,
        "message": "success",
        "data": {
            "messages": [msg.to_dict() for msg in messages],
            "room_status": room.status,
            "last_sequence": messages[-1].sequence if messages else since_sequence
        }
    }


@router.get("/{room_code}/stream", summary="消息流（SSE）")
async def message_stream(
    room_code: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    实时消息流（Server-Sent Events）
    
    - 用于实时接收房间消息
    - 前端使用 EventSource 连接
    """
    service = PracticeRoomService(db)
    
    room = await service.get_room_by_code(room_code.upper())
    if not room:
        raise HTTPException(status_code=404, detail="房间不存在")
    
    async def event_generator():
        last_sequence = 0
        
        while True:
            # 获取新消息
            messages = await service.get_messages(
                room_id=room.id,
                since_sequence=last_sequence
            )
            
            for msg in messages:
                yield f"event: message\ndata: {msg.to_dict()}\n\n"
                last_sequence = msg.sequence
            
            # 检查房间状态
            room_status = await service.get_room_by_id(room.id)
            if room_status and room_status.status in ["completed", "canceled"]:
                yield f"event: room_closed\ndata: {{\"status\": \"{room_status.status}\"}}\n\n"
                break
            
            # 等待一段时间再轮询
            await asyncio.sleep(0.5)
    
    return StreamingResponse(
        event_generator(),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "X-Accel-Buffering": "no"
        }
    )


@router.get("/{room_code}/report", summary="获取或生成对练报告")
async def get_practice_report(
    room_code: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    获取双人对练报告
    
    - 如果报告不存在，则调用 AI 生成
    - 返回双方表现评估
    """
    from app.services.ai.duo_practice_analysis_service import DuoPracticeAnalysisService
    
    service = PracticeRoomService(db)
    
    # 获取房间详情
    room_data = await service.get_room_with_users(room_code.upper())
    if not room_data:
        raise HTTPException(status_code=404, detail="房间不存在")
    
    room = room_data["room"]
    
    # 检查房间是否已完成
    if room.status != "completed":
        raise HTTPException(status_code=400, detail="对练尚未结束，无法生成报告")
    
    # 获取所有消息
    messages = await service.get_all_messages(room.id)
    chat_messages = [m for m in messages if m.message_type == "chat"]
    
    if not chat_messages:
        raise HTTPException(status_code=400, detail="暂无对话记录")
    
    # 准备对话历史
    dialogue_history = [
        {
            "sequence": m.sequence,
            "role_name": m.role_name,
            "content": m.content,
            "user_id": m.user_id
        }
        for m in chat_messages
    ]
    
    # 获取用户名称
    host_name = room_data["host_user"].full_name if room_data["host_user"] else "用户A"
    guest_name = room_data["guest_user"].full_name if room_data["guest_user"] else "用户B"
    
    # 确定角色对应的用户名
    if room.host_role == "A":
        user_a_name = host_name
        user_b_name = guest_name
    else:
        user_a_name = guest_name
        user_b_name = host_name
    
    # 调用 AI 分析
    analysis_service = DuoPracticeAnalysisService()
    result = await analysis_service.analyze(
        scene_name=room.scene_name or "双人对练",
        scene_background=room.scene_background or "",
        role_a_name=room.role_a_name,
        role_b_name=room.role_b_name,
        role_a_description=room.role_a_description or f"扮演{room.role_a_name}",
        role_b_description=room.role_b_description or f"扮演{room.role_b_name}",
        user_a_name=user_a_name,
        user_b_name=user_b_name,
        dialogue_history=dialogue_history,
        duration_seconds=room.duration_seconds,
        total_turns=room.total_turns,
        db=db
    )
    
    return {
        "code": 200,
        "message": "success",
        "data": {
            "room": {
                "id": room.id,
                "room_code": room.room_code,
                "room_name": room.room_name,
                "scene_name": room.scene_name,
                "duration_seconds": room.duration_seconds,
                "total_turns": room.total_turns
            },
            "analysis": analysis_service.result_to_dict(result)
        }
    }


@router.get("", summary="获取我的房间列表")
async def get_my_rooms(
    status: Optional[str] = Query(None, description="按状态筛选"),
    limit: int = Query(20, description="数量限制"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    获取当前用户的房间列表
    """
    service = PracticeRoomService(db)
    
    rooms = await service.get_user_rooms(
        user_id=current_user.id,
        status=status,
        limit=limit
    )
    
    return {
        "code": 200,
        "message": "success",
        "data": {
            "rooms": [
                {
                    "id": room.id,
                    "room_code": room.room_code,
                    "room_name": room.room_name,
                    "scene_name": room.scene_name,
                    "status": room.status,
                    "is_host": room.host_user_id == current_user.id,
                    "created_at": room.created_at.isoformat() if room.created_at else None,
                    "duration_seconds": room.duration_seconds,
                    "total_turns": room.total_turns
                }
                for room in rooms
            ]
        }
    }


@router.get("/{room_code}/report", summary="获取对练报告")
async def get_practice_report(
    room_code: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    获取双人对练报告
    
    包含：
    - 房间基本信息
    - 参与者信息
    - 对话统计分析
    - 表现评估
    - 改进建议
    """
    service = PracticeRoomService(db)
    
    # 通过房间码获取房间
    room = await service.get_room_by_code(room_code)
    if not room:
        raise HTTPException(status_code=404, detail="房间不存在")
    
    # 验证用户权限
    if current_user.id not in [room.host_user_id, room.guest_user_id]:
        raise HTTPException(status_code=403, detail="无权查看此报告")
    
    # 生成报告
    report = await service.generate_report(room.id)
    if not report:
        raise HTTPException(status_code=404, detail="无法生成报告")
    
    return {
        "code": 200,
        "message": "success",
        "data": report
    }
