# Author: Marvin Pinto <me@marvinp.ca>
# Author: Dennis Lutter <lad1337@gmail.com>
# Author: Aaron Bieber <deftly@gmail.com>
#
# This file is part of SickGear.
#
# SickGear is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SickGear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SickGear.  If not, see <http://www.gnu.org/licenses/>.

import socket
import time

from .generic import Notifier
import sickgear

from _23 import decode_bytes, decode_str, urlencode
# noinspection PyUnresolvedReferences
from six.moves import urllib

API_URL = 'https://api.pushover.net/1/messages.json'
DEVICE_URL = 'https://api.pushover.net/1/users/validate.json'


class PushoverNotifier(Notifier):

    def get_devices(self, user_key=None, api_key=None):

        user_key = self._choose(user_key, sickgear.PUSHOVER_USERKEY)
        api_key = self._choose(api_key, sickgear.PUSHOVER_APIKEY)

        data = urlencode(dict(token=api_key, user=user_key))

        # get devices from pushover
        result = False
        try:
            req = urllib.request.Request(DEVICE_URL)
            http_response_obj = urllib.request.urlopen(req)  # PY2 http_response_obj has no `with` context manager
            if http_response_obj:
                result = http_response_obj.read()
                http_response_obj.close()
        except (urllib.error.URLError, socket.timeout):
            pass

        return ('{}', result)[bool(result)]

    def _notify(self, title, body, user_key=None, api_key=None, priority=None, device=None, sound=None, **kwargs):
        """
        Sends a pushover notification to the address provided

        title: The title of the message
        msg: The message to send (unicode)
        user_key: The pushover user id to send the message to (or to subscribe with)

        returns: True if the message succeeded, False otherwise
        """
        user_key = self._choose(user_key, sickgear.PUSHOVER_USERKEY)
        api_key = self._choose(api_key, sickgear.PUSHOVER_APIKEY)
        priority = self._choose(priority, sickgear.PUSHOVER_PRIORITY)
        device = self._choose(device, sickgear.PUSHOVER_DEVICE)
        sound = self._choose(sound, sickgear.PUSHOVER_SOUND)

        # build up the URL and parameters
        params = dict(title=title, message=decode_str(body.strip()), user=user_key, timestamp=int(time.time()))
        if api_key:
            params.update(token=api_key)
        if priority:
            params.update(priority=priority)
        if not device:
            params.update(device=device)
        if not sound:
            params.update(sound=sound)

        # send the request to pushover
        result = None
        try:
            req = urllib.request.Request(API_URL)
            # PY2 http_response_obj has no `with` context manager
            http_response_obj = urllib.request.urlopen(req, decode_bytes(urlencode(params)))
            http_response_obj.close()

        except urllib.error.HTTPError as e:
            # HTTP status 404 if the provided email address isn't a Pushover user.
            if 404 == e.code:
                result = 'Username is wrong/not a Pushover email. Pushover will send an email to it'
                self._log_warning(result)

            # For HTTP status code 401's, it is because you are passing in either an invalid token,
            # or the user has not added your service.
            elif 401 == e.code:

                # HTTP status 401 if the user doesn't have the service added
                subscribe_note = self._notify(title, body, user_key)
                if subscribe_note:
                    self._log_debug('Subscription sent')
                    # return True
                else:
                    result = 'Subscription could not be sent'
                    self._log_error(result)
            else:
                # If you receive an HTTP status code of 400, it is because you failed to send the proper parameters
                if 400 == e.code:
                    result = 'Wrong data sent to Pushover'

                # If you receive a HTTP status code of 429,
                #  it is because the message limit has been reached (free limit is 7,500)
                elif 429 == e.code:
                    result = 'API message limit reached - try a different API key'

                # If you receive a HTTP status code of 500, service is unavailable
                elif 500 == e.code:
                    result = 'Unable to connect to API, service unavailable'

                self._log_error(result)

        return self._choose((True, 'Failed to send notification: %s' % result)[bool(result)], not bool(result))


notifier = PushoverNotifier