"""
Defines forms for providing validation of embargo admin details.
"""

from django import forms

from embargo.models import EmbargoedCourse, EmbargoedState, IPFilter
from embargo.fixtures.country_codes import COUNTRY_CODES

import socket

from xmodule.modulestore.django import modulestore


class EmbargoedCourseForm(forms.ModelForm):  # pylint: disable=incomplete-protocol
    """Form providing validation of entered Course IDs."""

    class Meta:  # pylint: disable=missing-docstring
        model = EmbargoedCourse

    def clean_course_id(self):
        """Validate the course id"""
        course_id = self.cleaned_data["course_id"]

        # Try to get the course.  If this returns None, it's not a real course
        try:
            course = modulestore().get_course(course_id)
        except ValueError:
            msg = 'COURSE NOT FOUND'
            msg += u' --- Entered course id was: "{0}". '.format(course_id)
            msg += 'Please recheck that you have supplied a valid course id.'
            raise forms.ValidationError(msg)
        if not course:
            msg = 'COURSE NOT FOUND'
            msg += u' --- Entered course id was: "{0}". '.format(course_id)
            msg += 'Please recheck that you have supplied a valid course id.'
            raise forms.ValidationError(msg)

        return course_id


class EmbargoedStateForm(forms.ModelForm):  # pylint: disable=incomplete-protocol
    """Form validating entry of states to embargo"""

    class Meta:  # pylint: disable=missing-docstring
        model = EmbargoedState

    def _is_valid_code(self, code):
        """Whether or not code is a valid country code"""
        return code in COUNTRY_CODES

    def clean_embargoed_countries(self):
        """Validate the country list"""
        embargoed_countries = self.cleaned_data["embargoed_countries"]
        if not embargoed_countries:
            return ''

        error_countries = []

        for country in embargoed_countries.split(','):
            country = country.strip().upper()
            if not self._is_valid_code(country):
                error_countries.append(country)

        if error_countries:
            msg = 'COULD NOT PARSE COUNTRY CODE(S) FOR: {0}'.format(error_countries)
            msg += ' Please check the list of country codes and verify your entries.'
            raise forms.ValidationError(msg)

        return embargoed_countries


class IPFilterForm(forms.ModelForm):  # pylint: disable=incomplete-protocol
    """Form validating entry of IP addresses"""

    class Meta:  # pylint: disable=missing-docstring
        model = IPFilter

    def _is_valid_ipv4(self, address):
        """Whether or not address is a valid ipv4 address"""
        try:
            # Is this an ipv4 address?
            socket.inet_pton(socket.AF_INET, address)
        except socket.error:
            return False
        return True

    def _is_valid_ipv6(self, address):
        """Whether or not address is a valid ipv6 address"""
        try:
            # Is this an ipv6 address?
            socket.inet_pton(socket.AF_INET6, address)
        except socket.error:
            return False
        return True

    def _valid_ip_addresses(self, addresses):
        """
        Checks if a csv string of IP addresses contains valid values.

        If not, raises a ValidationError.
        """
        if addresses == '':
            return ''
        error_addresses = []
        for addr in addresses.split(','):
            address = addr.strip()
            if not (self._is_valid_ipv4(address) or self._is_valid_ipv6(address)):
                error_addresses.append(address)
        if error_addresses:
            msg = 'Invalid IP Address(es): {0}'.format(error_addresses)
            msg += ' Please fix the error(s) and try again.'
            raise forms.ValidationError(msg)

        return addresses

    def clean_whitelist(self):
        """Validates the whitelist"""
        whitelist = self.cleaned_data["whitelist"]
        return self._valid_ip_addresses(whitelist)

    def clean_blacklist(self):
        """Validates the blacklist"""
        blacklist = self.cleaned_data["blacklist"]
        return self._valid_ip_addresses(blacklist)
