from django.db import transaction
from rest_framework import status
from rest_framework.exceptions import ValidationError

from api.admin_permission_conf import PERMISSIONS
from api.models import Role, RolePermission, RolePermissionDepartment, TtDepartment
from api.views.admin.base import AdminApiBase
from api.validator import BaseValidator
from api.utils import log_critical_error, get_exception_detail
from api.translation import __


class RoleCreate(AdminApiBase):
    def validate_request(self, request):
        rules = {
            "name": "required",
            "color": "nullable",
            "type": "nullable",
            "is_only_self": "nullable|boolean",
            "permissions": "nullable|array",
        }

        validator = BaseValidator(request.data, rules, {})
        error = validator.validate()
        if error:
            raise ValidationError(error)

        permissions = request.data.get("permissions", [])
        if permissions is None:
            permissions = []

        if not isinstance(permissions, list):
            raise ValidationError({
                "error": __('validation.invalid_format'),
                "errors": {"permissions": __("validation.invalid_format")}
            })

        valid_permission_codes = PERMISSIONS
        seen = set()

        for idx, item in enumerate(permissions):
            if not isinstance(item, dict):
                raise ValidationError({
                    "error": __('validation.invalid_format'),
                    "errors": {f"permissions.{idx}": __("validation.invalid_format")}
                })

            permission = item.get("permission")
            grant = item.get("grant_to_all_department")
            department_ids = item.get("department_ids", [])

            if permission not in valid_permission_codes:
                raise ValidationError({
                    "error": __('validation.exists'),
                    "errors": {f"permissions.{idx}.permission": __("validation.exists")}
                })

            if permission in seen:
                raise ValidationError({
                    "error": __('validation.duplicate'),
                    "errors": {f"permissions.{idx}.permission": __("validation.duplicate")}
                })
            seen.add(permission)

            if not isinstance(grant, bool):
                raise ValidationError({
                    "error": __('validation.invalid_format'),
                    "errors": {f"permissions.{idx}.grant_to_all_department": __("validation.invalid_format")}
                })

            if not grant:
                exists_count = TtDepartment.objects.filter(id__in=department_ids).count()
                if exists_count != len(set(department_ids)):
                    raise ValidationError({
                        "error": __('validation.exists'),
                        "errors": {f"permissions.{idx}.department_ids": __("validation.exists")}
                    })

    def post(self, request):
        try:
            self.validate_request(request)

            permissions = request.data.get("permissions", [])
            if permissions is None:
                permissions = []

            with transaction.atomic():
                role = Role.objects.create(
                    name=request.data["name"],
                    color=request.data.get("color"),
                    type=request.data.get("type", ""),
                    is_only_self=request.data.get("is_only_self", False),
                    created_by=request.user.id,
                )

                for item in permissions:
                    rp = RolePermission.objects.create(
                        role=role,
                        permission=item["permission"],
                        grant_to_all_department=item["grant_to_all_department"],
                    )

                    if not item["grant_to_all_department"]:
                        objs = [
                            RolePermissionDepartment(
                                role_permission=rp,
                                department_id=dept_id
                            )
                            for dept_id in item.get("department_ids", [])
                        ]
                        if objs:
                            RolePermissionDepartment.objects.bulk_create(objs)

            return self.api_response(data={})

        except ValidationError as e:
            return self.api_response(
                error=e.detail['error'],
                errors=e.detail['errors'],
                code=status.HTTP_400_BAD_REQUEST
            )
        except Exception as e:
            e_details = get_exception_detail(e)
            log_critical_error(None, e_details['descr'], e_details['url'], e_details['trace'])
            return self.api_response(
                error=__("message.internal_server_error"),
                code=status.HTTP_500_INTERNAL_SERVER_ERROR
            )