from __future__ import unicode_literals, division, absolute_import
from builtins import *  # noqa pylint: disable=unused-import, redefined-builtin
from future.moves.urllib.parse import urlparse

import logging
import math

from requests import RequestException

from flexget import plugin
from flexget.event import event
from flexget.entry import Entry

log = logging.getLogger('next_sonarr_episodes')


class NextSonarrEpisodes(object):
    """
    This plugin return the 1st missing episode of every show configures in Sonarr.
    This can be used with the discover plugin or set_series_begin plugin to
    get the relevant data from Sonarr.

    Syntax:

    next_sonarr_episodes:
      base_url=<value> (Required)
      port=<value> (Default is 80)
      api_key=<value> (Required)
      include_ended=<yes|no> (Default is yes)
      only_monitored=<yes|no> (Default is yes)
      page_size=<value> (Default is 50)

    Page size determines the amount of results per each API call.
    Higher value means a bigger response. Lower value means more calls.
    Should be changed if there are performance issues.


    Usage: (Example with discover)

    discover_from_sonarr_task:
      discover:
        what:
          - next_sonarr_episodes:
              base_url: '{? credentials.sonarr.url ?}'
              port: 8989
              api_key: '{? credentials.sonarr.api_key ?}'
              include_ended: false
        from:
          - kat:
              verified: yes
      all_series: yes
      download: c:\bla\

    Usage: (Example with set_series_begin)

    set-series-begin-from-sonarr:
      next_sonarr_episodes:
        base_url: '{{ secrets.credentials.sonarr.url }}'
        port: 8989
        api_key: '{{ secrets.credentials.sonarr.api_key }}'
        include_ended: false
      accept_all: yes
      set_series_begin: yes
    """
    schema = {
        'type': 'object',
        'properties': {
            'base_url': {'type': 'string'},
            'port': {'type': 'number', 'default': 80},
            'api_key': {'type': 'string'},
            'include_ended': {'type': 'boolean', 'default': True},
            'only_monitored': {'type': 'boolean', 'default': True},
            'page_size': {'type': 'number', 'default': 50}
        },
        'required': ['api_key', 'base_url'],
        'additionalProperties': False
    }

    # Function that gets a page number and page size and returns the responding result json
    def get_page(self, task, config, page_number):
        parsedurl = urlparse(config.get('base_url'))
        url = '{}://{}:{}{}/api/wanted/missing?page={}&pageSize={}&sortKey=series.title&sortdir=asc'.format(
            parsedurl.scheme, parsedurl.netloc, config.get('port'), parsedurl.path, page_number,
            config.get('page_size'))
        headers = {'X-Api-Key': config['api_key']}
        try:
            json = task.requests.get(url, headers=headers).json()
        except RequestException as e:
            raise plugin.PluginError(
                'Unable to connect to Sonarr at {}://{}:{}{}. Error: {}'.format(parsedurl.scheme, parsedurl.netloc,
                                                                                config.get('port'), parsedurl.path, e))
        return json

    def on_task_input(self, task, config):
        json = self.get_page(task, config, 1)
        entries = []
        pages = int(math.ceil(json['totalRecords'] / config.get('page_size')))  # Sets number of requested pages
        current_series_id = 0  # Initializes current series parameter
        for page in range(1, pages + 1):
            json = self.get_page(task, config, page)
            for record in json['records']:
                # Verifies that we only get the first missing episode from a series
                if current_series_id != record['seriesId']:
                    current_series_id = record['seriesId']
                    season = record['seasonNumber']
                    episode = record['episodeNumber']
                    entry = Entry(url='',
                                  series_name=record['series']['title'],
                                  series_season=season,
                                  series_episode=episode,
                                  series_id='S%02dE%02d' % (season, episode),
                                  tvdb_id=record['series'].get('tvdbId'),
                                  tvrage_id=record['series'].get('tvRageId'),
                                  tvmaze_id=record['series'].get('tvMazeId'),
                                  title=record['series']['title'] + ' ' + 'S%02dE%02d' % (season, episode))
                    if entry.isvalid():
                        entries.append(entry)
                    else:
                        log.error('Invalid entry created? {}'.format(entry))
                    # Test mode logging
                    if entry and task.options.test:
                        log.verbose("Test mode. Entry includes:")
                        for key, value in list(entry.items()):
                            log.verbose('     {}: {}'.format(key.capitalize(), value))
        return entries


@event('plugin.register')
def register_plugin():
    plugin.register(NextSonarrEpisodes, 'next_sonarr_episodes', api_ver=2)
