from flask import session

from common.models.user import Partner, Role, PartnerTenant

from common.utils.eveai_exceptions import EveAIRoleAssignmentException
from common.utils.security_utils import current_user_has_role


class UserServices:
    @staticmethod
    def get_assignable_roles():
        """Retrieves roles that can be assigned to a user depending on the current user logged in,
        and the active tenant for the session"""
        current_tenant_id = session.get('tenant').get('id', None)
        effective_role_names = []
        if current_tenant_id == 1:
            if current_user_has_role("Super User"):
                effective_role_names.append("Super User")
        elif current_tenant_id:
            if current_user_has_role("Tenant Admin"):
                effective_role_names.append("Tenant Admin")
            if current_user_has_role("Partner Admin") or current_user_has_role("Super User"):
                effective_role_names.append("Tenant Admin")
                if session.get('partner'):
                    if session.get('partner').get('tenant_id') == current_tenant_id:
                        effective_role_names.append("Partner Admin")
        effective_role_names = list(set(effective_role_names))
        effective_roles = [(role.id, role.name) for role in
                           Role.query.filter(Role.name.in_(effective_role_names)).all()]
        return effective_roles

    @staticmethod
    def validate_role_assignments(role_ids):
        """Validate a set of role assignments, raising exception for first invalid role"""
        assignable_roles = UserServices.get_assignable_roles()
        assignable_role_ids = {role[0] for role in assignable_roles}
        role_id_set = set(role_ids)
        return role_id_set.issubset(assignable_role_ids)

    @staticmethod
    def can_user_edit_tenant(tenant_id) -> bool:
        if current_user_has_role('Super User'):
            return True
        elif current_user_has_role('Partner Admin'):
            partner = session.get('partner', None)
            if partner and partner["tenant_id"] == tenant_id:
                return True
            partner_service = next((service for service in session['partner']['services']
                                    if service.get('type') == 'MANAGEMENT_SERVICE'), None)
            if not partner_service:
                return False
            else:
                partner_tenant = PartnerTenant.query.filter(
                    PartnerTenant.tenant_id == tenant_id,
                    PartnerTenant.partner_service_id == partner_service['id'],
                ).first()
                if partner_tenant:
                    return True
                else:
                    return False
        else:
            return False

    @staticmethod
    def can_user_create_tenant() -> bool:
        if current_user_has_role('Super User'):
            return True
        elif current_user_has_role('Partner Admin'):
            partner_id = session['partner']['id']
            partner_service = next((service for service in session['partner']['services']
                                    if service.get('type') == 'MANAGEMENT_SERVICE'), None)
            if not partner_service:
                return False
            else:
                partner_permissions = partner_service.get('permissions', None)
                return partner_permissions.get('can_create_tenant', False)
        else:
            return False

    @staticmethod
    def can_user_assign_license() -> bool:
        if current_user_has_role('Super User'):
            return True
        elif current_user_has_role('Partner Admin'):
            partner_id = session['partner']['id']
            partner_service = next((service for service in session['partner']['services']
                                    if service.get('type') == 'MANAGEMENT_SERVICE'), None)
            if not partner_service:
                return False
            else:
                partner_permissions = partner_service.get('permissions', None)
                return partner_permissions.get('can_assign_license', False)
        else:
            return False

