"""app.bsky.feed.* XRPC methods."""
import json
import logging
import re

from granary import bluesky, microformats2
import mf2util
from oauth_dropins.webutil import util
from oauth_dropins.webutil.util import json_loads

from app import xrpc_server
from models import Object

logger = logging.getLogger(__name__)


@xrpc_server.method('app.bsky.feed.getAuthorFeed')
def getAuthorFeed(input, author=None, limit=None, before=None):
    """
    lexicons/app/bsky/feed/getAuthorFeed.json, feedViewPost.json
    """
    if not author or not re.match(util.DOMAIN_RE, author):
        raise ValueError(f'{author} is not a domain')

    url = f'https://{author}/'
    mf2 = util.fetch_mf2(url, gateway=True)
    logger.info(f'Got mf2: {json.dumps(mf2, indent=2)}')

    feed_author = mf2util.find_author(mf2, source_url=url, fetch_mf2_func=util.fetch_mf2)
    if feed_author:
        logger.info(f'Authorship found: {feed_author}')
        actor = {
            'url': feed_author.get('url') or url,
            'displayName': feed_author.get('name'),
            'image': {'url': feed_author.get('photo')},
        }
    else:
        logger.info(f'No authorship result on {url} ; generated {feed_author}')
        actor = {
            'url': url,
            'displayName': author,
        }

    activities = microformats2.json_to_activities(mf2)
    # default actor to feed author
    for a in activities:
        a.setdefault('actor', actor)
    logger.info(f'AS1 activities: {json.dumps(activities, indent=2)}')

    return {'feed': [bluesky.from_as1(a) for a in activities]}


@xrpc_server.method('app.bsky.feed.getPostThread')
def getPostThread(input, uri=None, depth=None):
    """
    lexicons/app/bsky/feed/getPostThread.json
    """
    if not uri:
        raise ValueError('Missing uri')

    mf2 = util.fetch_mf2(uri, gateway=True)
    logger.info(f'Got mf2: {json.dumps(mf2, indent=2)}')

    entry = mf2util.find_first_entry(mf2, ['h-entry'])
    logger.info(f'Entry: {json.dumps(entry, indent=2)}')
    if not entry:
        raise ValueError(f"No h-entry on {uri}")

    obj = microformats2.json_to_object(entry)
    logger.info(f'AS1: {json.dumps(obj, indent=2)}')

    return {
        'thread': {
            '$type': 'app.bsky.feed.getPostThread#threadViewPost',
            'post': bluesky.from_as1(obj)['post'],
            'replies': [{
                '$type': 'app.bsky.feed.getPostThread#threadViewPost',
                'post': bluesky.from_as1(reply)['post'],
            } for reply in obj.get('replies', {}).get('items', [])],
        },
    }


# TODO
# what's the mf2 for repost children of an h-entry? u-repost, like u-comment?
# nothing about markup on https://indieweb.org/reposts
# based on https://indieweb.org/comments-display , it would be u-repost
# @xrpc_server.method('app.bsky.feed.getRepostedBy')
# def getRepostedBy(input, uri=None, cid=None, limit=None, before=None):
#     """
#     lexicons/app/bsky/feed/getRepostedBy.json
#     """
#     mf2 = util.fetch_mf2(uri, gateway=True)
#     logger.info(f'Got mf2: {json.dumps(mf2, indent=2)}')

#     entry = mf2util.find_first_entry(mf2, ['h-entry'])
#     logger.info(f'Entry: {json.dumps(entry, indent=2)}')
#     if not entry:
#         raise ValueError(f"No h-entry on {uri}")

#     obj = microformats2.json_to_object(entry)
#     logger.info(f'AS1: {json.dumps(obj, indent=2)}')

#     return {
#         'uri': 'http://orig/post',
#         'repostBy': [{
#             '$type': 'app.bsky.feed.getRepostedBy#repostedBy',
#             'did': 'did:web:eve.net',
#             'declaration': {
#                 '$type': 'app.bsky.system.declRef',
#                 'cid': 'TODO',
#                 'actorType': 'app.bsky.system.actorUser',
#             },
#             'handle': 'eve.net',
#             'displayName': 'Eve',
#             'indexedAt': '2022-01-02T03:04:05+00:00',
#         }],
#     }


# TODO: cursor
@xrpc_server.method('app.bsky.feed.getTimeline')
def getTimeline(input, algorithm=None, limit=50, before=None):
    """
    lexicons/app/bsky/feed/getTimeline.json
    """
    # TODO: how to get authed user?
    user = 'foo.com'

    # TODO: de-dupe with pages.feed()
    logger.info(f'Fetching {limit} objects for {user}')
    objects, _, _ = Object.query(
        Object.domains == user, Object.labels == 'feed'
        ).order(-Object.created
        ).fetch_page(limit)

    return {'feed': [bluesky.from_as1(json_loads(obj.as1)) for obj in objects]}


# TODO: use likes as votes?
@xrpc_server.method('app.bsky.feed.getVotes')
def getVotes(input, uri=None, direction=None, cid=None, limit=None, before=None):
    """
    lexicons/app/bsky/feed/getVotes.json
    """
    return {
        'uri': uri,
        'votes': [],
    }
