#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Removes Shows from On Deck.

Author: Blacktwin
Requires: requests, plexapi

 Example:
     python off_deck.py --action deck --user Steve
        - Display what shows are on Steve's On Deck

     python off_deck.py --action deck --shows "The Simpsons" Seinfeld
        - The Simpsons and Seinfeld will be removed from On Deck

     python off_deck.py --action deck --shows "The Simpsons" Seinfeld --user Steve
        - The Simpsons and Seinfeld will be removed from Steve's On Deck

     python off_deck.py --action deck --playlist "Favorite Shows!"
        - Any Show found in Favorite Shows playlist will be remove
        from On Deck

     python off_deck.py --action watch --user Steve
        - Display what shows are on Steve's Continue Watching

     python off_deck.py --action watch --shows "The Simpsons" Seinfeld
        - The Simpsons and Seinfeld will be removed from Continue Watching

     python off_deck.py --action watch --shows "The Simpsons" Seinfeld --user Steve
        - The Simpsons and Seinfeld will be removed from Steve's Continue Watching

     python off_deck.py --action watch --playlist "Favorite Shows!"
        - Any Show found in Favorite Shows playlist will be remove
        from Continue Watching

!!!NOTICE!!!

 * This script should be used for Shows that you have already watched and
don't want showing up on your On Deck.

 * For episodes of show already watched the view count will be reset back to it
original.

 * For episodes of show not watched the view count will be set to 1.

"""

import requests
import argparse
import datetime
from plexapi.server import PlexServer, CONFIG

PLEX_URL = ''
PLEX_TOKEN = ''

if not PLEX_URL:
    PLEX_URL = CONFIG.data['auth'].get('server_baseurl', '')

if not PLEX_TOKEN:
    PLEX_TOKEN = CONFIG.data['auth'].get('server_token', '')

sess = requests.Session()
# Ignore verifying the SSL certificate
sess.verify = False  # '/path/to/certfile'
# If verify is set to a path to a directory,
# the directory must have been processed using the c_rehash utility supplied
# with OpenSSL.
if sess.verify is False:
    # Disable the warning that the request is insecure, we know that...
    import urllib3
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

plex = PlexServer(PLEX_URL, PLEX_TOKEN, session=sess)
account = plex.myPlexAccount()


def actions():
    """
    deck - Items that are On Deck
    watch - Items that are Continue Watching
    """
    return ['deck', 'watch']


def get_con_watch(server, off_deck=None):
    """

    Parameters
    ----------
    server : class
        User's server to pull On Deck list
    Returns
    -------
    dict
        Show, episodes, and episodes view count

    """
    con_watch = []
    for item in server.library.onDeck():
        if off_deck and item.type == 'episode' and item.viewOffset > 0:
            if item.grandparentTitle in off_deck:
                print('Removing {}: S{:02}E{:02} {} from Continue Watching '
                      'by marking watched.'.format(
                          item.grandparentTitle.encode('UTF-8'),
                          int(item.parentIndex), int(item.index),
                          item.title.encode('UTF-8')))
                item.markWatched()
        else:
            if item.type == 'episode' and item.viewOffset > 0:
                con_watch.append(item)

    if con_watch:
        print('The following shows are marked Continue Watching:')
        for item in con_watch:
            offset = datetime.timedelta(milliseconds=item.viewOffset)
            print('{}: S{:02}E{:02} {} ({})'.format(
                item.grandparentTitle.encode('UTF-8'),
                int(item.parentIndex), int(item.index),
                item.title.encode('UTF-8'), offset))


def get_on_deck(server, off_deck=None):
    """

    Parameters
    ----------
    server : class
        User's server to pull On Deck list
    off_deck : list
        List of Shows to remove from On Deck

    Returns
    -------
    dict
        Show, episodes, and episodes view count

    """
    watched_statuses = {}
    on_deck = []
    for item in server.library.onDeck():
        if off_deck and item.type == 'episode' and item.viewOffset == 0:
            if item.grandparentTitle in off_deck:
                grandparent = server.fetchItem(item.grandparentRatingKey)
                watched_statuses['grandparent'] = grandparent
                watched_statuses['episodes'] = []
                for episode in grandparent.episodes():
                    watched_statuses['episodes'].append({
                        'object': episode,
                        'viewCount': episode.viewCount})
        else:
            if item.type == 'episode':
                on_deck.append(item)

    if on_deck:
        watched_statuses['on_deck'] = on_deck
    return watched_statuses


if __name__ == '__main__':

    parser = argparse.ArgumentParser(description="Remove items from On Deck.",
                                     formatter_class=argparse.RawTextHelpFormatter)
    parser.add_argument('--shows', nargs='+',
                        help='Shows to be removed from On Deck.')
    parser.add_argument('--user', nargs='?',
                        help='User whose On Deck will be modified.')
    parser.add_argument('--playlist', nargs='?',
                        help='Shows in playlist to be removed from On Deck')
    parser.add_argument('--action', required=True, choices=actions(),
                        help='Action selector.'
                             '{}'.format(actions.__doc__))

    opts = parser.parse_args()

    ep_list = []
    to_remove = ''

    if opts.user:
        user_acct = account.user(opts.user)
        plex_server = PlexServer(PLEX_URL, user_acct.get_token(plex.machineIdentifier))
    else:
        plex_server = plex

    if opts.shows and not opts.playlist:
        to_remove = opts.shows
    elif not opts.shows and opts.playlist:
        to_remove = [x.grandparentTitle for x in plex_server.playlist(opts.playlist).items()]

    if opts.action == 'deck':
        if not to_remove:
            print('The following shows are On Deck...')
            on_deck = get_on_deck(plex_server)['on_deck']
            for item in on_deck:
                print('{}: S{:02}E{:02} {}'.format(
                    item.grandparentTitle.encode('UTF-8'),
                    int(item.parentIndex), int(item.index),
                    item.title.encode('UTF-8')))

        else:
            print('Finding listed shows On Deck...')
            while True:
                off_deck = get_on_deck(plex_server, to_remove)
                if off_deck:
                    ep_list += off_deck['episodes']
                    print('Marking {} Unwatched'.format(off_deck['grandparent']
                                                        .title.encode('UTF-8')))
                    off_deck['grandparent'].markUnwatched()
                else:
                    break

            print('Resetting watch counts...')
            for item in ep_list:
                print('Resetting view count for {}: S{:02}E{:02} {}'.format(
                    item['object'].grandparentTitle.encode('UTF-8'),
                    int(item['object'].parentIndex), int(item['object'].index),
                    item['object'].title.encode('UTF-8')))
                # if viewCount was 0 then make 1 so as not to return to On Deck.
                for _ in range(item['viewCount'] if item['viewCount'] != 0 else 1):
                    item['object'].markWatched()

    elif opts.action == 'watch':
        print('Finding shows marked Continue Watching...')
        get_con_watch(plex_server, to_remove)