"""Room CRUD router."""

from datetime import datetime
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Query, status
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session

from app.database import get_db
from app.models.floor import Floor
from app.models.panorama import Panorama
from app.models.room import Room
from app.models.user import User
from app.schemas.room import RoomCreate, RoomRead, RoomUpdate, ROOM_TYPES
from app.services.auth_service import get_current_user
from app.utils.helpers import generate_uuid, paginate

router = APIRouter()


# ── Custom schemas ─────────────────────────────────────────────────────── #

class ReorderBody(BaseModel):
    sort_order: int = Field(..., ge=0)


class RoomMergeBody(BaseModel):
    source_room_id: str
    target_room_id: str


class RoomSplitBody(BaseModel):
    new_room_name: str = Field(..., min_length=1, max_length=200)
    new_room_type: str = Field(..., pattern=f"^({'|'.join(ROOM_TYPES)})$")
    panorama_ids: list[str] = Field(..., min_length=1)


# ── Helpers ────────────────────────────────────────────────────────────── #

def get_room_or_404(room_id: str, db: Session) -> Room:
    room = db.query(Room).filter(Room.id == room_id).first()
    if not room:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="房间不存在",
        )
    return room


# ── Endpoints ──────────────────────────────────────────────────────────── #

@router.get(
    "/api/floors/{fid}/rooms",
    response_model=dict,
    summary="获取楼层房间列表",
)
def list_rooms(
    fid: str,
    page: int = Query(1, ge=1),
    size: int = Query(50, ge=1, le=200),
    db: Session = Depends(get_db),
    _: User = Depends(get_current_user),
):
    """List all rooms on a floor (paginated)."""
    floor = db.query(Floor).filter(Floor.id == fid).first()
    if not floor:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="楼层不存在",
        )

    query = (
        db.query(Room)
        .filter(Room.floor_id == fid)
        .order_by(Room.sort_order)
    )
    result = paginate(query, page=page, size=size)

    return {
        "items": [RoomRead.model_validate(r) for r in result["items"]],
        "total": result["total"],
        "page": result["page"],
        "size": result["size"],
        "pages": result["pages"],
    }


@router.post(
    "/api/floors/{fid}/rooms",
    response_model=RoomRead,
    status_code=status.HTTP_201_CREATED,
    summary="创建房间",
)
def create_room(
    fid: str,
    body: RoomCreate,
    db: Session = Depends(get_db),
    _: User = Depends(get_current_user),
):
    """Create a new room on a floor."""
    floor = db.query(Floor).filter(Floor.id == fid).first()
    if not floor:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="楼层不存在",
        )

    room = Room(
        id=generate_uuid(),
        floor_id=fid,
        name=body.name,
        type=body.type,
        sort_order=body.sort_order,
        cover_pano_id=body.cover_pano_id,
        created_at=datetime.utcnow(),
        updated_at=datetime.utcnow(),
    )
    db.add(room)
    db.commit()
    db.refresh(room)

    return RoomRead.model_validate(room)


@router.put("/api/rooms/{id}", response_model=RoomRead, summary="更新房间")
def update_room(
    id: str,
    body: RoomUpdate,
    db: Session = Depends(get_db),
    _: User = Depends(get_current_user),
):
    """Update a room."""
    room = get_room_or_404(id, db)

    update_data = body.model_dump(exclude_unset=True)
    for field, value in update_data.items():
        setattr(room, field, value)
    room.updated_at = datetime.utcnow()

    db.commit()
    db.refresh(room)
    return RoomRead.model_validate(room)


@router.delete("/api/rooms/{id}", status_code=status.HTTP_200_OK, summary="删除房间")
def delete_room(
    id: str,
    db: Session = Depends(get_db),
    _: User = Depends(get_current_user),
):
    """Delete a room."""
    room = get_room_or_404(id, db)
    db.delete(room)
    db.commit()

    return {"message": "房间已删除", "room_id": id}


@router.put("/api/rooms/{id}/reorder", response_model=RoomRead, summary="重排房间")
def reorder_room(
    id: str,
    body: ReorderBody,
    db: Session = Depends(get_db),
    _: User = Depends(get_current_user),
):
    """Update the sort order of a room."""
    room = get_room_or_404(id, db)
    room.sort_order = body.sort_order
    db.commit()
    db.refresh(room)
    return RoomRead.model_validate(room)


@router.post("/api/rooms/merge", response_model=dict, summary="合并房间")
def merge_rooms(
    body: RoomMergeBody,
    db: Session = Depends(get_db),
    _: User = Depends(get_current_user),
):
    """Merge source room into target room.

    All panoramas from source are moved to target, then source is deleted.
    """
    source = get_room_or_404(body.source_room_id, db)
    target = get_room_or_404(body.target_room_id, db)

    if source.floor_id != target.floor_id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="只能合并同一楼层的房间",
        )

    if source.id == target.id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="不能合并同一个房间",
        )

    # Move all panoramas from source to target
    panoramas = (
        db.query(Panorama)
        .filter(Panorama.room_id == source.id)
        .all()
    )
    for pano in panoramas:
        pano.room_id = target.id

    # Delete source room
    db.delete(source)
    db.commit()

    # Reload target to get fresh state
    db.refresh(target)

    return {
        "message": "房间已合并",
        "source_room_id": body.source_room_id,
        "target_room_id": body.target_room_id,
        "target_room": RoomRead.model_validate(target),
    }


@router.post("/api/rooms/{id}/split", response_model=dict, summary="拆分房间")
def split_room(
    id: str,
    body: RoomSplitBody,
    db: Session = Depends(get_db),
    _: User = Depends(get_current_user),
):
    """Split a room by moving specified panoramas into a new room."""
    source = get_room_or_404(id, db)

    # Verify all specified panoramas belong to this room
    panoramas_to_move = (
        db.query(Panorama)
        .filter(
            Panorama.id.in_(body.panorama_ids),
            Panorama.room_id == source.id,
        )
        .all()
    )

    if len(panoramas_to_move) != len(body.panorama_ids):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="部分全景图不属于该房间或不存在",
        )

    if len(panoramas_to_move) == len(
        db.query(Panorama).filter(Panorama.room_id == source.id).all()
    ):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="不能将所有全景图移动到新房间，源房间应至少保留一个全景图",
        )

    # Create new room
    new_room = Room(
        id=generate_uuid(),
        floor_id=source.floor_id,
        name=body.new_room_name,
        type=body.new_room_type,
        sort_order=source.sort_order + 1,
        created_at=datetime.utcnow(),
        updated_at=datetime.utcnow(),
    )
    db.add(new_room)
    db.flush()

    # Move panoramas
    for pano in panoramas_to_move:
        pano.room_id = new_room.id

    db.commit()
    db.refresh(source)
    db.refresh(new_room)

    return {
        "message": "房间已拆分",
        "source_room": RoomRead.model_validate(source),
        "new_room": RoomRead.model_validate(new_room),
    }
