from collections import defaultdict
import re
from typing import List
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder
from fastapi.security import OAuth2PasswordRequestForm,HTTPBearer, HTTPAuthorizationCredentials
from core.security import verify_password, get_password_hash, create_access_token,  verify_token
from datetime import datetime, timezone
from db.session import get_db
from db.models.user import User  # Replace with actual import
from db.schemas.role import  RoleBase   # Replace with actual import
from jose import jwt, JWTError
from db.models.role import Role
from db.models.permission import Permission
from db.models.section import Section
from db.schemas.permission import PermissionUpdate

router = APIRouter()
security = HTTPBearer()


@router.get("/roles-list", response_model=RoleBase)
async def get_roles(
    limit: int = 10,
    offset: int = 0,
    search: str = None,
    sort_by: str = "id",
    sort_order: str = "asc",
    db: Session = Depends(get_db), 
    credentials: HTTPAuthorizationCredentials = Depends(security)
):
    """
    Retrieve a list of roles.
    """
    token = credentials.credentials
    user_id = verify_token(token)

    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid user token")
    
    db_query = db.query(Role).order_by(
        getattr(Role, sort_by).asc() if sort_order == "asc" else getattr(Role, sort_by).desc()
    )

    role_count = db_query.count()
    if search:
        db_query = db_query.filter(Role.name.ilike(f"%{search}%"))
    
    role_users = db_query.offset(offset).limit(limit).all()
    
    if not role_users:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No active users found")
    
    # users_dict = [UserResponse.from_orm(user) for user in active_users]
    role_list = jsonable_encoder(role_users) 
    return JSONResponse(
        content={
            'role': role_list,
            'count': role_count,
            'status_code': status.HTTP_200_OK,
            'message': 'Active roles retrieved successfully'
        }, 
        status_code=status.HTTP_200_OK
    )
@router.get("/roles-with-permissions/{role_id}")
def get_role_permissions(role_id: int, db: Session = Depends(get_db)):
    # ✅ Fetch the role
    role = db.query(Role).filter(Role.id == role_id).first()
    if not role:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Role not found")

    # ✅ Fetch all sections (we want all, even those without permissions)
    sections = db.query(Section).all()

    # ✅ Fetch permissions for the role
    role_permissions = (
        db.query(Permission)
        .filter(Permission.role_id == role_id)
        .all()
    )

    # Convert permissions into a lookup dictionary for faster access
    permissions_by_section = {}
    for perm in role_permissions:
        permissions_by_section.setdefault(perm.section_id, []).append({
            "id": perm.id,
            "create": perm.create,
            "view": perm.view,
            "edit": perm.edit,
            "delete": perm.delete,
        })

    # ✅ Build final response
    sections_data = []
    for section in sections:
        section_permissions = permissions_by_section.get(section.id, [])
        sections_data.append({
            "id": section.id,
            "name": section.name,
            "permissions": section_permissions
        })

    return {
        "role": {"name": role.name, "id": role.id},
        "sections": sections_data,
        "count": len(sections_data),
        "status_code": 200,
        "message": "Permissions grouped by sections retrieved successfully"
    }

@router.put("/permissions-update/{role_id}")
async def update_permissions(
    role_id: int,
    permissions: List[PermissionUpdate],
    db: Session = Depends(get_db),
    credentials: HTTPAuthorizationCredentials = Depends(security)
):
    """
    Update all permissions of a given role_id.
    Includes sections that are missing from payload (with all False).
    """
    # --- Verify token ---
    token = credentials.credentials
    current_user_id = verify_token(token)
    current_user = db.query(User).filter(User.id == current_user_id).first()
    if not current_user:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid user token"
        )

    # --- Check role exists ---
    role = db.query(Role).filter(Role.id == role_id).first()
    if not role:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Role not found"
        )

    try:
        # --- Delete existing permissions for role ---
        db.query(Permission).filter(Permission.role_id == role_id).delete()

        # --- Get all sections ---
        all_sections = db.query(Section).all()
        section_ids = {section.id for section in all_sections}

        # --- Convert input permissions to dict for quick lookup ---
        payload_map = {
            perm.section_id: perm for perm in permissions
        }

        # --- Prepare new permissions ---
        new_permissions = []
        for section_id in section_ids:
            perm_data = payload_map.get(section_id)

            if perm_data:
                # Use provided permissions
                new_permissions.append(Permission(
                    role_id=role_id,
                    section_id=section_id,
                    create=perm_data.create,
                    view=perm_data.view,
                    edit=perm_data.edit,
                    delete=perm_data.delete
                ))
            else:
                # Add section with all permissions set to False
                new_permissions.append(Permission(
                    role_id=role_id,
                    section_id=section_id,
                    create=False,
                    view=False,
                    edit=False,
                    delete=False
                ))

        # --- Insert new permissions ---
        db.bulk_save_objects(new_permissions)
        db.commit()

        return JSONResponse(
            content={
                "status_code": status.HTTP_200_OK,
                "message": "Permissions updated successfully"
            },
            status_code=status.HTTP_200_OK
        )

    except Exception as e:
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to update permissions: {str(e)}"
        )
