#!/usr/bin/env python
# =======================================================================
# title             :SerialDo0n
# description       :This program displays Information About Tv Series
# author            :LinArcX
# date              :03/21/2017
# version           :1.2.0
# mail              :linarcx@gmail.com
# web               :stack.blog.ir
# notes             :
# python_version    :3.6.0
# main api:         :http://www.tvmaze.com/api
# second api:       :https://www.episodate.com/api
# =======================================================================

# Import the modules needed to run TvDo0n.
import os
import pwd
import queue
import re
import sys
from datetime import datetime

import pytvmaze
from prettytable import PrettyTable
from pyfiglet import figlet_format
import argparse

from threads import threadDotCount
from threads import threadSchedule

from utility import colors
from utility import fileUtil
from utility import tvMazeUtil
from utility import constants


# =======================
#     MENUS FUNCTIONS
# =======================


def main_menu():
    os.system('clear')
    fileUtil.checkConfExist()
    username = pwd.getpwuid(os.getuid()).pw_name
    print(colors.BOLD + figlet_format('TvDo0n', font='starwars') + colors.END)
    print("Welcome " + username + ", Please Choose The Items:")
    print("s. Search Tv Series")
    print("m. My Favourites")
    print("u. Up-Coming Tv Show's")
    print("w. Who Am I?")
    print("h. Help" + " (v.1.2)")
    print("\nq. Quit")
    switchCreator("smuwhq","","")
    return


def searchTvSeries(pItems=None):
    items = ""
    try:
        if pItems is None:
            os.system('clear')
            itemShow = input("Enter Tv Show Name:")
            items=pytvmaze.show_search(itemShow)
        else:
            items = pItems
        x = PrettyTable()
        for i, item in enumerate(items):
            x.field_names = [i, "seriesname"]
            x.add_row([i, item.name])
        print(x)
        print(
            colors.CYAN + "to view more details, enter 'row Number' and hit ENTER.otherwise use below Capabilities." + colors.END)
    except Exception:
        print("There Is No Matching Tv Show")
    print("b. Back")
    print("q. Quit")
    itemChooser(len(items), searchTvSeries, selectTvShow, items)
    return


def selectTvShow(pItems, tvdbID=None):
    originalParams = "soazcibqfd"
    finalParams = ""
    try:
        tvItem = ""
        if tvdbID is not None:
            tvItem = tvMazeUtil.extractTV(tvdbID, pItems)
        else:
            tvItem = pItems
            tvdbID = tvItem.externals['thetvdb']
        deltaDate, nextReleaseDate = tvMazeUtil.tvMazeDate(tvItem)
        finalGenres = ""
        favExists = False
        try:
            x = PrettyTable()
            x.add_column("ID.", [tvdbID])
            x.add_column("Name", [tvItem.name])
            x.add_column("Rating", [tvItem.rating['average']])
            for item in tvItem.genres:
                finalGenres += str(item) + " | "
            x.add_column("Genres", [finalGenres.rsplit('|',1)[0]])
            x.add_column("Status", [tvItem.status])
            x.add_column("Premiered", [tvItem.premiered])
            x.add_column("Final Aired", [tvItem.previous_episode.airdate])
            x.add_column("Last ses/ep", [str(tvItem.previous_episode.season_number) + "/" + str(tvItem.previous_episode.episode_number)])
            if tvItem is not None:
                x.add_column("Next Episode",[nextReleaseDate])
                x.add_column("days to next...",[deltaDate])
            print(x)
        except ValueError:
            main_menu()
        except IndexError:
            print("Oops! You Enter Incorrect Number.Please Select Another Series Again: ")
            selectTvShow(pItems, tvdbID)
        favFile = open(fileUtil.PATH + "favourites.conf", "r")
        for line in favFile:
            if tvItem.name in line:
                favExists = True
        favFile.close()
        if favExists:
            print(
                colors.BOLD + colors.CYAN + "This Is your Favourite Serie." + colors.END)
            print("d. Delete From Favourites")
            finalParams = originalParams.replace("f", "")
        else:
            print("f. Favourite This!")
            finalParams = originalParams.replace("d", "")
        favFile.close()
        print("s. Search Another Tv Show")
        print("o. OverView")
        print("a. Actors")
        print("z. Seasons/Episodes")
        print("c. Crews")
        print("i. More Info")
    except:
        print("there is no enough Information")
        print("s. Search Another Tv Show")
        finalParams = originalParams.replace("o", "")
        finalParams = finalParams.replace("a", "")
        finalParams = finalParams.replace("f", "")
        finalParams = finalParams.replace("d", "")
    print("b. Back")
    print("q. Quit")
    switchCreator(finalParams, pItems, "searchTvSeries", tvdbID)
    return


def OverView(pItems, tvdbID):
    tvItem = tvMazeUtil.extractTV(tvdbID, pItems)
    print("overview: \n")
    print(colors.RED + str(tvItem.summary) + colors.END)
    print("b. Back")
    print("q. Quit")
    switchCreator("bqacizs", pItems, "selectTvShow", tvdbID)
    return

def actors(pItems, tvdbID):
    try:
        tvItem = tvMazeUtil.extractTV(tvdbID, pItems)
        peoples = pytvmaze.show_cast(tvItem.maze_id).people
        x = PrettyTable()
        for i, people in enumerate(peoples):
            x.field_names = [i, "Character", "Person"]
            x.add_row([i, colors.GREEN + people.character.name + colors.END,
                       colors.CYAN + people.name + colors.END])
        print(x)
    except Exception as e:
        print("Sorry, there is no information about actors!")
    print("b. Back")
    print("q. Quit")
    switchCreator("qbocsiz", pItems, "selectTvShow", tvdbID)
    return

def seasons(pItems, tvdbID):
    seasons = 0
    try:
        tvItem = tvMazeUtil.extractTV(tvdbID, pItems)
        seasons = pytvmaze.show_seasons(tvItem.maze_id)
        x = PrettyTable()
        for i, season in enumerate(seasons):
            x.field_names = ["Seasons"]
            x.add_row([i+1])
        print(x)
        print(colors.CYAN + "to view the list of episodes, enter 'row Number' and hit ENTER.otherwise use below Capabilities." + colors.END)
    except Exception as e:
        print("Sorry, there is no information about seasons!")
    print("b. Back")
    print("q. Quit")
    itemChooser(len(seasons)+1, seasons, episodes, pItems, tvdbID)
    return


def episodes(pItems, tvdbID, seasonNum):
    try:
        tvItem = tvMazeUtil.extractTV(tvdbID, pItems)
        x = PrettyTable()
        for i, episode in enumerate(tvItem.episodes):
            if episode.season_number == int(seasonNum):
                x.field_names = ["Seasons/Episodes", "Title"]
                x.add_row([colors.CYAN + seasonNum + "/" + str(episode.episode_number) + colors.END, episode.title])
        print(x)
    except Exception as e:
        print("Sorry, there is no information about episodes!")
    print("b. Back")
    print("q. Quit")
    switchCreator("qb", pItems, "seasons", tvdbID)
    return

def crews(pItems, tvdbID):
    try:
        tvItem = tvMazeUtil.extractTV(tvdbID, pItems)
        crews = pytvmaze.get_show_crew(tvItem.maze_id)
        x = PrettyTable()
        for i, people in enumerate(crews):
            x.field_names = [i, "Person", "Role"]
            x.add_row([i, colors.GREEN + people.person.name + colors.END,
                       colors.CYAN + people.type + colors.END])
        print(x)
    except Exception as e:
        print("Sorry, there is no information about crews!")
    print("b. Back")
    print("q. Quit")
    switchCreator("qboas", pItems, "selectTvShow", tvdbID)
    return


def moreInfo(pItems, tvdbID):
    schedule = ""
    try:
        tvItem = tvMazeUtil.extractTV(tvdbID, pItems)
        x = PrettyTable()
        x.add_column("Network", [tvItem.network.name])
        x.add_column("Country", [tvItem.network.country])
        for item in tvItem.schedule['days']:
            schedule += str(item) + " | "
        x.add_column("Schedule Days", [schedule.rsplit('|', 1)[0]])
        x.add_column("Schedule Time", [tvItem.schedule['time']])
        x.add_column("RunTime", [tvItem.runtime])
        x.add_column("Score", [tvItem.score])
        print(x)
    except Exception as e:
        print("Sorry, there is no information about crews!")
    print("b. Back")
    print("q. Quit")
    switchCreator("qboas", pItems, "selectTvShow", tvdbID)
    return


def favouriteThis(pItems, tvdbID):
    tvItem = tvMazeUtil.extractTV(tvdbID, pItems)
    favFile = open(fileUtil.PATH + "favourites.conf", "a")
    favFile.write(tvItem.name + "-" + str(tvdbID) + "\n")
    favFile.close()
    print(
        colors.GREEN + "'" + tvItem.name + "'" + " Successfully Added to Your Favourite List." + colors.END)
    print("b. Back")
    print("q. Quit")
    switchCreator("qbos", pItems, "selectTvShow", tvdbID)
    return


def deleteFavourites(pItems, tvdbID):
    tvItem = tvMazeUtil.extractTV(tvdbID, pItems)

    # open File in ReadOnly-Mode
    f = open(fileUtil.PATH + "favourites.conf", "r")
    rLines = f.readlines()
    f.close()

    # Open File in Write-Mode
    f = open(fileUtil.PATH + "favourites.conf", "w")
    for line in rLines:
        if tvItem.name not in line:
            f.write(line)

    f.close()
    print(
        colors.CYAN + "'" + tvItem.name + "'" + " was Successfully removed from your favourite list" + colors.END)
    print("b. Back")
    print("q. Quit")
    switchCreator("qbos", pItems, "selectTvShow", tvdbID)
    return


def myFavourites():
    lineCount = 0
    allResults = []
    x = PrettyTable()
    favFile = open(fileUtil.PATH + "favourites.conf", "r")
    if os.path.getsize(fileUtil.PATH + "favourites.conf") > 0:
        for i, line in enumerate(favFile):
            item=pytvmaze.lookup_tvdb(line.split("-")[1])
            allResults.append(item)
            deltaDate, nextReleaseDate = tvMazeUtil.tvMazeDate(item)
            x.field_names = [i, "seriesname", "next Episode", "days to next..."]
            x.add_row([i, line.split("-")[0], nextReleaseDate, deltaDate])
            lineCount+=1
        print(x)
        print("b. Back")
        print("q. Quit")
        favFile.close()
        itemChooser(lineCount, myFavourites, selectTvShow, allResults)
    else:
        favFile.close()
        print(colors.RED + "there is no favourite tv show in the list!" + colors.END)
        print("b. Back")
        print("q. Quit")
        switchCreator("qb", "", "main_menu")
    return


def upcoming():
    returnQueue = queue.Queue()
    exceptDay = input("Enter Except Day(i.e: " + str(datetime.now().date()) + "):")
    # parser = argparse.ArgumentParser()
    # parser.add_argument('-t', '--today', help='show episode lists of today.', action='store_true', default=True)
    # parser.add_argument('-u', '--until', help='show episode lists Until the day.', action='store_true', default=True)
    # parser.add_argument('-j', '--just', help='show episode lists, just for specified Day.', action='store_true', default=True)

    # args = parser.parse_args()
    # IgnoreCase = args.ignoreCase
    try:
        exceptDay = datetime.strptime(exceptDay, '%Y-%m-%d').date()
    except:
        print(colors.RED + "Date Format Is Incorrect.Enter Date like:2012-02-18" + colors.END)
        upcoming()
    currentDay = datetime.now().date()

    if exceptDay >= currentDay:
        # Create new threads
        thread1 = threadDotCount.threadDotCount(1, "Thread-1", True)
        thread2 = threadSchedule.threadSchedule(2, "Thread-2", returnQueue, currentDay,True, 'Us', exceptDay)

        # Start new Threads
        thread1.start()
        thread2.start()

        # Kill all threads
        thread1.join()
        thread2.join()
        constants.wholeCounter = True

        # Get Response As Dictionary
        try:
            responseDict = returnQueue.get()
            print(colors.CYAN + "to view the list of episodes, enter 'row Number' and then hit ENTER.otherwise use below Capabilities." + colors.END)
            print("b. Back")
            print("q. Quit")
            itemChooser(len(responseDict), upcoming, upcomingDetails, responseDict)
        except:
            pass
    else:
        print(colors.RED + "You Enter A Decayed Time :( Try Again" + colors.END)
        upcoming()
    return

def upcomingDetails(scheduleDay):
    x = PrettyTable()
    for i, item in enumerate(scheduleDay):
        x.field_names = [i, "TvShow", "Season.No.", "Episode.No.", "AirStamp", "RunTime"]
        x.add_row([i, item.show.name, item.season_number, item.episode_number, item.airstamp, item.runtime])
    print(x)
    print(colors.CYAN + "to view more details, enter 'row Number' and then hit ENTER.otherwise use below Capabilities." + colors.END)
    print("b. Back")
    print("q. Quit")
    itemChooser(len(scheduleDay)+1, upcomingDetails, selectTvShow, scheduleDay)
    return

def whoAmI():
    print("i am nobody, please visit us on : http://www.bbs.archusers.ir!\n")
    print("b. Back")
    print("q. Quit")
    switchCreator("qb", "", "main_menu")
    return

def help():
    parser = argparse.ArgumentParser()
    parser.parse_args()
    print("this program use english letters for get into other menu(sub-menu).\nfor example, if you see: 'b. Back', you must enter b letter, "+
          "and hit enter from keyboard.")
    print("b. Back")
    print("q. Quit")
    switchCreator("qb", "", "main_menu")
    return

def quit():
    sys.exit()


def itemChooser(condition, srcFunction, destFunction, *args):
    """
    choose the item and go inside it with parameters.
    :param condition:
    :param srcFunction:
    :param destFunction:
    :param args:
    """
    flag = 0
    while flag == 0:
        mainChoice = input(" >>  ")
        if mainChoice == 'b':
            main_menu()
        elif mainChoice == 'q':
            quit()
        elif re.match("\d", mainChoice):
            try:
                if int(mainChoice) < condition and int(mainChoice) >= 0:
                    if destFunction == episodes:
                        destFunction(args[0], args[1], mainChoice)
                    elif destFunction == upcomingDetails:
                        destFunction(args[0][int(mainChoice)])
                    elif destFunction == selectTvShow:
                        if srcFunction == searchTvSeries:
                            destFunction(args[0], args[0][int(mainChoice)].externals['thetvdb'])
                        elif srcFunction == myFavourites:
                            destFunction(args[0][int(mainChoice)])
                        elif srcFunction == upcomingDetails:
                            destFunction(args[0][int(mainChoice)].show)
                else:
                    print("You Entered Wrong Number.Please Try Again Later.")
            except IndexError as e:
                print("You Entered Wrong Number.Please Try Again Later.")
        else:
            print("Invalid selection, please try again.\n")


def switchCreator(*args):

    """call the appropriate function, according to arguments pass it.

    :param args: args[0] =menu actions, args[1] =function parameters, args[2] =function name
    :return:
    """
    flag = 0
    while flag == 0:
        mainChoice = input(" >>  ")
        if mainChoice == 's' and 's' in args[0]:
            searchTvSeries()
        elif mainChoice == 'm' and 'm' in args[0]:
            myFavourites()
        elif mainChoice == 'f' and 'f' in args[0]:
            favouriteThis(args[1], args[3])
        elif mainChoice == 'd' and 'd' in args[0]:
            deleteFavourites(args[1], args[3])
        elif mainChoice == 'u' and 'u' in args[0]:
            upcoming()
        elif mainChoice == 'w' and 'w' in args[0]:
            whoAmI()
        elif mainChoice == 'h' and 'h' in args[0]:
            help()
        elif mainChoice == 'q' and 'q' in args[0]:
            quit()
        elif mainChoice == 'o' and 'o' in args[0]:
            OverView(args[1],args[3])
        elif mainChoice == 'a' and 'a' in args[0]:
            actors(args[1], args[3])
        elif mainChoice == 'z' and 'z' in args[0]:
            seasons(args[1], args[3])
        elif mainChoice == 'e' and 'e' in args[0]:
            episodes(args[1], args[3])
        elif mainChoice == 'c' and 'c' in args[0]:
            crews(args[1], args[3])
        elif mainChoice == 'i' and 'i' in args[0]:
            moreInfo(args[1], args[3])
        elif mainChoice == 'b' and 'b' in args[0]:
            if args[2] == "main_menu":
                result = main_menu()
                return result
            elif args[2] == "searchTvSeries":
                searchTvSeries(args[1])
            elif args[2] == "selectTvShow":
                selectTvShow(args[1], args[3])
            elif args[2] == "seasons":
                seasons(args[1], args[3])
        else:
            print("Invalid selection, please try again.\n")


# =======================
#    MENUS DEFINITIONS
# =======================
# Menu definition

menu_actions = {
    'main_menu': main_menu,
    's': searchTvSeries,
    'w': whoAmI,
    'h': help,
    't': selectTvShow,
    'o': OverView,
    'a': actors,
    'z': seasons,
    'e': episodes,
    'c': crews,
    'i': moreInfo,
    'm': myFavourites,
    'f': favouriteThis,
    'd': deleteFavourites,
    'u': upcoming,
    'q': quit,
}

# =======================
#      MAIN PROGRAM
# =======================
# Tv Show Samples: Game of Thrones - stranger things - dexter - lost

# Main Program
if __name__ == "__main__":
    try:
        main_menu()
    except (KeyboardInterrupt, SystemExit):
        print("You have successfully signed out!")
