import json

from django.db.models import Q
from rest_framework import serializers

from assets.constants import RESOLVED_STATUS
from assets.models.assets import Asset, AssetListGroup, OperatingSystem, AssetManufacturer
from console.models import Vulnerability
from core.serializers import DateTimeLocalizedField, ModelLocalizedSerializer
from incident.models import Incident
from incident.serializers.incident import IncidentSerializer


class OsSerializer(serializers.ModelSerializer):
    class Meta:
        model = OperatingSystem
        fields = '__all__'


class OsNameSerializer(serializers.ModelSerializer):
    class Meta:
        model = OperatingSystem
        fields = ['name']


class AssetManufacturerSerializer(serializers.ModelSerializer):
    class Meta:
        model = AssetManufacturer
        fields = ['id', 'name', 'description']


class AssetGroupSerializer(serializers.ModelSerializer):
    class Meta:
        model = AssetListGroup
        fields = ['name', 'description', 'id', 'collapsed']


class AssetListSerializer(serializers.ModelSerializer):
    updated = DateTimeLocalizedField()
    count_incidents = serializers.IntegerField()

    class Meta:
        model = Asset
        fields = ['id', 'name', 'asset_type', 'status', 'ip', 'updated', 'count_incidents']


class AssetDetailSerializer(serializers.ModelSerializer):
    os = OsSerializer()
    group = AssetGroupSerializer()
    incidents = IncidentSerializer(many=True)
    ports = serializers.SerializerMethodField()
    updated = DateTimeLocalizedField()

    class Meta:
        model = Asset
        fields = '__all__'

    def get_ports(self, asset):
        try:
            ports = json.loads(asset.ports)
            return f'{ports}' or f'{[]}'
        except TypeError:
            return f'{[]}'


class AssetCreateUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Asset
        fields = '__all__'

    def to_representation(self, instance):
        return AssetDetailSerializer(instance=instance).data


class AssetAuthorizeSerializer(serializers.Serializer):
    selected_assets = serializers.ListField(child=serializers.IntegerField())


class AssetCsvExportSerializer(ModelLocalizedSerializer):
    """ Serializer for CSV export of Assets data
    The idea behind parsing almost every field is that if we dont do this, than fields that are used as links to the
        other models will be shown in table as the dictionary
    """
    incidents = serializers.SerializerMethodField('get_incidents')
    os = serializers.ReadOnlyField(source='os.name', allow_null=True)
    group = serializers.ReadOnlyField(source='group.name', allow_null=True)
    asset_type = serializers.ReadOnlyField(source='get_asset_type_display', allow_null=True)
    status = serializers.ReadOnlyField(source='get_status_display', allow_null=True)
    manufacturer = serializers.ReadOnlyField(source='manufacturer_name', allow_null=True)

    def get_incidents(self, obj):
        amount_of_active_incs = Incident.objects.filter(~Q(status=RESOLVED_STATUS), asset=obj).count()
        return amount_of_active_incs

    class Meta:
        model = Asset
        fields = ['name', 'manufacturer', 'updated', 'model', 'ip', 'os', 'ports', 'incidents',
                  'group', 'asset_type', 'status']


class IncidentTitleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Incident
        fields = ['pk', 'title', 'status']


class AssetInfoSerializer(serializers.ModelSerializer):
    incidents = IncidentTitleSerializer(many=True)
    os = OsNameSerializer()
    updated = DateTimeLocalizedField()

    class Meta:
        model = Asset
        fields = ['id', 'name', 'description', 'ip', 'os', 'ports', 'updated', 'incidents', 'status']


class AssetIncidentInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Incident
        fields = ['pk', 'title', 'description', 'status']


class AssetVulnerabilitiesInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Vulnerability
        fields = ['name', 'description']


class AssetActiveProblemsSerializer(serializers.ModelSerializer):
    incidents = AssetIncidentInfoSerializer(many=True)

    def get_incidents(self, obj):
        inc_queryset = Incident.objects.filter(~Q(status=RESOLVED_STATUS), asset=obj)
        serializer = AssetIncidentInfoSerializer(instance=inc_queryset, many=True, context=self.context)
        return serializer.data

    class Meta:
        model = Asset
        fields = ['incidents']
