from fastapi import APIRouter, Depends, HTTPException, status
from typing import Optional, Dict, List
from fastapi.encoders import jsonable_encoder
from bson import ObjectId
from app.db import database
from app.v1.models.saas.rolemodel import Role, RoleCreate, RoleUpdate
from app.v1.services.saas.roles import create_role_service, update_role_service, get_role_service
from app.v1.dependencies.auth import get_current_userdetails
from app.v1.models.default import features_list, default_roles

router = APIRouter()

# Define two groups of features: SaaS modules and Platform modules.

@router.get("/features", tags=["Features"])
async def get_features(current_user = Depends(get_current_userdetails)):
    """
    Returns the list of features.
      - If current user has role 1 (Superadmin), return both SaaS and Platform features.
      - If current user has role 100 (Account admin), return only Platform features.
    """
    user_role = current_user.get("roles")
    if user_role == 1:
        return features_list
    elif user_role == 100:
        return {"platform": features_list["platform"]}
    else:
        raise HTTPException(status_code=403, detail="Insufficient permissions")

def generate_role_permissions(role_id: int) -> Dict[int, List[str]]:
    """
    Generate a permissions mapping for a given system role based on its name, using module IDs as keys.
    
    SaaS roles:
      - Superadmin: Full access (IDs 1-13, all actions).
      - Sales/Accounts: Access to modules [1,2,3,4,5,6,10,11,12] with actions: create, read, update.
      - Partner (and Tech Team): Limited access (only IDs [1,2,3,4,5,10,11,12]) with actions: create, read, update.
    
    Platform roles:
      - Admin: Full access to all modules (IDs 21â€“35).
      - Manager: All modules with actions: create, read, update, delete.
      - Finance: For Transactions (ID 32) and Invoices (ID 33), full access; read-only for other modules.
      - Customer: Only access to modules [22, 23] with actions: create, read, update.
      - Vendor: Limited access to modules [21, 24, 25, 26, 27] with actions: create, read, update.
      - Workforce: Only access to the Workforce module (ID 27, read-only).
    """
    permissions: Dict[int, List[str]] = {}

    # SaaS roles: using the "saas" modules list
    if role_id <=99 :
        modules = features_list["saas"]
        if role_id == 1: # Superadmin
            actions = ["create", "read", "update", "delete"]
            for feature in modules:
                permissions[feature["id"]] = actions.copy()
        elif role_id == 2: # Sales/Accounts
            allowed_ids = {1, 2, 3, 4, 5, 6, 10, 11, 12}
            actions = ["create", "read", "update"]
            for feature in modules:
                if feature["id"] in allowed_ids:
                    permissions[feature["id"]] = actions.copy()
        elif role_id == 3: # Partner
            allowed_ids = {1, 2, 3, 4, 5, 10, 11, 12}
            actions = ["create", "read", "update"]
            for feature in modules:
                if feature["id"] in allowed_ids:
                    permissions[feature["id"]] = actions.copy()

        elif role_id == 4: # Partner - Sales/Accounts
            allowed_ids = {1, 2, 3, 4, 5, 10, 11, 12}
            actions = ["create", "read", "update"]
            for feature in modules:
                if feature["id"] in allowed_ids:
                    permissions[feature["id"]] = actions.copy()

        elif role_id == 5: #Tech Team
            allowed_ids = {11}
            actions = ["create", "read", "update", "delete"]
            for feature in modules:
                if feature["id"] in allowed_ids:
                    permissions[feature["id"]] = actions.copy()

    # Platform roles: using the "platform" modules list
    elif role_id >= 100:
        modules = features_list["platform"]
        if role_id == 100: #Account Owner
            actions = ["create", "read", "update", "delete"]
            disabled_ids = {22, 23}
            for feature in modules:
                if feature["id"] not in disabled_ids:
                    permissions[feature["id"]] = actions.copy()
        elif role_id == 101 : #Account Admin/ Manager
            actions = ["create", "read", "update", "delete"]
            disabled_ids = {22, 23}
            for feature in modules:
                if feature["id"] not in disabled_ids:
                    permissions[feature["id"]] = actions.copy()
        elif role_id == 102: #Finance
            for feature in modules:
                if feature["id"] in {32, 33}:  # Transactions and Invoices
                    permissions[feature["id"]] = ["create", "read", "update", "delete"]
                else:
                    permissions[feature["id"]] = ["read"]
        elif role_id == 104: #Customer
            allowed_ids = {22, 23}  # Customer-specific Dashboard and Booking
            for feature in modules:
                if feature["id"] in allowed_ids:
                    permissions[feature["id"]] = ["create", "read", "update"]
        elif role_id == 105: #Vendor
            allowed_ids = {21, 24, 25, 26, 27}
            for feature in modules:
                if feature["id"] in allowed_ids:
                    permissions[feature["id"]] = ["create", "read", "update"]
        elif role_id == 103: #Employees or Workforce
            for feature in modules:
                if feature["id"] == 27:  # Only Workforce module
                    permissions[feature["id"]] = ["read"]
    else:
        # Fallback: read-only access to all modules
        for category in features_list.values():
            for feature in category:
                permissions[feature["id"]] = ["read"]

    return permissions

async def get_role_by_name(db, name: str) -> Optional[dict]:
    """
    Check if a system default role with the given name exists.
    """
    roles_collection = db["roles"]
    return roles_collection.find_one({"name": name, "is_system_default": True})

async def get_role_by_id(db, id: int) -> Optional[dict]:
    """
    Check if a system default role with the given role_id exists.
    """
    roles_collection = db["roles"]
    return roles_collection.find_one({"role_id": id, "is_system_default": True})

@router.get("/access", tags=["RBAC"])
async def get_access(
    db: database.MongoDB = Depends(database.get_mongo_db),
    current_user = Depends(get_current_userdetails)
):
    """
    Returns the list of features (tailored to the user's role) and the role rights from the roles table.
    """
    user_role = current_user.get("roles")
    if user_role == 1:
        modules = features_list
    elif user_role == 100:
        modules = {"platform": features_list["platform"]}
    else:
        raise HTTPException(status_code=403, detail="Insufficient permissions")
    
    role_id = current_user.get("role_id")
    if not role_id:
        return {"modules": modules}
    
    role = await get_role_service(role_id, db)
    if not role:
        raise HTTPException(status_code=404, detail="Role not found")
    
    return {"modules": modules, "role": role}

@router.post("/default", tags=["Roles"])
async def create_default_system_roles(
    db: database.MongoDB = Depends(database.get_mongo_db),
    current_user = Depends(get_current_userdetails)
):
    """
    Create or update default system roles and insert the features list into the features collection.
    
    This endpoint performs the following:
      1. Inserts/updates the features list (with descriptions) into a dedicated "features" collection.
      2. Updates the features counter (using _id: "features_id") so new features have an appropriate ID.
      3. Creates or updates default system roles with mapped permissions.
    
    Default system roles:
      - SaaS Roles (role_id 1-4): 
          1: Superadmin (full access, is_global_access=True, is_saas_only=True)
          2: Sales/Accounts (access only to allowed modules, is_global_access=True, is_saas_only=True)
          3: Partner (limited access, is_global_access=False, is_saas_only=True)
          4: Tech Team (limited access, is_global_access=False, is_saas_only=True)
      - Platform Roles (role_id 100+):
          100: Admin (full access, is_global_access=True)
          101: Manager (read & update, is_global_access=True)
          102: Finance (full on Transactions/Invoices, read-only otherwise, is_global_access=True)
          103: Workforce (minimal; only Workforce module, is_global_access=False)
          104: Customer (access only to Dashboard and Booking, read-only, is_global_access=True)
          105: Vendor (limited access, is_global_access=False)
    
    These roles are marked with is_system_default=True so they are not modifiable.
    System roles do not use an account_id.
    """
    if current_user.get("roles") != 1:
        raise HTTPException(status_code=403, detail="Not authorized to create default system roles.")
    
    # 1. Insert/Update features into the "features" collection
    features_collection = db["features"]
    for category, features in features_list.items():
        for feature in features:
            # Ensure each feature has a description; if missing, set a default description.
            if "description" not in feature:
                feature["description"] = f"{feature['name']} feature"
            feature_doc = feature.copy()
            feature_doc["category"] = category
            features_collection.update_one(
                {"features_id": feature_doc["id"], "category": category},
                {"$set": feature_doc},
                upsert=True
            )
    
    # 2. Update the features counter in the "counters" collection.
    # Determine the maximum feature ID across all categories.
    max_feature_id = max(
        feature["id"] for category in features_list for feature in features_list[category]
    )
    counters_collection = db["counters"]
    counters_collection.update_one(
        {"_id": "features_id"},
        {"$set": {"sequence_value": max_feature_id}},
        upsert=True
    )
    
    created_roles = []
    for role_def in default_roles:
        existing = await get_role_by_id(db, role_def["role_id"])
        permissions = generate_role_permissions(role_def["role_id"])
        
        if existing:
            update_data = {
                "name": role_def["name"],
                "description": role_def["description"],
                "permissions": permissions,
                "is_system_default": role_def["is_system_default"],
                "is_global_access": role_def["is_global_access"],
                "is_saas_only": role_def.get("is_saas_only", False)
            }
            role_update_model = RoleUpdate(**update_data)
            updated_role = update_role_service(existing["role_id"], role_update_model, db)
            created_roles.append(updated_role)
        else:
            role_create = RoleCreate(
                role_id=role_def["role_id"],
                name=role_def["name"],
                description=role_def["description"],
                permissions=permissions,
                account_id="",
                is_system_default=role_def["is_system_default"],
                is_global_access=role_def["is_global_access"],
                is_saas_only=role_def.get("is_saas_only", False)
            )
            new_role = create_role_service(role_create, db)
            created_roles.append(new_role)
    
    return jsonable_encoder({"created_roles": created_roles}, custom_encoder={ObjectId: str})
