import json
import re

from response.core.models.incident import Incident
from response.slack.models import HeadlinePost, CommsChannel, UserStats, PinnedMessage

from response.slack.decorators import slack_event, handle_incident_command, handle_keywords


def decode_app_mention(payload):
    """
    Convenience function for dealing with the common pattern for app mention slack events.

    Example: @bot create Something's happened
    Extracts:  slack_id -> "@bot"
               command  -> "create"
               extra    -> "Something's happened"

    @param payload an app mention string of the form @bot create Something's happened
    @return: three variables split by bot, action and extra text
    """
    incident_command_re = re.compile(r"(<@[A-Z0-9]+>)\s+(\w+)\s*(.*)")
    m = incident_command_re.match(payload.strip())

    if not m or len(m.groups()) != 3:
        raise ValueError(
            f'Could not parse app mention payload "{payload}" into "@<bot> <command> <text>"')

    slack_id = m.group(1)
    command = m.group(2)
    extra = m.group(3)

    return slack_id, command, extra


@slack_event('app_mention')
def handle_app_mention(incident: Incident, payload: json):
    """
    Events of type `app_mention` are of the form `@incident some text here`
    We handle all of these as incident_commands
    """
    _, command_name, message = decode_app_mention(payload['text'])

    channel_id = payload['channel']
    user_id = payload['user']
    thread_ts = payload['ts']

    handle_incident_command(command_name, message, thread_ts, channel_id, user_id)


@slack_event('message')
def handle_keyword_detection(incident: Incident, payload: json):
    handle_keywords(payload)


@slack_event('message')
def update_user_stats(incident: Incident, payload: json):
     # message with a user field are messages coming from users.
    if 'user' in payload:
        user_id = payload['user']
        UserStats.increment_message_count(incident, user_id)


@slack_event('pin_added')
def handle_pin_added(incident, payload):
    """
    Handler for pin added events

    @param payload a slack pin_added event
    """
    pinned_message = payload['item']['message']

    if 'user' in pinned_message:
        author_id = pinned_message['user']
        message_ts = pinned_message['ts']
        text = pinned_message['text']
        PinnedMessage.objects.add_pin(incident, message_ts, author_id, text)


@slack_event('pin_removed')
def handle_pin_removed(incident, payload):
    """
    Handler for pin removed events

    @param payload a slack pin_removed event
    """

    pinned_message = payload['item']['message']
    message_ts = pinned_message['ts']

    PinnedMessage.objects.remove_pin(incident, message_ts)
