# -*- coding: utf-8 -*-
#
# Copyright 2016 Continuum Analytics, Inc.
# May be copied and distributed freely only as part of an Anaconda or
# Miniconda installation.
#

"""
Community Tab.
"""

# Standard library imports
from __future__ import absolute_import, division, print_function
import json
import os
import sys
import random
import re

# Third party imports
from qtpy.QtCore import Qt, QTimer, Signal
from qtpy.QtGui import QImage, QPixmap
from qtpy.QtWidgets import QCheckBox, QHBoxLayout, QVBoxLayout

# Local imports
from anaconda_navigator.api import AnacondaAPI
from anaconda_navigator.config import (IMAGE_DATA_PATH, CONTENT_JSON_PATH,
                                       CONTENT_PATH)
from anaconda_navigator.data import LINKS_INFO_PATH
from anaconda_navigator.images import VIDEO_ICON_PATH
from anaconda_navigator.widgets import (FrameCommunity, LineEditSearch,
                                        WidgetBase)
from anaconda_navigator.widgets.videos import (ListItemContent,
                                               ListWidgetContent)
from anaconda_navigator.utils.logs import logger
from anaconda_navigator.utils.styles import load_style_sheet


class CommunityTab(WidgetBase):
    sig_video_started = Signal(str, int)
    sig_status_updated = Signal(object, int, int, int)
    instances = []

    VIDEOS_LIMIT = 20
    WEBINARS_LIMIT = 20
    EVENTS_LIMIT = 20

    def __init__(self, parent=None, tags=None, content_urls=None):
        super(CommunityTab, self).__init__(parent)

        self._parent = parent
        self._downloaded_urls = []
        self._downloaded_filepaths = []
        self.api = AnacondaAPI()
        self.content_urls = content_urls
        self.content_info = []
        self.step = 0
        self.step_size = 1
        self.tags = tags
        self.timer_load = QTimer()
        self.pixmaps = {}
        self.default_pixmap = QPixmap(VIDEO_ICON_PATH).scaled(
            100, 60, Qt.KeepAspectRatio, Qt.FastTransformation)

        # Widgets
        self.text_filter = LineEditSearch()
        self.frame_community = FrameCommunity()
        self.list = ListWidgetContent()

        # Widget setup
        self.timer_load.setInterval(333)
        self.list.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.text_filter.setPlaceholderText('Search')
        self.text_filter.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.setObjectName("Tab")

        self.list.setMinimumHeight(200)
        fm = self.text_filter.fontMetrics()
        self.text_filter.setMaximumWidth(fm.width('M'*23))

        # Layouts
        hlayout = QHBoxLayout()
        self.filters_layout = QHBoxLayout()

        layout = QVBoxLayout()
        layout.addLayout(hlayout)

        controls_layout = QHBoxLayout()
        controls_layout.addLayout(self.filters_layout)
        controls_layout.addStretch()
        controls_layout.addWidget(self.text_filter)
        layout.addLayout(controls_layout)
        layout.addWidget(self.list)
        self.frame_community.setLayout(layout)

        layout = QHBoxLayout()
        layout.addWidget(self.frame_community)
        self.setLayout(layout)

        # Signals
        self.timer_load.timeout.connect(self.set_content_list)
        self.text_filter.textChanged.connect(self.filter_content)

    def setup_tab(self):
        self.download_content()

    def _json_downloaded(self, worker, output, error):
        url = worker.url
        if url in self._downloaded_urls:
            self._downloaded_urls.remove(url)

        if not self._downloaded_urls:
            self.load_content()

    def download_content(self):
        self._downloaded_urls = []
        self._downloaded_filepaths = []

        if self.content_urls:
            for url in self.content_urls:
                url = url.lower()  # Enforce lowecase... just in case
                fname = url.split('/')[-1] + '.json'
                filepath = os.sep.join([CONTENT_PATH, fname])
                self._downloaded_urls.append(url)
                self._downloaded_filepaths.append(filepath)
                worker = self.api.download_async(url, filepath)
                worker.url = url
                worker.sig_finished.connect(self._json_downloaded)
        else:
            self.load_content()

    def load_content(self, paths=None):
        """
        Load downloaded and bundled content.
        """
        content = []

        # Load downloaded content
        for filepath in self._downloaded_filepaths:
            fname = filepath.split(os.sep)[-1]
            items = []
            if os.path.isfile(filepath):
                with open(filepath, 'r') as f:
                    data = f.read()
                try:
                    items = json.loads(data)
                except Exception as error:
                    logger.error(str((filepath, error)))
            else:
                items = []

            if 'video' in fname:
                for item in items:
                    try:
                        item['tags'] = ['video']
                        item['uri'] = item.get('video', '')

                        if item['uri']:
                            uri = item['uri'].split('watch?v=')[-1]
                            url = 'http://img.youtube.com/vi/{0}/0.jpg'.format(uri)
                            item['image_file_path'] = uri + '.jpg'
                        else:
                            url = ''
                            item['image_file_path'] = ''

                        item['banner'] = url
                        item['date'] = item.get('date_start', '')
                    except:
                        logger.debug("Video parse failed: %s", item)
                items = items[:self.VIDEOS_LIMIT]

            elif 'event' in fname:
                for item in items:
                    try:
                        item['tags'] = ['event'] + item.get('categories', '').split(', ')
                        item['uri'] = item.get('url', '')
                        if item['banner']:
                            item['image_file_path'] = item['banner'].split('/')[-1]
                        else:
                            item['banner'] = ''
                    except:
                        logger.debug('Event parse failed: %s', item)
                items = items[:self.EVENTS_LIMIT]

            elif 'webinar' in fname:
                for item in items:
                    try:
                        item['tags'] = ['webinar']
                        item['uri'] = item.get('url', '')
                        image = item.get('image', '')

                        if image and isinstance(image, dict):
                            item['banner'] = image.get('src', '')
                            if item['banner']:
                                item['image_file_path'] = item['banner'].split('/')[-1]
                            else:
                                item['image_file_path'] = ''
                        else:
                            item['banner'] = ''
                            item['image_file_path'] = ''
                    except:
                        logger.debug('Webinar parse failed: %s', item)
                items = items[:self.WEBINARS_LIMIT]

            if items:
                content.extend(items)

        # Load bundled content
        with open(LINKS_INFO_PATH, 'r') as f:
            data = f.read()
        items = []
        try:
            items = json.loads(data)
        except Exception as error:
            logger.error(str(filepath, error))
        content.extend(items)

        # Add the omage path to get the full path
        for item in content:
            filename = item['image_file_path']
            item['image_file_path'] = os.path.sep.join([IMAGE_DATA_PATH,
                                                        filename])
        self.content_info = content

        # Save loaded data in a single file
        with open(CONTENT_JSON_PATH, 'w') as f:
            json.dump(content, f)

        self.make_tag_filters()
        self.timer_load.start(random.randint(25, 35))

    def make_tag_filters(self):
        if not self.tags:
            self.tags = set()
            for content_item in self.content_info:
                tags = content_item.get('tags', [])
                for tag in tags:
                    if tag:
                        self.tags.add(tag)
        logger.debug("TAGS: %s", self.tags)
        self.filter_widgets = []
        for tag in self.tags:
            item = QCheckBox(tag.capitalize())
            item.setObjectName(tag.lower())
            item.setChecked(True)
            item.clicked.connect(self.filter_content)
            self.filter_widgets.append(item)
            self.filters_layout.addWidget(item)

    def filter_content(self, text=None):
        """
        Filter content by a search string on all the fields of the item.

        Using comma allows the use of several keywords, e.g. Peter,2015
        """
        text = self.text_filter.text().lower()
        text = [t for t in re.split('\W', text) if t]

        sel_tags = [i.text().lower() for i in self.filter_widgets if i.isChecked()]

        for i in range(self.list.count()):
            item = self.list.item(i)

            all_checks = []
            for t in text:
                t = t.strip()
                checks = (t in item.title.lower() or
                          t in item.venue.lower() or
                          t in ' '.join(item.authors).lower() or
                          t in item.summary.lower())
                all_checks.append(checks)
            all_checks.append(any(tag.lower() in sel_tags for tag in item.tags))

            if all(all_checks):
                item.setHidden(False)
            else:
                item.setHidden(True)

    def set_content_list(self):
        """
        Add items to the list, gradually.

        Called by a timer.
        """
        for i in range(self.step, self.step + self.step_size):
            if i < len(self.content_info):
                item = self.content_info[i]
                banner = item.get('banner', '')
                path = item.get('image_file_path', '')
                content_item = ListItemContent(
                    title=item['title'],
                    subtitle=item.get('subtitle', "") or "",
                    uri=item['uri'], date=item.get('date', '') or "",
                    summary=item.get('summary', '') or "",
                    tags=item.get('tags', []),
                    banner=banner,
                    path=path,
                    pixmap=self.default_pixmap
                    )
                self.list.addItem(content_item)
                content_item.pixmaps = self.pixmaps
                self.download_thumbnail(content_item, banner, path)
            else:
                self.timer_load.stop()
                break
        self.step += self.step_size
        self.filter_content()

    def download_thumbnail(self, item, url, path):
        """
        Download all the video thumbnails.
        """
        worker = self.api.download_async(url, path)
        worker.url = url
        worker.item = item
        worker.sig_finished.connect(self.convert_image)
        logger.debug('Fetching thumbnail %s', url)

    def convert_image(self, worker, output, error):
        """
        Load an image using PIL, and converts it to a QPixmap.

        This was needed as some image libraries are not found in some OS.
        """
        # Needs to come after qtpy imports
        path = output
        if path in self.pixmaps:
            return

        if path:
            if os.path.isfile(path):
                try:
                    if sys.platform == 'darwin':
                        from PIL.ImageQt import ImageQt
                        from PIL import Image

                        image = Image.open(path)
                        image = ImageQt(image)
                        qt_image = QImage(image)
                        pixmap = QPixmap.fromImage(qt_image)
                    else:
                        extension = path.split('.')[-1].upper()

                        if extension in ['PNG', 'JPEG', 'JPG']:
                            pixmap = QPixmap(path, format=extension)
                        else:
                            pixmap = QPixmap(path)

                    self.pixmaps[path] = pixmap
                except (IOError, OSError) as error:
                    logger.error(str(error))

    def update_style_sheet(self, style_sheet=None):
        if style_sheet is None:
            self.style_sheet = load_style_sheet()
        else:
            self.style_sheet = style_sheet

        self.setStyleSheet(self.style_sheet)
        self.list.update_style_sheet(self.style_sheet)


def dev_endpoints():
    dev = 'http://api-dev-continuum-content.pantheonsite.io/api/'
    VIDEOS_URL = dev + 'videos'
    EVENTS_URL = dev + 'events'
    WEBINARS_URL = dev + 'webinars'
    return [EVENTS_URL, VIDEOS_URL, WEBINARS_URL]


def production_endpoints():
    VIDEOS_URL = "http://content.continuum.io/api/videos"
    EVENTS_URL = "http://content.continuum.io/api/events"
    WEBINARS_URL = "http://content.continuum.io/api/webinars"
    return [EVENTS_URL, VIDEOS_URL, WEBINARS_URL]


def test_JSON_endpoint(dev=False):
    content = dev_endpoints() if dev else production_endpoints()
    w = CommunityTab(content_urls=content)
    w.update_style_sheet(load_style_sheet())
    w.setup_tab()
    w.showMaximized()
    return w


def test():
    from anaconda_navigator.utils.qthelpers import qapplication
    app = qapplication()
    w = test_JSON_endpoint(dev=False)
    w2 = test_JSON_endpoint(dev=True)

    ex = app.exec_()
    from anaconda_navigator.utils.logs import logfile
    text = open(logfile).read()
    if "'No JSON object could be decoded'" in text:
        sys.exit(1)
    sys.exit(ex)


if __name__ == "__main__":
    test()
