# Copyright (c) 2014 - 2017, Carlos Millett
# All rights reserved.
#
# This software may be modified and distributed under the terms
# of the Simplified BSD License.  See the LICENSE file for details.


#
# Import
#
import re
import json
import time
import difflib

from collections import namedtuple
from urllib import error as urlerr
from urllib import request as urlRequest

from . import error


#
# Class
#
class Web():
    def _downloadData(self, link):
        try:
            down = urlRequest.urlopen(link)

        except urlerr.URLError:
            raise error.DownloadError("Failed to fetch data.")

        else:
            data = down.read()
            text = json.loads(data.decode("UTF-8"))
            return text

    def searchShow(self, title):
        saneTitle = re.sub("\W", "+", title)
        url = [self.url]
        url.extend(["search", "q={}".format(saneTitle)])
        link = "&".join(url)
        return self._downloadData(link)

    def lookupShow(self):
        link = self._show.link
        return self._downloadData(link)


class TvShow(Web):
    def __init__(self, title, country=None, year=None):
        self.url = "http://api.tvmaze.com/search/shows?"
        self._show = None
        self._season = None
        self._curSeason = None

        showsList = self._findShow(title)
        if not showsList:
            strerror = "Could not find {}.".format(title.upper())
            raise error.NotFoundError(strerror)
        self._show = self._selectShow(showsList, country, year)

    def _findShow(self, title):
        showCand = namedtuple("Show", ["title", "country", "premier", "thetvdb", "link"])
        showsList = []
        genID = (lambda x: re.sub("\W", "", x.upper()))

        match = difflib.SequenceMatcher(None, genID(title))
        showInfo = self.searchShow(title)
        for entry in [x for x in showInfo if x["show"]["premiered"]]:
            match.set_seq2(genID(entry["show"]["name"]))
            if match.quick_ratio() < 0.975:
                continue

            network = entry["show"]["network"]
            webchannel = entry["show"]["webChannel"]
            showProvider = network if network else webchannel
            countryCode = showProvider["country"]["code"] if showProvider["country"] else None

            newItem = showCand(
                title=entry["show"]["name"],
                country=countryCode,
                premier=entry["show"]["premiered"],
                thetvdb=entry["show"]["externals"]["thetvdb"],
                link="{}/episodes".format(entry["show"]["_links"]["self"]["href"])
            )
            showsList.append(newItem)
        return showsList

    def _selectShow(self, showsList, country, year):
        showsList.sort(key=lambda x: x.premier, reverse=True)
        if year and country:
            selYear = [
                x for x in showsList if int(year) == time.strptime(x.premier, "%Y-%m-%d").tm_year
            ]
            selCountry = [x for x in showsList if country == x.country]
            sel = list(filter(lambda x: x in selYear, selCountry))

        elif year:
            sel = [
                x for x in showsList if int(year) == time.strptime(x.premier, "%Y-%m-%d").tm_year
            ]

        elif country:
            sel = [x for x in showsList if country == x.country]

        else:
            sel = showsList

        return sel.pop()

    def populate(self):
        self._epsInfo = self.lookupShow()

    @property
    def title(self):
        return self._show.title

    @property
    def season(self):
        return self._curSeason

    @season.setter
    def season(self, season):
        if self._curSeason != season:
            self._curSeason = season
            self._season = {
                "{:0>2}".format(x["number"]): x["name"]
                for x in self._epsInfo if "{:0>2}".format(x["season"]) == self._curSeason
            }

    @property
    def seasonEps(self):
        return self._season

    @property
    def thetvdb(self):
        return self._show.thetvdb

@@ -246,23 +246,8 @@
 time
-%0Aimport difflib
 %0A%0Afr
@@ -354,16 +354,47 @@
 lRequest
+%0Afrom fuzzywuzzy import process
 %0A%0Afrom .
@@ -1287,25 +1287,24 @@
 ason = None%0A
-%0A
         show
@@ -1304,746 +1304,333 @@
    s
-howsList = self._findShow(title)%0A        if not showsList:%0A            strerror = %22Could not find %7B%7D.%22.format(title.upper())%0A            raise error.NotFoundError(strerror)%0A        self._show = self._selectShow(showsList, country, year)%0A%0A    def _findShow(self, title):%0A        showCand = namedtuple(%22Show%22, %5B%22title%22, %22country%22, %22premier%22, %22thetvdb%22, %22link%22%5D)%0A        showsList = %5B%5D%0A        genID = (lambda x: re.sub(%22%5CW%22, %22%22, x.upper()))%0A%0A        match = difflib.SequenceMatcher(None, genID(title))%0A        showInfo = self.searchShow(title)%0A        for entry in %5Bx for x in showInfo if x%5B%22show%22%5D%5B%22premiered%22%5D%5D:%0A            match.set_seq2(genID(entry%5B%22show%22%5D%5B%22name%22%5D))%0A            if match.quick_ratio() %3C 0.975:%0A                continue%0A
+elf._show = self._selectShow(self._findShow(title), country, year)%0A%0A    def _findShow(self, title):%0A        showCand = namedtuple(%22Show%22, %5B%22title%22, %22country%22, %22premier%22, %22thetvdb%22, %22link%22%5D)%0A        showsList = %5B%5D%0A%0A        showInfo = self.searchShow(title)%0A        for entry in %5Bx for x in showInfo if x%5B%22show%22%5D%5B%22premiered%22%5D%5D:
 %0A   
@@ -2248,24 +2248,25 @@
 ewItem)%0A
+%0A
         
 return s
@@ -2261,24 +2261,266 @@
     
-return showsList
+candidates = %7Bx: x.title for x in showsList%7D%0A        if len(candidates) == 0:%0A            strerror = %22Could not find %7B%7D.%22.format(title.upper())%0A            raise error.NotFoundError(strerror)%0A%0A        return %5Bx%5B2%5D for x in process.extract(title, candidates)%5D
 %0A%0A  

refactor show title matching code