import logging
from collections import deque

from taggit.models import Tag

from django.conf import settings
from django.contrib import messages
from django.http import HttpResponse, Http404
from django.shortcuts import render
from django.template.loader import render_to_string

from authentications.decorators import authenticated_user
from documents.api import get_pad_link
from documents.etherpadlib import add_ep_cookie
from members.models import Member, JobMember
from .forms import PostSearchForm
from .models import Event, FetMeeting, FileUpload, Post
from .utils import render_to_pdf


logger = logging.getLogger(__name__)


def index(request):
    posts = None
    taglist = None

    compact_view = None
    fet_meeting_only = None

    public_only = not request.user.is_authenticated

    if request.method == "POST":
        if "btn_input" in request.POST:
            form = PostSearchForm(request.POST)

            if "compact_view" in request.POST.getlist("checkbox"):
                compact_view = True

            if "fet_meeting_only" in request.POST.getlist("checkbox"):
                fet_meeting_only = True

            if form.is_valid():
                month = form.cleaned_data["month"]
                year = form.cleaned_data["year"]

                if month == "":
                    month = None

                if year == "":
                    year = None

                if not year and month:
                    messages.info(
                        request, "Es kann nicht nur nach einem Monat gesucht werden."
                    )

                posts = Post.objects.date_filtered_list(
                    public_only,
                    year,
                    month,
                    fet_meeting_only,
                )
    else:
        form = PostSearchForm()
        posts = Post.objects.date_sorted_list(public_only)

    if posts:
        taglist = map(lambda post: post.tags, posts)

    context = {
        "formset": form,
        "compact_view": compact_view,
        "fet_meeting_only": fet_meeting_only,
        "posts": posts,
        "tags_list": taglist,
    }

    return render(request, "posts/index.html", context)


def calendar(request):
    """
    ICS-calendar for outlook, google calender,...
    """
    # publish all events independent of authenticated user
    events = Event.all_events.published(False)

    context = {
        "events": events,
    }

    return render(
        request, "posts/fet_calendar.ics", context, content_type="text/calendar"
    )


def tags(request, tag=""):
    public_only = not request.user.is_authenticated

    posts = Post.objects.published(public_only).filter(tags__name=tag)
    featured_post = Post.objects.published(public_only).filter(slug=tag).first()

    job_members = JobMember.active_member.get_all_by_slug(slug=tag)

    author_image = None
    if featured_post:
        post_author = Member.all_members.filter(nickname=featured_post.author).first()

        if post_author:
            author_image = post_author.image["avatar"].url

    context = {
        "posts": posts,
        "author_image": author_image,
        "featured_post": featured_post,
        "job_members": job_members,
        "tags_list": None,
    }

    return render(request, "posts/tag.html", context)


def __get_post_object(id=None, public=True):
    post = None

    try:
        if id.isdigit() or id is int:
            post = Post.objects.published(public).get(id=int(id))
        elif id != "" and id is not None:
            post = Post.objects.published(public).get(slug=id)
    except Exception:
        logger.info("Wrong id '{}'".format(id))
        raise Http404("wrong post id")

    return post


def show(request, id=None):
    public_only = not request.user.is_authenticated
    post = __get_post_object(id, public_only)

    # files
    files = FileUpload.objects.filter(post=post)

    # author
    author = None
    author_image = None
    post_author = Member.all_members.filter(username=post.author).first()
    if post_author:
        author = post_author
        author_image = post_author.image["avatar"].url

    # etherpad links for agenda and protocol
    ep_agenda_link = "#"
    ep_protocol_link = "#"
    # set filename for pdf, not a nice solution
    filename_agenda = None
    filename_protocol = None

    if post.has_agenda:
        ep_agenda_link = get_pad_link(post.agenda_key)

        if ep_agenda_link != "#":
            filename_agenda = post.slug + "-agenda.pdf"

    if post.has_protocol:
        ep_protocol_link = get_pad_link(post.protocol_key)

        if ep_protocol_link != "#":
            filename_protocol = post.slug + "-protokoll.pdf"

    related_posts = post.tags.similar_objects()
    # list of non 'is_hidden' posts for related_posts
    for obj in related_posts:
        if not obj.published:
            related_posts.remove(obj)

    context = {
        "post": post,
        "files": files,
        "author": author,
        "author_image": author_image,
        "next": __next(post, public_only),
        "related_posts": related_posts[0:6],
        "ep_agenda_link": ep_agenda_link,
        "ep_protocol_link": ep_protocol_link,
        "filename_agenda": filename_agenda,
        "filename_protocol": filename_protocol,
    }

    response = render(request, "posts/show.html", context)

    # check if etherpad server works
    if ep_agenda_link or ep_protocol_link:
        try:
            response = add_ep_cookie(request, response)
        except Exception as e:
            logger.info("Etherpad Server doesn't work. Error: %s", e)

    return response


def show_pdf(request, html, filename):
    rendered = render_to_string(
        settings.BASE_DIR + "/templates/posts/pdf/template.html"
    )

    # get body-content from pdf template
    rendered = rendered.split("<html>")[1]
    rendered = rendered.split("<body>")[0]

    # set body-content in html
    idx = html.index("<body>")
    html = html[:idx] + rendered + html[idx:]

    pdf = render_to_pdf(html)

    if not pdf:
        raise Http404("can't create pdf file")

    response = HttpResponse(pdf, content_type="application/pdf")

    content = "inline; filename=%s" % filename
    response["Content-Disposition"] = content

    return response


def show_pdf_agenda(request, id):
    post = __get_post_object(id)
    html = post.agenda_html

    return show_pdf(request, html, post.slug + "-agenda")


@authenticated_user
def show_pdf_protocol(request, id):
    post = __get_post_object(id)
    html = post.protocol_html

    return show_pdf(request, html, post.slug + "-protokoll")


def __next(post=None, public=True):
    """
    Helper function for getting next post
    """
    posts = None
    d = post.slug

    if post:
        # TODO: bad implementation but it works!!
        if post.post_type == "N" or post.post_type == "E":
            posts = Post.articles.date_sorted_list(public)
        elif post.post_type == "F":
            posts = FetMeeting.objects.published(public)

    if posts:
        for k, v in enumerate(posts):
            if post.slug == v.slug:
                if (k + 1) < len(posts):
                    d = posts[k + 1].slug
                else:
                    d = posts[0].slug
                break

    return d
