import logging
import requests
from typing import Any, Dict, List, Tuple, Optional
from requests.exceptions import ConnectionError

USERS_LIST_URL = 'https://api.flock.co/v1/roster.listContacts'
SEND_MESSAGE_URL = 'https://api.flock.co/v1/chat.sendMessage'

help_message = '''
You can send messages to any Flock user associated with your account from Zulip.
*Syntax*: **@botname to: message** where `to` is **firstName** of recipient.
'''

# Matches the recipient name provided by user with list of users in his contacts.
# If matches, returns the matched User's ID
def find_recipient_id(users: List[Any], recipient_name: str) -> str:
    for user in users:
        if recipient_name == user['firstName']:
            return user['id']

# Make request to given flock URL and return a two-element tuple
# whose left-hand value contains JSON body of response (or None if request failed)
# and whose right-hand value contains an error message (or None if request succeeded)
def make_flock_request(url: str, params: Dict[str, str]) -> Tuple[Any, str]:
    try:
        res = requests.get(url, params=params)
        return (res.json(), None)
    except ConnectionError as e:
        logging.exception(str(e))
        error = "Uh-Oh, couldn't process the request \
right now.\nPlease try again later"
        return (None, error)

# Returns two-element tuple whose left-hand value contains recipient
# user's ID (or None if it was not found) and right-hand value contains
# an error message (or None if recipient user's ID was found)
def get_recipient_id(recipient_name: str, config: Dict[str, str]) -> Tuple[Optional[str], Optional[str]]:
    token = config['token']
    payload = {
        'token': token
    }
    users, error = make_flock_request(USERS_LIST_URL, payload)
    if users is None:
        return (None, error)

    recipient_id = find_recipient_id(users, recipient_name)
    if recipient_id is None:
        error = "No user found. Make sure you typed it correctly."
        return (None, error)
    else:
        return (recipient_id, None)

# This handles the message sending work.
def get_flock_response(content: str, config: Dict[str, str]) -> str:
    token = config['token']
    content_pieces = content.split(':')
    recipient_name = content_pieces[0].strip()
    message = content_pieces[1].strip()

    recipient_id, error = get_recipient_id(recipient_name, config)
    if recipient_id is None:
        return error

    if len(str(recipient_id)) > 30:
        return "Found user is invalid."

    payload = {
        'to': recipient_id,
        'text': message,
        'token': token
    }
    res, error = make_flock_request(SEND_MESSAGE_URL, payload)
    if res is None:
        return error

    if "uid" in res:
        return "Message sent."
    else:
        return "Message sending failed :slightly_frowning_face:. Please try again."

def get_flock_bot_response(content: str, config: Dict[str, str]) -> None:
    content = content.strip()
    if content == '' or content == 'help':
        return help_message
    else:
        result = get_flock_response(content, config)
        return result

class FlockHandler:
    '''
    This is flock bot. Now you can send messages to any of your
    flock user without having to leave Zulip.
    '''

    def initialize(self, bot_handler: Any) -> None:
        self.config_info = bot_handler.get_config_info('flock')

    def usage(self) -> str:
        return '''Hello from Flock Bot. You can send messages to any Flock user
right from Zulip.'''

    def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None:
        response = get_flock_bot_response(message['content'], self.config_info)
        bot_handler.send_reply(message, response)

handler_class = FlockHandler
