# -*- coding: utf-8 -*-

# pylint: disable=missing-module-docstring

from http import HTTPStatus
from urllib.parse import urlparse
import requests
from anaconda_navigator.utils.logs import http_logger


class AdvertisementMixin:  # pylint: disable=missing-class-docstring,too-few-public-methods
    def _is_valid_url(self, url):
        parse_result = urlparse(url)

        if not all((parse_result.scheme, parse_result.netloc, parse_result.path)):
            self.errors.append(f'{url} is not a valid URL')
            return False
        return True

    def _log_errors(self):
        for error in self.errors:
            http_logger.error(error)


class AdvertisementsList(AdvertisementMixin):  # pylint: disable=missing-class-docstring
    BANNER_TIMEOUT_MS = 60000  # pylint: disable=invalid-name

    def __init__(self, source_url):
        self.source_url = source_url
        self.advertisements = []
        self.errors = []
        self.load()

        self._log_errors()

    def load(self):
        """
        Tries to load the data to be displayed in the advertisements.
        """
        try:
            resp = requests.get(self.source_url)
            http_logger.http(response=resp)
            if resp.status_code == HTTPStatus.OK:
                for data in resp.json():
                    image_url = data.get('image_url')
                    redirect_url = data.get('redirect_url')
                    text = data.get('text')

                    ad = Advertisement(image_url, redirect_url, text)  # pylint: disable=invalid-name

                    if ad.is_valid():
                        self.advertisements.append(ad)

        except requests.ConnectionError:
            self.errors.append(f'Tried to load advertisement data from {self.source_url}. URL is not reachable')
        except Exception as e:  # pylint: disable=broad-except,invalid-name
            self.errors.append(f'Unexpected error while loading advertisement. Stacktrace: {str(e)}')

    def advertisements_carousel(self):  # pylint: disable=missing-function-docstring
        start_pos = 0
        adlen = len(self.advertisements)
        while start_pos < adlen:
            curr_pos = start_pos
            res = self.advertisements[start_pos]
            start_pos = (start_pos + 1) if start_pos + 1 < adlen else 0
            yield curr_pos, res


class Advertisement(AdvertisementMixin):  # pylint: disable=too-few-public-methods
    """
    Class for loading advertisements data, handling errors and validating data.
    """
    def __init__(self, image_url, redirect_url, text):
        self.errors = []
        self.image = None
        if self._is_valid_url(image_url):
            self.image = self._load_image(image_url)

        self.url = None
        if self._is_valid_url(redirect_url):
            self.url = redirect_url

        self.text = text

        self._log_errors()

    def is_valid(self):
        """
        Checks if all needed data is present and correct.
        """
        image_and_link = self.image and self.url
        text_and_link = self.text and self.url
        all_set = self.text and self.url and self.image

        return all_set or image_and_link or text_and_link

    def _load_image(self, image_url):
        """
        Tries to load the image of an advertisement.

        :param str image_url: The url of the image to be downloaded.
        """
        resp = requests.get(image_url)
        http_logger.http(response=resp)

        if resp.status_code == HTTPStatus.OK:
            return resp.content
        self.errors.append(
            f'Tried to load advertisement image from {image_url}. Data is not fetched with status {resp.status_code}',
        )
        return None
