
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session, joinedload

from app.api.deps import get_current_user
from app.api.permissions import require_create, require_delete, require_read, require_update
from app.core.security import get_password_hash
from app.crud.user import user as crud_user
from app.db.session import get_db
from app.models.role import Role
from app.models.tenant import Tenant
from app.models.user import User
from app.models.user_role import UserRole
from app.schemas.user import UserCreate, UserResponse, UserUpdate
from app.services.access.rbac_bootstrap_service import RBACBootstrapService
from common_logging import get_logger

router = APIRouter(tags=["users"])
logger = get_logger(__name__)


def get_role_display(user: User, tenant: Tenant = None) -> str:
    role_map = {
        "platform_admin": "平台管理员",
        "platform_user": "平台用户",
        "customer_admin": "客户管理员",
        "customer_user": "客户用户",
    }
    role_text = role_map.get(user.role, user.role)
    if tenant:
        return f"{tenant.name}/{role_text}"
    return role_text


@router.get("/", response_model=list[UserResponse])
def list_users(
    skip: int = 0,
    limit: int = 100,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_read("users")),
):
    query = db.query(User).options(joinedload(User.tenant))
    if current_user.role != "platform_admin":
        query = query.filter(User.tenant_id == current_user.tenant_id)
    users = query.offset(skip).limit(limit).all()
    result = []
    for user in users:
        result.append(
            UserResponse(
                id=user.id,
                email=user.email,
                name=user.name,
                role=user.role,
                tenant_id=user.tenant_id,
                company_name=user.tenant.name if user.tenant else None,
                role_display=get_role_display(user, user.tenant),
                is_verified=user.is_verified,
                last_login=user.last_login,
                created_at=user.created_at,
            )
        )
    return result


@router.post("/", response_model=UserResponse)
def create_user(
    user_in: UserCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_create("users")),
):
    if current_user.role == "customer_admin":
        if user_in.role not in ["customer_admin", "customer_user"]:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Customer admin can only create customer_admin and customer_user roles",
            )
        user_in.tenant_id = current_user.tenant_id
    existing_user = crud_user.get_by_email(db, email=user_in.email)
    if existing_user:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered"
        )
    if user_in.role in ["customer_admin", "customer_user"]:
        if not user_in.tenant_id:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="tenant_id is required for customer roles",
            )
        tenant = db.query(Tenant).filter(Tenant.id == user_in.tenant_id).first()
        if not tenant:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Company not found")
    db_user = User(
        email=user_in.email,
        name=user_in.name,
        hashed_password=get_password_hash(user_in.password),
        role=user_in.role,
        tenant_id=user_in.tenant_id,
        is_verified=True,
    )
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    RBACBootstrapService.sync_user_role_binding(db, db_user)
    logger.bind(user_id=db_user.id).info("User created")
    tenant = (
        db.query(Tenant).filter(Tenant.id == db_user.tenant_id).first()
        if db_user.tenant_id
        else None
    )
    return UserResponse(
        id=db_user.id,
        email=db_user.email,
        name=db_user.name,
        role=db_user.role,
        tenant_id=db_user.tenant_id,
        company_name=tenant.name if tenant else None,
        role_display=get_role_display(db_user, tenant),
        is_verified=db_user.is_verified,
        last_login=db_user.last_login,
        created_at=db_user.created_at,
    )


@router.put("/{user_id}", response_model=UserResponse)
def update_user(
    user_id: int,
    user_in: UserUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_update("users")),
):
    if current_user.role == "customer_admin":
        db_user = (
            db.query(User)
            .filter(User.id == user_id, User.tenant_id == current_user.tenant_id)
            .first()
        )
    else:
        db_user = db.query(User).filter(User.id == user_id).first()
    if not db_user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    if current_user.role == "customer_admin":
        if user_in.role and user_in.role not in ["customer_admin", "customer_user"]:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Customer admin can only set customer_admin and customer_user roles",
            )
    if user_in.email and user_in.email != db_user.email:
        existing_user = crud_user.get_by_email(db, email=user_in.email)
        if existing_user:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered"
            )
    if user_in.name is not None:
        db_user.name = user_in.name
    if user_in.email is not None:
        db_user.email = user_in.email
    previous_role = db_user.role
    previous_tenant_id = db_user.tenant_id
    if user_in.role is not None:
        db_user.role = user_in.role
    if user_in.tenant_id is not None:
        tenant = db.query(Tenant).filter(Tenant.id == user_in.tenant_id).first()
        if not tenant:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Company not found")
        db_user.tenant_id = user_in.tenant_id
    if user_in.is_verified is not None:
        db_user.is_verified = user_in.is_verified
    db.commit()
    db.refresh(db_user)
    RBACBootstrapService.sync_user_role_binding(
        db, db_user, previous_role=previous_role, previous_tenant_id=previous_tenant_id
    )
    logger.bind(user_id=db_user.id).info("User updated")
    tenant = (
        db.query(Tenant).filter(Tenant.id == db_user.tenant_id).first()
        if db_user.tenant_id
        else None
    )
    return UserResponse(
        id=db_user.id,
        email=db_user.email,
        name=db_user.name,
        role=db_user.role,
        tenant_id=db_user.tenant_id,
        company_name=tenant.name if tenant else None,
        role_display=get_role_display(db_user, tenant),
        is_verified=db_user.is_verified,
        last_login=db_user.last_login,
        created_at=db_user.created_at,
    )


@router.delete("/{user_id}")
def delete_user(
    user_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_delete("users")),
):
    if user_id == current_user.id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot delete your own account"
        )
    if current_user.role == "customer_admin":
        db_user = (
            db.query(User)
            .filter(User.id == user_id, User.tenant_id == current_user.tenant_id)
            .first()
        )
    else:
        db_user = db.query(User).filter(User.id == user_id).first()
    if not db_user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    logger.bind(user_id=db_user.id).info("User deleted")
    db.delete(db_user)
    db.commit()
    return {"message": f"User {db_user.name} deleted successfully"}


@router.put("/{user_id}/roles")
def update_user_roles(
    user_id: int,
    role_ids: list[int],
    db: Session = Depends(get_db),
    current_user: User = Depends(require_update("users")),
):
    from sqlalchemy import text

    from app.crud.user_role import user_role as user_role_crud

    if current_user.role != "platform_admin":
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Only platform admin can update user roles",
        )
    db.execute(text("SET search_path TO public"))
    db_user = db.query(User).filter(User.id == user_id).first()
    if not db_user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    roles = db.query(Role).filter(Role.id.in_(role_ids), not Role.is_deleted).all()
    if len(roles) != len(role_ids):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail="One or more roles not found"
        )
    user_role_crud.update_user_roles(
        db, user_id=user_id, role_ids=role_ids, tenant_id=db_user.tenant_id
    )
    if roles:
        db_user.role = roles[0].code
        db.commit()
    logger.bind(user_id=user_id, role_ids=role_ids).info("User roles updated")
    return {"message": "User roles updated successfully", "role_ids": role_ids}


@router.get("/{user_id}/roles")
def get_user_roles(
    user_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)
):
    from sqlalchemy import text

    if current_user.role != "platform_admin":
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Insufficient permissions to view user roles",
        )
    db.execute(text("SET search_path TO public"))
    db_user = db.query(User).filter(User.id == user_id).first()
    if not db_user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    user_roles = (
        db.query(UserRole).filter(UserRole.user_id == user_id, not UserRole.is_deleted).all()
    )
    role_ids = [ur.role_id for ur in user_roles]
    roles = db.query(Role).filter(Role.id.in_(role_ids), not Role.is_deleted).all()
    return {
        "user_id": user_id,
        "roles": [{"id": r.id, "code": r.code, "name": r.name} for r in roles],
    }
