from .. import app
from .. import queue
from .. import hooks
from ..models import Post
from bs4 import BeautifulSoup
import urllib
import re
import requests


def register():
    hooks.register('post-saved', send_webmentions)


def send_webmentions(post, args):
    if args.get('action') in ('save_draft', 'publish_quietly'):
        app.logger.debug('skipping webmentions for {}'.format(post.id))
        return

    try:
        app.logger.debug("queueing webmentions for {}".format(post.id))
        queue.enqueue(do_send_webmentions, post.id)
        return True, 'Success'

    except Exception as e:
        app.logger.exception('sending webmentions')
        return False, "Exception while sending webmention: {}"\
            .format(e)


def do_send_webmentions(post_id):
    app.logger.debug("sending mentions for {}".format(post_id))
    post = Post.load_by_id(post_id)
    return handle_new_or_edit(post)


def get_source_url(post):
    return post.permalink


def get_target_urls(post):
    target_urls = []
    # send mentions to 'in_reply_to' as well as all linked urls
    target_urls += post.in_reply_to
    target_urls += post.repost_of
    target_urls += post.like_of

    app.logger.debug("search post content {}".format(post.content_html))

    soup = BeautifulSoup(post.content_html)
    for link in soup.find_all('a'):
        link_target = link.get('href')
        if link_target:
            app.logger.debug("found link {} with href {}"
                             .format(link, link_target))
            target_urls.append(link_target.strip())

    return target_urls


def get_response(url):
    if url in get_response.cached_responses:
        return get_response.cached_responses[url]
    response = requests.get(url)
    get_response.cached_responses[url] = response
    return response

get_response.cached_responses = {}


def handle_new_or_edit(post):
    target_urls = get_target_urls(post)
    app.logger.debug("Sending webmentions to these urls {}"
                     .format(" ; ".join(target_urls)))
    results = []
    for target_url in target_urls:
        results.append(send_mention(post, target_url))
    return results


def send_mention(post, target_url):
    app.logger.debug("Looking for webmention endpoint on %s",
                     target_url)

    success, explanation = check_content_type_and_size(target_url)
    if success:
        if supports_webmention(target_url):
            app.logger.debug("Site supports webmention")
            success, explanation = send_webmention(post, target_url)

        elif supports_pingback(target_url):
            app.logger.debug("Site supports pingback")
            success, explanation = send_pingback(post, target_url)
            app.logger.debug("Sending pingback successful: %s", success)

        else:
            app.logger.debug("Site does not support mentions")
            success = False
            explanation = 'Site does not support webmentions or pingbacks'

    return {'target': target_url,
            'success': success,
            'explanation': explanation}


def check_content_type_and_size(target_url):
    request = urllib.request.Request(
        target_url, headers={'User-Agent': 'kylewm.com'})
    metadata = urllib.request.urlopen(request).info()
    if not metadata:
        return False, "Could not retrieve metadata for url {}".format(
            target_url)

    content_type = metadata.get_content_maintype()
    content_length = metadata.get('Content-Length')

    if content_type and content_type != 'text':
        return False, "Target content type '{}' is not 'text'".format(
            content_type)

    if content_length and int(content_length) > 2097152:
        return False, "Target content length {} is too large".format(
            content_length)

    return True, None


def supports_webmention(target_url):
    return find_webmention_endpoint(target_url) is not None


def find_webmention_endpoint(target_url):
    app.logger.debug("looking for webmention endpoint in %s", target_url)
    response = get_response(target_url)
    app.logger.debug("looking for webmention endpoint in headers and body")
    endpoint = (find_webmention_endpoint_in_headers(response.headers)