import io
import json
import logging

from django.forms import model_to_dict
from django.http import HttpResponse
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet, ModelViewSet

from core.mixins import ApiPermissionCheckMixin, ExportToJSONMixin
from correlation.models import Group, Rule
from correlation.serializers import (RuleSerializer, GroupSerializer, ImporRulesFileSerializer)
from correlation.services.import_service import ImportRulesService
from correlation.tasks import update_correlator_tasks
from perms.models import Perm

_log = logging.getLogger(__name__)


class RuleViewSet(ApiPermissionCheckMixin,
                  ExportToJSONMixin,
                  ListModelMixin,
                  RetrieveModelMixin,
                  UpdateModelMixin,
                  DestroyModelMixin,
                  GenericViewSet):
    serializer_class = RuleSerializer
    console_permissions = {"destroy": [Perm.can_delete_correlation_rules],
                           "list": [Perm.can_view_correlation_rules_list],
                           "create": [Perm.can_create_and_edit_correlation_rule],
                           "retrieve": [Perm.can_view_correlation_rule_card],
                           "update": [Perm.can_create_and_edit_correlation_rule],
                           "partial_update": [Perm.can_create_and_edit_correlation_rule],
                           "json_export": [Perm.can_create_and_edit_correlation_rule],
                           "import_rules": [Perm.can_create_and_edit_correlation_rule],
                           }

    def get_queryset(self):
        if self.action == 'json_export':
            return Rule.objects.exclude(actions_json__contains=[{'type': 'firewall'}])
        return Rule.objects.order_by('-status', 'id')

    def create(self, request, *args, **kwargs):
        data_dict = request.data.copy()
        data_dict["kind"] = "JSON"
        rule = RuleSerializer(data=data_dict)
        if rule.is_valid():
            rule.save()
            return Response(data=rule.data, status=status.HTTP_201_CREATED)
        else:
            _log.critical(f"\n\n\nError: {rule.errors}\n\nData: {rule.data}\n\n")
            return Response(data=rule.errors, status=status.HTTP_400_BAD_REQUEST)

    def get_object(self):
        # get the initial value of the model fields
        # in the signal (correlation/services/signals.py) we make a decision to increase rule.rev or not
        rule = super().get_object()
        rule._initial = model_to_dict(rule, fields=[field.name for field in rule._meta.fields])
        return rule

    @action(methods=['POST'], detail=False)
    def import_rules(self, request, *args, **kwargs):
        serializer = ImporRulesFileSerializer(request.POST, request.FILES)
        serializer.is_valid(raise_exception=True)
        service = ImportRulesService(serializer.validated_data['uploaded_file'])
        result = service.run_import()

        # send all exists rules to correlator
        update_correlator_tasks(clear_store=True)

        # create report file
        file = io.BytesIO()
        file.write(json.dumps(result, ensure_ascii=False, indent=4).encode())
        file.seek(0)
        response = HttpResponse(file, content_type="application/file")
        response['Content-Disposition'] = f'attachment; filename="Report.json"'
        return response


class GroupViewSet(ApiPermissionCheckMixin, ModelViewSet):
    serializer_class = GroupSerializer

    console_permissions = {'list': [Perm.can_view_correlation_rule_card],
                           'create': [Perm.can_edit_correlation_groups],
                           'retrieve': [Perm.can_edit_correlation_groups],
                           'destroy': [Perm.can_edit_correlation_groups],
                           'update': [Perm.can_edit_correlation_groups],
                           'partial_update': [Perm.can_edit_correlation_groups]}

    queryset = Group.objects.all()
