"""House 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.house import House
from app.models.permission import Role
from app.models.user import User
from app.models.user_house_role import UserHouseRole
from app.schemas.house import HouseRead, HouseUpdate
from app.schemas.user import UserRead
from app.services.auth_service import get_current_user
from app.utils.helpers import generate_uuid, paginate, slugify

router = APIRouter()


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

class HouseCreateBody(BaseModel):
    title: str = Field(..., min_length=1, max_length=200)
    address: Optional[str] = Field(None, max_length=500)
    slug: Optional[str] = Field(
        None, min_length=1, max_length=200, pattern=r"^[a-z0-9\-]+$"
    )
    cover_image_url: Optional[str] = None


class AddMemberBody(BaseModel):
    user_id: str
    role_id: str


# ── Helper ─────────────────────────────────────────────────────────────── #

def get_house_or_404(house_id: str, db: Session) -> House:
    house = db.query(House).filter(House.id == house_id).first()
    if not house:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="房屋不存在",
        )
    return house


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

@router.get("", response_model=dict, summary="获取用户房屋列表")
def list_houses(
    page: int = Query(1, ge=1),
    size: int = Query(20, ge=1, le=100),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """List houses where the current user has a role (paginated)."""
    query = (
        db.query(House)
        .join(UserHouseRole, UserHouseRole.house_id == House.id)
        .filter(
            UserHouseRole.user_id == current_user.id,
            House.status != "archived",
        )
        .order_by(House.created_at.desc())
        .distinct()
    )
    result = paginate(query, page=page, size=size)

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


@router.post(
    "",
    response_model=HouseRead,
    status_code=status.HTTP_201_CREATED,
    summary="创建房屋",
)
def create_house(
    body: HouseCreateBody,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Create a new house (auto-slug, assign creator as owner)."""
    # Determine slug
    slug_value = body.slug or slugify(body.title)
    if not slug_value:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="无法生成有效的 slug",
        )

    # Check slug uniqueness
    existing = db.query(House).filter(House.slug == slug_value).first()
    if existing:
        # Append suffix to make it unique
        suffix = 1
        while True:
            candidate = f"{slug_value}-{suffix}"
            if not db.query(House).filter(House.slug == candidate).first():
                slug_value = candidate
                break
            suffix += 1

    house = House(
        id=generate_uuid(),
        title=body.title,
        address=body.address,
        slug=slug_value,
        cover_image_url=body.cover_image_url,
        status="draft",
        created_by=current_user.id,
        created_at=datetime.utcnow(),
        updated_at=datetime.utcnow(),
    )
    db.add(house)
    db.flush()

    # Assign owner role to creator
    owner_role = db.query(Role).filter(Role.name == "owner").first()
    if not owner_role:
        owner_role = Role(
            id=generate_uuid(),
            name="owner",
            description="房屋所有者",
            is_system=True,
        )
        db.add(owner_role)
        db.flush()

    uhr = UserHouseRole(
        id=generate_uuid(),
        user_id=current_user.id,
        house_id=house.id,
        role_id=owner_role.id,
        granted_by=current_user.id,
    )
    db.add(uhr)
    db.commit()
    db.refresh(house)

    return HouseRead.model_validate(house)


@router.get("/{house_id}", response_model=HouseRead, summary="获取房屋详情")
def get_house(
    house_id: str,
    db: Session = Depends(get_db),
    _: User = Depends(get_current_user),
):
    """Get a single house by ID."""
    house = get_house_or_404(house_id, db)
    return HouseRead.model_validate(house)


@router.put("/{house_id}", response_model=HouseRead, summary="更新房屋信息")
def update_house(
    house_id: str,
    body: HouseUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Update a house."""
    house = get_house_or_404(house_id, db)

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

    db.commit()
    db.refresh(house)
    return HouseRead.model_validate(house)


@router.delete("/{house_id}", summary="归档房屋")
def archive_house(
    house_id: str,
    db: Session = Depends(get_db),
    _: User = Depends(get_current_user),
):
    """Soft-delete a house by setting its status to 'archived'."""
    house = get_house_or_404(house_id, db)
    house.status = "archived"
    house.updated_at = datetime.utcnow()
    db.commit()

    return {"message": "房屋已归档", "house_id": house_id}


@router.get("/{house_id}/members", response_model=dict, summary="获取房屋成员列表")
def list_members(
    house_id: str,
    db: Session = Depends(get_db),
    _: User = Depends(get_current_user),
):
    """List all members of a house with their roles."""
    get_house_or_404(house_id, db)

    members = (
        db.query(UserHouseRole)
        .filter(UserHouseRole.house_id == house_id)
        .all()
    )

    result = []
    for m in members:
        user = db.query(User).filter(User.id == m.user_id).first()
        role = db.query(Role).filter(Role.id == m.role_id).first()
        result.append(
            {
                "id": m.id,
                "user_id": m.user_id,
                "user_email": user.email if user else None,
                "user_display_name": user.display_name if user else None,
                "role_id": m.role_id,
                "role_name": role.name if role else None,
                "granted_by": m.granted_by,
                "created_at": m.created_at.isoformat() if m.created_at else None,
            }
        )

    return {"items": result, "total": len(result)}


@router.post(
    "/{house_id}/members",
    status_code=status.HTTP_201_CREATED,
    summary="添加房屋成员",
)
def add_member(
    house_id: str,
    body: AddMemberBody,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Add a user to a house with a specific role."""
    get_house_or_404(house_id, db)

    # Validate user exists
    user = db.query(User).filter(User.id == body.user_id).first()
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="用户不存在",
        )

    # Validate role exists
    role = db.query(Role).filter(Role.id == body.role_id).first()
    if not role:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="角色不存在",
        )

    # Check duplicate assignment
    existing = (
        db.query(UserHouseRole)
        .filter(
            UserHouseRole.user_id == body.user_id,
            UserHouseRole.house_id == house_id,
            UserHouseRole.role_id == body.role_id,
        )
        .first()
    )
    if existing:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="该用户已拥有此角色",
        )

    uhr = UserHouseRole(
        id=generate_uuid(),
        user_id=body.user_id,
        house_id=house_id,
        role_id=body.role_id,
        granted_by=current_user.id,
    )
    db.add(uhr)
    db.commit()

    return {
        "message": "成员已添加",
        "id": uhr.id,
        "user_id": body.user_id,
        "role_id": body.role_id,
    }


# ── Convenience: rooms & panoramas under a house ──────────────────────── #

@router.get("/{hid}/rooms")
def list_house_rooms(
    hid: str,
    db: Session = Depends(get_db),
    _=Depends(get_current_user),
):
    """List all rooms under a house (across all floors)."""
    from app.models.floor import Floor
    from app.models.room import Room
    rooms = (
        db.query(Room)
        .join(Floor, Room.floor_id == Floor.id)
        .filter(Floor.house_id == hid)
        .order_by(Floor.level, Room.sort_order)
        .all()
    )
    return {
        "items": [
            {
                "id": r.id, "floorId": r.floor_id, "name": r.name,
                "type": r.type, "sortOrder": r.sort_order,
                "coverPanoId": r.cover_pano_id,
                "createdAt": r.created_at.isoformat() if r.created_at else None,
            }
            for r in rooms
        ],
        "total": len(rooms),
    }


@router.get("/{hid}/panoramas")
def list_house_panoramas(
    hid: str,
    size: int = Query(1000, ge=1, le=5000),
    db: Session = Depends(get_db),
    _=Depends(get_current_user),
):
    """List all panoramas under a house (across all rooms)."""
    from app.models.floor import Floor
    from app.models.room import Room
    from app.models.panorama import Panorama
    panos = (
        db.query(Panorama)
        .join(Room, Panorama.room_id == Room.id)
        .join(Floor, Room.floor_id == Floor.id)
        .filter(Floor.house_id == hid)
        .order_by(Panorama.capture_order)
        .limit(size)
        .all()
    )
    return {
        "items": [
            {
                "id": p.id, "roomId": p.room_id, "imageUrl": p.image_url,
                "thumbnailUrl": p.thumbnail_url, "sequence": p.sequence,
                "defaultYaw": p.default_yaw, "defaultPitch": p.default_pitch,
                "captureOrder": p.capture_order,
                "position": {"x": p.position_x, "y": p.position_y, "z": p.position_z},
                "createdAt": p.created_at.isoformat() if p.created_at else None,
            }
            for p in panos
        ],
        "total": len(panos),
    }
