from fastapi import APIRouter, HTTPException, Depends, status
from typing import List, Optional
from bson import ObjectId
from pydantic import BaseModel

from app.models.role import Role
from app.models.user_role import UserRole
from app.core.auth import get_current_user
from app.schemas.role import RoleResponse, RoleCreate, RoleUpdate
from app.schemas.user_role import UserRoleResponse

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

class AssignDefaultRoleRequest(BaseModel):
    user_id: str

@router.post("/assign-default", response_model=UserRoleResponse)
async def assign_default_role(request: AssignDefaultRoleRequest):
    """Assign default role to a user"""
    try:
        # Convert string ID to ObjectId
        user_id = ObjectId(request.user_id)
        
        # Check if user already has any roles
        existing_roles = await UserRole.get_user_roles(user_id)
        if existing_roles:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="User already has roles assigned"
            )
        
        # Get default role
        default_role = await Role.get_default_role()
        if not default_role:
            # Create system roles if they don't exist
            await Role.create_system_roles()
            default_role = await Role.get_default_role()
            
            if not default_role:
                raise HTTPException(
                    status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    detail="No default role configured in the system"
                )
        
        # Assign default role
        user_role = await UserRole.assign_role(
            user_id=user_id,
            role_name=default_role.name,
            notes="Default role assignment during registration"
        )
        
        return UserRoleResponse(
            user_id=str(user_role.user_id),
            role_name=user_role.role_name,
            assigned_at=user_role.assigned_at,
            is_active=user_role.is_active,
            is_permanent=user_role.is_permanent
        )
        
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to assign default role: {str(e)}"
        )

@router.get("", response_model=List[RoleResponse])
async def get_roles(
    active_only: bool = True,
    role_type: Optional[str] = None,
    _=Depends(get_current_user)
):
    """Get all roles"""
    query = {}
    if active_only:
        query["is_active"] = True
    if role_type:
        query["role_type"] = role_type
    
    roles = await Role.find(query).to_list()
    return [RoleResponse.from_orm(role) for role in roles]

@router.post("", response_model=RoleResponse, status_code=status.HTTP_201_CREATED)
async def create_role(role: RoleCreate, current_user=Depends(get_current_user)):
    """Create a new role"""
    # Check if role already exists
    existing = await Role.find_one(Role.name == role.name)
    if existing:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Role with name '{role.name}' already exists"
        )
    
    # Create role
    new_role = Role(
        **role.dict(),
        created_by=current_user.id
    )
    await new_role.save()
    
    return RoleResponse.from_orm(new_role)

@router.get("/{role_name}", response_model=RoleResponse)
async def get_role(role_name: str, _=Depends(get_current_user)):
    """Get a specific role"""
    role = await Role.find_one(Role.name == role_name)
    if not role:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Role '{role_name}' not found"
        )
    
    return RoleResponse.from_orm(role)

@router.put("/{role_name}", response_model=RoleResponse)
async def update_role(
    role_name: str,
    role_update: RoleUpdate,
    current_user=Depends(get_current_user)
):
    """Update a role"""
    role = await Role.find_one(Role.name == role_name)
    if not role:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Role '{role_name}' not found"
        )
    
    # Prevent modification of system roles
    if role.is_system_role:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Cannot modify system roles"
        )
    
    # Update role
    for field, value in role_update.dict(exclude_unset=True).items():
        setattr(role, field, value)
    
    await role.save()
    return RoleResponse.from_orm(role)

@router.delete("/{role_name}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_role(role_name: str, current_user=Depends(get_current_user)):
    """Delete a role"""
    role = await Role.find_one(Role.name == role_name)
    if not role:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Role '{role_name}' not found"
        )
    
    # Prevent deletion of system roles
    if role.is_system_role:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Cannot delete system roles"
        )
    
    # Check if role is assigned to any users
    user_count = await role.get_user_count()
    if user_count > 0:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Cannot delete role '{role_name}' as it is assigned to {user_count} users"
        )
    
    await role.delete()