from ..context import context_adaption
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.http import FileResponse, HttpResponseNotAllowed
from django.shortcuts import render, HttpResponse, redirect
from django.urls.base import reverse
from django.utils.translation import gettext as _
from ..forms import TagForm
import fstools
from ..help import help_pages
from .image import get_image_instance, other
from .infoviews import get_wrapper_instance as get_infoview_wrapper_instance
import mimetypes
from ..models import get_item_by_rel_path, get_item_type, TYPE_IMAGE, Tag, Item
import os
import pygal
from ..queries import search_result_query
import tempfile
from themes import Context
from users.views import profile_pre_actions, profile_post_actions
from users.forms import UserProfileFormLanguageOnly
from .userviews import get_wrapper_instance as get_userview_wrapper_instance
import zipfile
from pygal.views.userviews import query_view
from pygal.views.image import mm_image


def pygal_item_does_not_exist(request, context):
    context.set_additional_title(_('Page does not exist!'))
    messages.error(request, _('The Item for the given URL does not exist.'))
    return render(request, 'pygal/empty.html', context=context)


def pygal_access_denied(request, context):
    context.set_additional_title(_('Access denied!'))
    messages.error(request, _('Access Denied: You don\'t have access rights.'))
    return render(request, 'pygal/empty.html', context=context)


def get_next(request):
    if not request.POST:
        return request.GET.get('next', '/')
    else:
        return request.POST.get('next', '/')


def pygal_responses(request, responsetype=pygal.RESP_TYPE_USERVIEW, datatype=pygal.DATA_TYPE_SEARCH, rel_path=''):
    # raw and scaled items
    if responsetype in [pygal.RESP_TYPE_RAWITEM, pygal.RESP_TYPE_WEBNAIL, pygal.RESP_TYPE_THUMBNAIL]:
        return pygal_item(request, responsetype, rel_path)
    # userview and infoview for items
    elif responsetype in [pygal.RESP_TYPE_USERVIEW, pygal.RESP_TYPE_INFOVIEW] and datatype == pygal.DATA_TYPE_ITEM:
        return pygal_userview_infoview(request, responsetype, rel_path)
    # download
    elif responsetype == pygal.RESP_TYPE_DOWNLOAD:
        return pygal_download(request, datatype, rel_path)
    # search
    elif responsetype in [pygal.RESP_TYPE_USERVIEW, pygal.RESP_TYPE_INFOVIEW] and datatype == pygal.DATA_TYPE_SEARCH:
        if not rel_path:
            return pygal_search(request, rel_path)
        else:
            return pygal_userview_infoview(request, responsetype, rel_path)
    else:
        d = {
            'responsetype': responsetype,
            'datatype': datatype,
        }
        messages.error(request, _('No response implemented in pygal.views.pygal_responses for responsetype="%(responsetype)s" and datatype="%(datatype)s".') % d)
        return redirect('/')


def pygal_search(request, rel_path):
    context = Context(request)      # needs to be executed first because of time mesurement
    w = query_view(request, search_result_query(request))
    context_adaption(context, request, '', wrapper_instance=w)
    context.set_additional_title(w.name)
    return w.render(context)


def pygal_download(request, datatype, rel_path):
    full_path = pygal.get_full_path(rel_path)
    if os.path.isfile(full_path):
        # Download a file
        temp = open(full_path, 'rb')
        fn = os.path.basename(full_path)
    else:
        if pygal.is_favouriteview(request) or pygal.is_searchview(request) and rel_path == '':
            if pygal.is_favouriteview(request):
                fn = 'favourites.zip'
            else:
                fn = 'search.zip'
            # Download the favourites or search results
            fp_list = []
            for i in search_result_query(request):
                if i.may_read(request.user):
                    fp_list.append(pygal.get_full_path(i.rel_path))
        else:
            # Download the folder full_path
            fn = (os.path.basename(full_path) or 'root') + '.zip'
            fp_list = []
            for i in get_item_by_rel_path(rel_path).all_itemslist():
                if i.may_read(request.user):
                    fp_list.append(pygal.get_full_path(i.rel_path))
        #
        # Create the Archive from fp_list
        #
        flat = pygal.is_flat(request)
        temp = tempfile.TemporaryFile(dir=settings.TEMP_ROOT)
        archive = zipfile.ZipFile(temp, 'w', zipfile.ZIP_STORED)
        for fp in fp_list:
            archive.write(fp, os.path.basename(pygal.get_rel_path(fp)) if flat else pygal.get_rel_path(fp))
        archive.close()
        temp.seek(0)
    #
    # return file response
    #
    response = FileResponse(temp, content_type=mimetypes.types_map.get(os.path.splitext(fn)[1]))
    response['Content-Disposition'] = 'attachment; filename="%s"' % fn
    return response


def pygal_helpview(request, page='main'):
    context = Context(request)      # needs to be executed first because of time mesurement
    help_content = help_pages[page]
    context_adaption(
        context,                            # the base context
        request,                            # the request object to be used in context_adaption
        rel_path='',                      # the current help_page to identify which taskbar entry has to be highlighted
        title=_('Help'),                    # the title for the page (template)
        current_help_page=page,
    )
    context['help_content'] = help_content  # the help content itself (template)
    return render(request, 'pygal/help.html', context=context)

    context = Context(request)      # needs to be executed first because of time mesurement
    context_adaption(context, request, '', title=_('Help'))
    return help_data(request, context)


def pygal_userview_infoview(request, responsetype, rel_path):
    context = Context(request)      # needs to be executed first because of time mesurement
    full_path = pygal.get_full_path(rel_path)
    try:
        if responsetype == pygal.RESP_TYPE_INFOVIEW:
            w = get_infoview_wrapper_instance(full_path, request)
        else:
            w = get_userview_wrapper_instance(full_path, request)
    except LookupError:
        context_adaption(context, request, '')
        return pygal_item_does_not_exist(request, context)
    context_adaption(context, request, rel_path, wrapper_instance=w)
    #
    if w.may_read():
        context.set_additional_title(w.name)
        return w.render(context)
    else:
        return pygal_access_denied(request, context)


def pygal_item(request, responsetype, rel_path):
    full_path = pygal.get_full_path(rel_path)
    i = get_item_by_rel_path(rel_path)
    if not i.may_read(request.user):
        im = other(full_path, request)  # This will return a mime icon instead of the image itself
    else:
        im = get_image_instance(full_path, request)
    #
    if responsetype == pygal.RESP_TYPE_THUMBNAIL:
        return HttpResponse(im.thumbnail_picture(), content_type=im.mime_type_xnails)
    elif responsetype == pygal.RESP_TYPE_WEBNAIL:
        return HttpResponse(im.webnail_picture(), content_type=im.mime_type_xnails)
    else:
        if i.may_read(request.user):
            mimetypes.init()
            mime_type = mimetypes.types_map.get(os.path.splitext(full_path)[1])
            data = open(full_path, 'rb').read()
            return HttpResponse(data, content_type=mime_type)
        else:
            im = mm_image(os.path.join(os.path.dirname(__file__), 'forbidden.png'))
            if responsetype == pygal.RESP_TYPE_THUMBNAIL:
                im.resize(int(pygal.get_thumbnail_size(request) * .75))
            return HttpResponse(im.image_data(), content_type='image/png')


@login_required
def pygal_profile(request):
    context = Context(request)      # needs to be executed first because of time mesurement
    current_thumbnail_size = pygal.get_thumbnail_size(request)
    current_webnail_size = pygal.get_webnail_size(request)
    profile_pre_actions(request, context, UserProfileFormLanguageOnly)
    context_adaption(context, request, '', title=_('Profile for %(username)s') % {'username': request.user.username})
    context['THUMBNAIL_SIZES'] = settings.THUMBNAIL_SIZES
    context['thumbnail_size'] = current_thumbnail_size
    context['WEBNAIL_SIZES'] = settings.WEBNAIL_SIZES
    context['webnail_size'] = current_webnail_size
    if request.POST:
        # store thumbnail size, if changed
        thumbnail_size = int(request.POST.get('thumbnail_size'))
        if current_thumbnail_size != thumbnail_size:
            pygal.set_thumbnail_size(request, thumbnail_size)
            current_thumbnail_size = thumbnail_size
            messages.info(request, _('The Thumbnail Size was set to "%d"') % (thumbnail_size))
        # store webnail size, if changed
        webnail_size = int(request.POST.get('webnail_size'))
        if current_webnail_size != webnail_size:
            pygal.set_webnail_size(request, webnail_size)
            current_webnail_size = webnail_size
            messages.info(request, _('The Webnail Size was set to "%d"') % (webnail_size))
        return profile_post_actions(request, context)
    else:
        return render(request, 'pygal/profile.html', context=context)


def tag_context_adaption(context, w, request, enable_tag_area_selection):
    context['item'] = w
    context['next'] = get_next(request)
    context['enable_tag_area_selection'] = enable_tag_area_selection
    if enable_tag_area_selection:
        i_w, i_h = w.width, w.height
        max_size = int(pygal.get_webnail_size(request) / 2)
        factor_to_original = max(i_w, i_h) / max_size
        context['factor_to_original'] = factor_to_original
        context['tag_img_width'] = int(i_w / factor_to_original)
        context['tag_img_height'] = int(i_h / factor_to_original)


def pygal_addtag(request, rel_path):
    context = Context(request)      # needs to be executed first because of time mesurement
    full_path = pygal.get_full_path(rel_path)
    w = get_userview_wrapper_instance(full_path, request)
    if not w.may_modify():
        messages.error(request, _('You don\'t have the rights to add a Tag to this Item.'))
        return redirect(get_next(request))
    else:
        context_adaption(
            context,
            request,
            rel_path,
            title=_('Add Tag for %s') % w.name
        )
        tag_context_adaption(context, w, request, get_item_type(full_path) in [TYPE_IMAGE])
        if request.POST:
            tag = Tag(item=w.item)
            form = TagForm(request.POST, instance=tag, factor_to_original=context['factor_to_original'])
            if form.is_valid():
                form.save()
                messages.info(request, _('Thanks for adding a Tag to %s') % w.name)
                return redirect(get_next(request))
        else:
            form = TagForm(factor_to_original=context['factor_to_original'])
        context['form'] = form
        return render(request, 'pygal/tagedit.html', context=context)


def pygal_tagedit(request, tag_id):
    context = Context(request)      # needs to be executed first because of time mesurement
    try:
        t = Tag.objects.get(pk=tag_id)
    except Tag.DoesNotExist:
        messages.error(request, _('Tag %d does not exist!') % tag_id)
        return redirect(get_next(request))
    if not t.item.may_modify(request.user):
        messages.error(request, _('You don\'t have the rights to change Tag %(tag_id)d.') % {'tag_id': tag_id})
        return redirect(get_next(request))
    else:
        w = get_userview_wrapper_instance(pygal.get_full_path(t.item.rel_path), request)
        context_adaption(
            context,
            request,
            t.item.rel_path,
            title=_('Edit Tag %(tag_id)d for %(item_name)s') % {'tag_id': tag_id, 'item_name': w.name}
        )
        tag_context_adaption(context, w, request, t.item.type in [TYPE_IMAGE])
        context['enable_delete_button'] = True
        if request.POST:
            if request.POST.get('save'):
                form = TagForm(request.POST, instance=t, factor_to_original=context['factor_to_original'])
                if form.is_valid():
                    form.save()
                    messages.info(request, _('Thanks for editing Tag %(tag_id)d to %(item_name)s') % {'tag_id': tag_id, 'item_name': w.name})
                    return redirect(get_next(request))
            else:
                t.delete()
                messages.info(request, _('Tag %(tag_id)d of %(item_name)s has been deleted.') % {'tag_id': tag_id, 'item_name': w.name})
                return redirect(get_next(request))
        else:
            form = TagForm(instance=t, factor_to_original=context['factor_to_original'])
        context['form'] = form
        return render(request, 'pygal/tagedit.html', context=context)


def pygal_favourite(request, set_favourite, rel_path):
    nxt = request.GET.get('next', '/')
    item = get_item_by_rel_path(rel_path)
    if not set_favourite and request.user in item.favourite_of.all():
        item.favourite_of.remove(request.user)
        item.save()
        if nxt.startswith(pygal.url_favouriteview(request)):
            nxt = pygal.url_favouriteview(request)
    elif set_favourite and request.user not in item.favourite_of.all():
        item.favourite_of.add(request.user)
        item.save()
    else:
        messages.error(request, 'Favourite setting is already in targetstate!')
    return redirect(nxt + '#%s' % item.name)
