# Copyright (C) 2022  Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import requests
import vobject
from django.contrib.postgres.fields import ArrayField
from django.db import models
from django.http import HttpResponse
from django.utils.translation import gettext_lazy as _

from passerelle.base.models import BaseResource
from passerelle.utils.api import endpoint
from passerelle.utils.jsonresponse import APIError

from .forms import HolidaysConnectorForm

ZONE_CHOICES = (
    ('a', 'A'),
    ('b', 'B'),
    ('c', 'C'),
)

HOLIDAYS_LABELS = {
    'winter_holidays': "Vacances d’Hiver",
    'spring_holidays': 'Vacances de Pâques',
    'summer_holidays': "Vacances d’Été",
    'all_saints_holidays': 'Vacances de la Toussaint',
    'christmas_holidays': 'Vacances de Noël',
}


HOLIDAYS_CHOICES = [(x[0], x[1]) for x in HOLIDAYS_LABELS.items()]


ZONE_URLS = {
    'a': 'https://fr.ftp.opendatasoft.com/openscol/fr-en-calendrier-scolaire/Zone-A.ics',
    'b': 'https://fr.ftp.opendatasoft.com/openscol/fr-en-calendrier-scolaire/Zone-B.ics',
    'c': 'https://fr.ftp.opendatasoft.com/openscol/fr-en-calendrier-scolaire/Zone-C.ics',
}


HOLIDAYS_MAPPING = {
    "Vacances d'Hiver": 'winter_holidays',
    'Vacances de Printemps': 'spring_holidays',
    "Vacances d'Été": 'summer_holidays',
    'Vacances de la Toussaint': 'all_saints_holidays',
    'Vacances de Noël': 'christmas_holidays',
}


class Holidays(BaseResource):
    zone = models.CharField(_('Zone'), max_length=16, choices=ZONE_CHOICES)
    holidays = ArrayField(
        models.CharField(max_length=32, choices=HOLIDAYS_CHOICES),
        verbose_name=_('Holidays'),
        blank=False,
        null=False,
    )

    category = _('Misc')
    manager_form_base_class = HolidaysConnectorForm

    class Meta:
        verbose_name = _('School holidays')

    def get_holidays_display(self):
        return ', '.join(HOLIDAYS_LABELS[holiday] for holiday in self.holidays)

    @endpoint(name='holidays.ics', description=_('Get holidays ICS.'))
    def holidays_ics(self, request):
        try:
            response = self.requests.get(ZONE_URLS[self.zone])
            response.raise_for_status()
        except requests.exceptions.RequestException as e:
            raise APIError('Error while getting ICS file: %s' % e)

        try:
            parsed = vobject.readOne(response.text)
        except vobject.base.ParseError as e:
            raise APIError('Invalid ICS file: %s' % e)

        if not parsed.contents.get('vevent'):
            raise APIError('ICS file does not contain events.')

        cal = vobject.iCalendar()
        for vevent in parsed.contents.get('vevent'):
            description = vevent.contents['summary'][0].value

            holiday_id = HOLIDAYS_MAPPING.get(description)
            if holiday_id not in self.holidays:
                continue

            new_vevent = cal.add('vevent')
            new_vevent.add('summary').value = HOLIDAYS_LABELS[holiday_id]
            new_vevent.add('uid').value = '%s-%s' % (holiday_id, vevent.dtstart.value.year)
            new_vevent.add('categories').value = [holiday_id]
            new_vevent.add('dtstart').value = vevent.dtstart.value
            new_vevent.add('dtend').value = vevent.dtend.value

        return HttpResponse(cal.serialize(), content_type='text/calendar')
