# Author: Braedy Kuzma

from django.http import HttpResponse, JsonResponse, HttpResponseForbidden
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.decorators.http import require_POST, require_GET
from django.views import generic
from .models import Post, Category, Comment, CanSee, Author, Follow, FriendRequest
from django.contrib.auth.models import User
from django.db.models import Q
from .forms import PostForm, CommentForm
import base64
import uuid
import itertools
from django.views.generic.edit import CreateView
from rest.authUtils import createBasicAuthToken, parseBasicAuthToken, \
                           getRemoteCredentials
from rest.models import RemoteCredentials
from rest.serializers import PostSerializer, CommentSerializer, \
                             FollowSerializer, AuthorSerializer
from django.utils.dateparse import parse_datetime
from urllib.parse import urlsplit, urlunsplit
import requests
from rest.verifyUtils import NotFound, RequestExists
import datetime
import dateutil.parser
from requests.exceptions import ChunkedEncodingError


def postSortKey(postDict):
    return parse_datetime(postDict['published'])

def getFriends(authorID):
    friends = []
    try:
        #Check if author is local

        #AuthorTest checks if that query breaks, because if so that goes to the DNE except
        authorTest = Author.objects.get(id=authorID)
        #If it hasn't broken yet, just check if local friends.
        following = Follow.objects \
                               .filter(author=authorID) \
                               .values_list('friend', flat=True)
        for author in following:
            try:
                #Check if author is local
                #AuthorTest checks if that query breaks, because if so that goes to the DNE except
                authorTest = Author.objects.get(id=author)

                #If it hasn't broken yet, just check they follow you locally
                following2 = Follow.objects \
                                       .filter(author=author) \
                                       .values_list('friend', flat=True)
                if authorID in following2:
                    friends.append(author)

            except Author.DoesNotExist:
                host2 = getRemoteCredentials(author)
                following2 = []
                if not host2:
                    #Might have friends with a server we don't have access to.
                    continue
                r2 = requests.get(author+ 'friends/',
                                  data={'query':'friends'},
                                  auth=(host2.username, host2.password))
                if r2.status_code == 200:
                    following2 = r2.json()['authors']
                    if authorID in following2:
                        friends.append(author)


    except Author.DoesNotExist:
        #Huzzah, something broke. Most likely, this means that the author is remote
        following = []
        host = getRemoteCredentials(authorID)
        if not host:
            return friends

        r1 = requests.get(authorID+ 'friends/',
                          data={'query':'friends'},
                          auth=(host.username, host.password))
        if r1.status_code == 200:
            following = r1.json()['authors']

            for user in following:
                try:
                    #Check if author is local
                    #AuthorTest checks if that query breaks, because if so that goes to the DNE except
                    authorTest = Author.objects.get(id=user)

                    #If it hasn't broken yet, just check if local friends.
                    following2 = Follow.objects \
                                           .filter(author=user) \
                                           .values_list('friend', flat=True)
                    if authorID in following2:
                        friends.append(user)


                except Author.DoesNotExist:
                    host2 = getRemoteCredentials(user)
                    following2 = []

                    if not host2:
                        continue
                    r2 = requests.get(user+ 'friends/',
                                      data={'query':'friends'},
                                      auth=(host2.username, host2.password))
                    if r2.status_code == 200:
                        following2 = r2.json()['authors']
                        if authorID in following2:
                            friends.append(user)

    return friends

class StreamView(LoginRequiredMixin, generic.ListView):
    login_url = 'login'
    template_name = 'dashboard.html'
    context_object_name = 'latest_post_list'
    def get_queryset(self):
        # Return posts that are visible to everyone (Public, this server only,
        # self posted. Remove unlisted unless you are the creator of post)

        localVisible = Post.objects.filter(
            ((Q(visibility='PUBLIC') | Q(visibility='SERVERONLY'))\
             & Q(unlisted=False)) | Q(author=self.request.user.author)
        )


        #list of all remote creditials we know about.
        #have host, username, password
        #does not contain our own server
        allRemotePosts = []
        hosts = RemoteCredentials.objects.all()
        for host in hosts:
            print('Getting from', host.host)
            # Technically, author/posts is all posts and posts/ is only PUBLIC
            # Will everyone follow that? who knows....
            try:
                r = requests.get(host.host + 'author/posts/',
                                 data={'query':'posts'},
                                 auth=(host.username, host.password))
                if r.status_code != 200:
                    r = requests.get(host.host + 'posts/',
                                     data={'query':'posts'},
                                     auth=(host.username, host.password))
                    if r.status_code != 200:
                        print('Error {} connecting while getting posts: {}'
                              .format(r.status_code, host.host))
                        print('Got response: {}'.format(r.text))
                        continue
            except ChunkedEncodingError as e:
                print('{} got chunked encoding error...'.format(host.host))
                print(e)
                continue

            # Hacky things to make us work with remotes that follow the spec
            # "closely"
            posts = r.json()['posts']
            for post in posts:
                try:
                    uuid.UUID(post['id'])
                # If it fails it means it's (probably) a url
                except ValueError:
                    pass
                # If it succeeded we want to overwrite it with the url
                else:
                    origin = post['origin']
                    if origin[-1] != '/':
                        origin += '/'
                    post['id'] = origin
            allRemotePosts += posts


        #get local authors who follow you
        localFollowers = Follow.objects \
                               .filter(friend=self.request.user.author.id) \
                               .values_list('author', flat=True)
        #Of your local follwers, get those that you follow back, the "friends"

        localFriends = Follow.objects \
                             .filter(author=self.request.user.author.id,friend__in=localFollowers) \
                             .values_list('friend', flat=True)
        # Get posts marked FRIENDS visibility whose authors consider this author
        # a friend

        localFriendsPosts = Post.objects\
                           .filter(visibility='FRIENDS', author__in=localFriends,
                                     unlisted=False)