from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext_lazy as _
from django.views.decorators.clickjacking import xframe_options_sameorigin
from rest_framework import status, mixins, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response

from accounts.filters import AutomationExecutionFilterSet
from accounts.models import AutomationExecution
from accounts.tasks import execute_account_automation_task
from assets import serializers
from assets.models import BaseAutomation
from common.const.choices import Trigger
from orgs.mixins import generics

__all__ = [
    'AutomationAssetsListApi', 'AutomationRemoveAssetApi',
    'AutomationAddAssetApi', 'AutomationNodeAddRemoveApi',
    'AutomationExecutionViewSet'
]


class AutomationAssetsListApi(generics.ListAPIView):
    model = BaseAutomation
    serializer_class = serializers.AutomationAssetsSerializer
    filterset_fields = ("name", "address")
    search_fields = filterset_fields

    def get_object(self):
        pk = self.kwargs.get('pk')
        return get_object_or_404(self.model, pk=pk)

    def get_queryset(self):
        instance = self.get_object()
        assets = instance.get_all_assets().only(
            *self.serializer_class.Meta.only_fields
        )
        return assets


class AutomationRemoveAssetApi(generics.UpdateAPIView):
    model = BaseAutomation
    queryset = BaseAutomation.objects.all()
    serializer_class = serializers.UpdateAssetSerializer
    http_method_names = ['patch']

    def update(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.serializer_class(data=request.data)

        if not serializer.is_valid():
            return Response({'error': serializer.errors})

        assets = serializer.validated_data.get('assets')
        if assets:
            instance.assets.remove(*tuple(assets))
        return Response({'msg': 'ok'})


class AutomationAddAssetApi(generics.UpdateAPIView):
    model = BaseAutomation
    queryset = BaseAutomation.objects.all()
    serializer_class = serializers.UpdateAssetSerializer
    http_method_names = ['patch']

    def update(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            assets = serializer.validated_data.get('assets')
            if assets:
                instance.assets.add(*tuple(assets))
            return Response({"msg": "ok"})
        else:
            return Response({"error": serializer.errors})


class AutomationNodeAddRemoveApi(generics.UpdateAPIView):
    model = BaseAutomation
    serializer_class = serializers.UpdateNodeSerializer
    http_method_names = ['patch']

    def update(self, request, *args, **kwargs):
        action_params = ['add', 'remove']
        action = request.query_params.get('action')
        if action not in action_params:
            err_info = _("The parameter 'action' must be [{}]".format(','.join(action_params)))
            return Response({"error": err_info})

        instance = self.get_object()
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            nodes = serializer.validated_data.get('nodes')
            if nodes:
                # eg: plan.nodes.add(*tuple(assets))
                getattr(instance.nodes, action)(*tuple(nodes))
            return Response({"msg": "ok"})
        else:
            return Response({"error": serializer.errors})


class AutomationExecutionViewSet(
    mixins.CreateModelMixin, mixins.ListModelMixin,
    mixins.RetrieveModelMixin, viewsets.GenericViewSet
):
    search_fields = ('id', 'trigger', 'automation__name')
    filterset_fields = ('trigger', 'automation_id', 'automation__name')
    filterset_class = AutomationExecutionFilterSet
    serializer_class = serializers.AutomationExecutionSerializer
    tp: str

    def get_queryset(self):
        queryset = AutomationExecution.objects.all()
        return queryset

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        automation = serializer.validated_data.get('automation')
        task = execute_account_automation_task.delay(
            pid=str(automation.pk), trigger=Trigger.manual, tp=self.tp
        )
        return Response({'task': task.id}, status=status.HTTP_201_CREATED)

    @xframe_options_sameorigin
    @action(methods=['get'], detail=True, url_path='report')
    def report(self, request, *args, **kwargs):
        execution = self.get_object()
        report = execution.manager.gen_report()
        return HttpResponse(report)
