import base64

from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers

from .models import *

class VPNPoolSerializer(serializers.ModelSerializer):
    class Meta:
        model = VPNPool
        fields = '__all__'

class VPNNetworkReservationSerializer(serializers.ModelSerializer):
    class Meta:
        model = VPNNetworkReservation
        fields = '__all__'


class VPNNetworkSerializer(serializers.ModelSerializer):
    class Meta:
        model = VPNNetwork
        fields = '__all__'

    # This is required for finding the VPN pool, but does not
    # exist in the model
    network_size = serializers.IntegerField(min_value=0,
                                            max_value=128,
                                            write_only=True)

    def validate_wireguard_public_key(self, value):
        msg = _("Supplied key is not a valid wireguard public key")

        """ FIXME: verify that this does not create broken wireguard config files,
        i.e. contains \n or similar!
        We might even need to be more strict to not break wireguard...
        """

        try:
            base64.standard_b64decode(value)
        except Exception as e:
            raise serializers.ValidationError(msg)

        if '\n' in value:
            raise serializers.ValidationError(msg)

        return value

    def validate(self, data):

        # FIXME: filter for status = active or similar
        all_pools = VPNPool.objects.all()
        sizes = [ p.subnetwork_size for p in all_pools ]

        pools = VPNPool.objects.filter(subnetwork_size=data['network_size'])

        if len(pools) == 0:
            msg = _("No pool available for networks with size = {}. Available are: {}".format(data['network_size'], sizes))
            raise serializers.ValidationError(msg)

        return data

    def create(self, validated_data):
        """
        Creating a new vpnnetwork - there are a couple of race conditions,
        especially when run in parallel.

        What we should be doing:

        - create a reservation race free
        - map the reservation to a network (?)
        """

        pools = VPNPool.objects.filter(subnetwork_size=validated_data['network_size'])

        vpn_network = None

        for pool in pools:
            if pool.num_free_networks > 0:
                next_address = pool.next_free_network

                reservation, created = VPNNetworkReservation.objects.update_or_create(
                    vpnpool=pool, address=next_address,
                    defaults = {
                        'status': 'used'
                    })

                vpn_network = VPNNetwork.objects.create(
                    owner=self.context['request'].user,
                    network=reservation,
                    wireguard_public_key=validated_data['wireguard_public_key']
                )

                break
        if not vpn_network:
            # FIXME: use correct exception
            raise Exception("Did not find any free pool")


        return vpn_network