import datetime
import uuid
from pyramid.security import authenticated_userid

from pyramid.view import view_config
from sqlalchemy.orm import joinedload_all
import transaction
from brewman import groupfinder
from brewman.models import DBSession
from brewman.models.auth import User

from brewman.models.messaging import Thread, Post, Tag, Subscriber
from brewman.models.tzinfoutc import get_age
from brewman.models.validation_exception import TryCatchFunction, ValidationError


@view_config(request_method='GET', route_name='message_id', renderer='brewman:templates/angular_base.mako')
@view_config(request_method='GET', route_name='message', renderer='brewman:templates/angular_base.mako')
def html(request):
    return {}


@view_config(request_method='POST', route_name='api_message', renderer='json', permission='Authenticated')
@TryCatchFunction
def save(request):
    user_id = uuid.UUID(authenticated_userid(request))
    user_name = User.by_id(user_id).name
    title = request.json_body['Title'].strip()
    if Thread.by_title(title) is not None:
        raise ValidationError('Message with same title already exists')
    thread = Thread(title=title, priority=request.json_body['Priority'], user_id=user_id)
    DBSession.add(thread)
    for item in request.json_body['Posts']:
        if 'Content' in item and item['Content'].strip() != '':
            dt = datetime.datetime.strptime(item['Date'], '%d-%b-%Y') if 'Date' in item else None
            post = Post(content=item['Content'].strip(), date=dt, user_id=user_id)
            thread.posts.append(post)
            DBSession.add(post)
    for item in request.json_body['Tags']:
        name = item.strip().title()
        tag = Tag.by_name(name)
        if tag is None:
            tag = Tag(name=name)
            DBSession.add(tag)
        thread.tags.append(tag)
    if user_name not in request.json_body['Subscribers']:
        request.json_body['Subscribers'].append(user_name)
    for item in request.json_body['Subscribers']:
        subscriber = Subscriber(user_id=User.by_name(item).id, read=item == user_name)
        thread.subscribers.append(subscriber)
        DBSession.add(subscriber)
    transaction.commit()
    return thread_info(thread.id)


@view_config(request_method='POST', route_name='api_message_id', renderer='json', permission='Authenticated')
@TryCatchFunction
def update(request):
    user_id = uuid.UUID(authenticated_userid(request))
    user_name = User.by_id(user_id).name
    super_user = 'Messages' in groupfinder(user_id, request)
    thread = Thread.by_id(uuid.UUID(request.matchdict['id']))
    public = request.json_body['Public']
    closed = request.json_body['Closed']
    if super_user or (thread.public and not public):
        thread.public = public
    if super_user or (not thread.closed and closed):
        thread.closed = closed
    thread.priority = request.json_body['Priority']

    newTags = request.json_body['Tags']
    for i in range(len(thread.tags), 0, -1):
        tag = thread.tags[i - 1]
        if tag.name not in newTags:
            thread.tags.remove(tag)
        else:
            newTags.remove(tag.name)
    for j in newTags:
        name = j.strip().title()
        tag = Tag.by_name(name)
        if tag is None:
            tag = Tag(name=name)
            DBSession.add(tag)
        thread.tags.append(tag)

    if super_user:
        posts = [p for p in request.json_body['Posts'] if p['Readonly'] == False or 'PostID' not in p]
    else:
        posts = [p for p in request.json_body['Posts'] if 'PostID' not in p]
    posts = [p for p in posts if 'Content' in p and p['Content'].strip() != '']
    for item in posts:
        if 'PostID' in item:
            post = Post.by_id(item['PostID'])
            post.content = item['Content'].strip()
            if 'Date' in item:
                post.date = datetime.datetime.strptime(item['Date'], '%d-%b-%Y')
            post.user_id = user_id
            post.creation_date = datetime.datetime.utcnow()
        else:
            dt = datetime.datetime.strptime(item['Date'], '%d-%b-%Y') if 'Date' in item else None
            post = Post(content=item['Content'].strip(), date=dt, user_id=user_id)
            thread.posts.append(post)
            DBSession.add(post)

    if user_name not in request.json_body['Subscribers']:
        request.json_body['Subscribers'].append(user_name)
    newSubscribers = request.json_body['Subscribers']
    for i in range(len(thread.subscribers), 0, -1):
        subscriber = thread.subscribers[i - 1]
        if subscriber.user.name not in newSubscribers:
            thread.subscribers.remove(subscriber)
        else:
            newSubscribers.remove(subscriber.user.name)
            subscriber.read = subscriber.user.name == user_name
    for j in newSubscribers:
        subscriber = Subscriber(user_id=User.by_name(j).id, read=j == user_name)
        thread.subscribers.append(subscriber)
        DBSession.add(subscriber)

    transaction.commit()
    return thread_info(thread.id)


@view_config(request_method='GET', route_name='api_message', renderer='json', permission='Authenticated')
def show_blank(request):
    user = User.by_id(authenticated_userid(request)).name
    return {'Title': '', 'User': user, 'Tags': [], 'Priority': 4, 'Public': False,
            'Posts': [], 'Closed': False, 'Subscribers': [user]}


@view_config(request_method='GET', route_name='api_message_id', renderer='json', permission='Authenticated')
def show_id(request):
    user_id = authenticated_userid(request) and uuid.UUID(authenticated_userid(request))
    thread = Thread.by_id(request.matchdict['id'])
    subscriber = [s for s in thread.subscribers if s.user_id == user_id]
    if len(subscriber) > 0:
        subscriber[0].read = True
    info = thread_info(thread)
    transaction.commit()
    return info


@view_config(request_method='GET', route_name='api_message', renderer='json', request_param='list')
def show_list(request):
    user_id = authenticated_userid(request) and uuid.UUID(authenticated_userid(request))
    list = Thread.query()

    type = request.params.get('type', 'open')
    if type == 'all':
        pass
    elif type == 'closed':
        list = list.filter(Thread.closed == True)
    else:
        type = 'open'
        list = list.filter(Thread.closed == False)

    if user_id is None:
        list = list.filter(Thread.public == True)
    elif 'Messages' not in groupfinder(user_id, request):
        list = list.filter(Thread.subscribers.any(Subscriber.user_id == user_id))

    list = list.order_by(Thread.priority).all()
    tags = {}
    threads = []
    for item in list:
        thread = {'ThreadID': item.id, 'Title': item.title, 'Age': get_age(item.creation_date), 'Read': False,
                  'CreationDate': item.creation_date.strftime('%d-%b-%Y %H:%M'), 'User': item.user.name,
                  'Priority': item.priority, 'Public': item.public, 'Tags': [], 'Posts': [], 'Subscribers': []}
        last_updated = item.creation_date
        for post in item.posts:
            last_updated = max(post.creation_date, last_updated)
        thread['LastUpdated'] = get_age(last_updated)

        for tag in item.tags:
            thread['Tags'].append(tag.name)
            if not tag.name in tags:
                tags[tag.name] = 1
            else:
                tags[tag.name] += 1

        for subscriber in item.subscribers:
            thread['Subscribers'].append(subscriber.user.name)
            if subscriber.user_id == user_id:
                thread['Read'] = subscriber.read
        threads.append(thread)
    return {'Tags': tags, 'Threads': threads, 'Type': type}


def thread_info(id):
    item = id if isinstance(id, Thread) else Thread.by_id(id)
    thread = {'ThreadID': item.id, 'Title': item.title, 'Closed': item.closed,
              'CreationDate': item.creation_date.strftime('%d-%b-%Y %H:%M'), 'User': item.user.name,
              'Priority': item.priority, 'Public': item.public, 'Tags': [], 'Posts': [], 'Subscribers': []}
    for tag in item.tags:
        thread['Tags'].append(tag.name)
    for subscriber in item.subscribers:
        thread['Subscribers'].append(subscriber.user.name)
    for post in item.posts:
        thread['Posts'].append({'PostID': post.id, 'Content': post.content, 'User': post.user.name,
                                'Date': post.date.strftime('%d-%b-%Y'),
                                'CreationDate': post.creation_date.strftime('%d-%b-%Y %H:%M'),
                                'Readonly': True})
    return thread


@view_config(request_method='GET', route_name='api_tag_list', renderer='json', permission='Authenticated')
def tag_list(request):
    list = Tag.query().order_by(Tag.name).all()
    tags = []
    for item in list:
        tags.append({'TagID': item.id, 'Name': item.name})
    return tags


