from abc import abstractmethod
from urllib.parse import urlparse
from urllib.parse import parse_qs
from bs4 import BeautifulSoup


import logging

logger = logging.getLogger(__name__)


from .extractor import *
from django.utils.translation import gettext_lazy as _
from dateutil import parser
import datetime

# A class to extract events from URL with two steps:
# - first build a list of urls where the events will be found
# - then for each document downloaded from these urls, build the events
# This class is an abstract class
class TwoStepsExtractor(Extractor):

    def __init__(self):
        super().__init__()
        self.has_2nd_method_in_list = False
        self.event_urls = None
        self.event_properties = {}

    def clean_url(url):
        return url

    def add_event_url(self, url):
        if url in self.event_urls:
            return False
        else:
            self.event_urls.append(url)
            return True

    def add_event_property(self, url, key, value):
        if url not in self.event_properties:
            self.event_properties[url] = {}
        self.event_properties[url][key] = value

    def add_event_url_human(self, url, url_human):
        self.add_event_property(url, "url_human", url_human)
    
    def add_event_start_day(self, url, start_day):
        self.add_event_property(url, "start_day", start_day)

    def add_event_start_time(self, url, start_time):
        self.add_event_property(url, "start_time", start_time)

    def add_event_title(self, url, title):
        self.add_event_property(url, "title", title)

    def add_event_tag(self, url, tag):
        if url not in self.event_properties:
            self.event_properties[url] = {}
        if "tags" not in self.event_properties[url]:
            self.event_properties[url]["tags"] = []
        self.event_properties[url]["tags"].append(tag)

    def add_event_category(self, url, cat):
        self.add_event_property(url, "category", cat)

    def add_event_location(self, url, loc):
        self.add_event_property(url, "location", loc)

    def add_event_with_props(
        self,
        default_values,
        event_url,
        title,
        category,
        start_day,
        location,
        description,
        tags,
        uuids,
        recurrences=None,
        url_human=None,
        start_time=None,
        end_day=None,
        end_time=None,
        last_modified=None,
        published=False,
        image=None,
        image_alt=None,
    ):
        if event_url in self.event_properties:
            if "tags" in self.event_properties[event_url]:
                tags = tags + self.event_properties[event_url]["tags"]
            if "start_day" in self.event_properties[event_url]:
                start_day = self.event_properties[event_url]["start_day"]
            if "start_time" in self.event_properties[event_url]:
                start_time = self.event_properties[event_url]["start_time"]
            if "title" in self.event_properties[event_url]:
                title = self.event_properties[event_url]["title"]
            if "category" in self.event_properties[event_url]:
                category = self.event_properties[event_url]["category"]
            if "location" in self.event_properties[event_url]:
                location = self.event_properties[event_url]["location"]
            if "url_human" in self.event_properties[event_url]:
                url_human = self.event_properties[event_url]["url_human"]

        self.add_event(
            default_values,
            title,
            category,
            start_day,
            location,
            description,
            tags,
            uuids,
            recurrences,
            url_human,
            start_time,
            end_day,
            end_time,
            last_modified,
            published,
            image,
            image_alt,
        )

    @abstractmethod
    def build_event_url_list(self, content):
        pass

    @abstractmethod
    def add_event_from_content(
        self,
        event_content,
        event_url,
        url_human=None,
        default_values=None,
        published=False,
    ):
        pass

    def prepare_2nd_extract_in_list(self):
        pass

    def extract(
        self,
        content,
        url,
        url_human=None,
        default_values=None,
        published=False,
        only_future=True,
        ignore_404=True,
        first=True

    ):

        first = True
        self.only_future = only_future
        self.now = datetime.datetime.now().date()
        self.set_header(url)
        self.clear_events()

        self.url = url
        self.url_human = url_human
        self.event_urls = []
        self.event_properties.clear()

        # first build the event list
        self.build_event_url_list(content)

        if self.event_urls is None:
            raise Exception("Unable to find the event list from the main document")

        if self.downloader is None:
            raise Exception("The downloader is not defined")

        # then process each element of the list
        for i, event_url in enumerate(self.event_urls):
            # first download the content associated with this link
            content_event = self.downloader.get_content(event_url)
            if content_event is None:
                msg = "Cannot extract event from url {}".format(event_url)
                if ignore_404:
                    logger.error(msg)
                else:
                    raise Exception(msg)
            else:
                # then extract event information from this html document
                try:
                    self.add_event_from_content(
                        content_event, event_url, url_human, default_values, published
                    )
                except Exception as e:
                    # some website (FB) sometime need a second step
                    if first and self.has_2nd_method_in_list and self.downloader.support_2nd_extract:
                        logger.info('Using cookie trick on a facebook event')
                        first = False
                        # TMP: on trace ce qui se passe
                        from agenda_culturel.import_tasks.generic_extractors import fbevents
                        fbevents.CExtractor.dump_content_for_debug(content_event, event_url)
                        self.prepare_2nd_extract_in_list()
                        content_event = self.downloader.get_content(event_url)
                        if not content_event is None:
                            self.add_event_from_content(
                                content_event, event_url, url_human, default_values, published
                            )
                    else:
                        raise e


        return self.get_structure()


class TwoStepsExtractorNoPause(TwoStepsExtractor):

    def extract(
        self,
        content,
        url,
        url_human=None,
        default_values=None,
        published=False,
        only_future=True,
        ignore_404=True
    ):
        if hasattr(self.downloader, "pause"):
            pause = self.downloader.pause
        else:
            pause = False
        self.downloader.pause = False
        result = super().extract(content, url, url_human, default_values, published, only_future, ignore_404)
        self.downloader.pause = pause

        return result

