from datetime import datetime

from django.contrib.auth import logout, login, update_session_auth_hash
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth.models import User
from django.core.paginator import Paginator
from django.http.response import HttpResponse
from django.shortcuts import render, get_object_or_404, redirect
from notifications.signals import notify

from main.forms import StoryForm, EpicForm, RegisterForm, ProfileForm, \
    CommentForm, SprintForm
from main.models import Story, Epic, Sprint, Comment, Project


def register(request):
    if request.method == 'POST':
        form = RegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            login(request, user)
            return redirect("index")
    else:
        form = RegisterForm()
    return render(request, 'registration/register.html', {'form': form})

@login_required
def index(request):
    epics = Epic.objects.filter(closed=False)
    return render(request, 'index.html', {'current_sprint': Sprint.current(), 'epics': epics})

@login_required
def profile_update(request):
    if request.method == 'POST':
        user = get_object_or_404(User, username=request.user)
        form = ProfileForm(request.POST, instance=user)
        if form.is_valid():
            user = form.save()
            login(request, user)
            return redirect("index")
    else:
        user = get_object_or_404(User, username=request.user)
        form = ProfileForm(instance=user)
    return render(request, 'registration/register.html', {'form': form})

@login_required
def change_password(request):
    if request.method == 'POST':
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user)  # Important!
            return redirect('index')
    else:
        form = PasswordChangeForm(request.user)
    return render(request, 'registration/change_password.html', {'form': form})

@login_required
def logout(request):
    logout(request)
    return redirect("index")

@login_required
def backlog_editor(request):
    
    epics = Epic.objects.filter(closed=False)
    closed = Epic.objects.filter(closed=True)
    
    return render(request, 'backlog_editor.html', {'epics': epics, 'closed': closed})

def sprint_end(request):
    
    current_sprint = Sprint.current()
    next_sprint = Sprint.next()
    
    if request.method == 'POST':
        current_sprint.retro = request.POST["retro"]
        current_sprint.closed = True
        current_sprint.save()
        return redirect("index")
    
    form = SprintForm(instance=current_sprint)
    return render(request, 'sprint_end.html', {'sprint': current_sprint, 'next_sprint': next_sprint, 'form': form})

@login_required
def story_index(request):
    
    sprints = Sprint.objects.all()
    users = User.objects.all()
    
    stories = Story.objects

    filters = request.GET
    if 'state' in filters and filters['state']:
        stories = stories.filter(closed=(filters['state'] == 'closed'))
    if 'sprint' in filters and filters['sprint']:
        if filters['sprint'] == "None":
            stories = stories.filter(sprints=None)
        else:
            stories = stories.filter(sprints__id=filters['sprint'])
    if 'author' in filters and filters['author']:
        stories = stories.filter(author_id=filters['author'])
    if 'assignee' in filters and filters['assignee']:
        stories = stories.filter(assignees__id=filters['assignee'])
    
    paginator = Paginator(stories.all(), 20)
    page = request.GET.get('page')
    stories = paginator.get_page(page)
    
    return render(request, 'story_index.html', {'stories': stories, 'sprints': sprints, 'users': users, 'pages': range(1, paginator.num_pages + 1)})

@login_required
def story_details(request, story_id):
    story = get_object_or_404(Story, id=story_id)
    return render(request, 'story_details.html', {'story': story})

@login_required
def story_create(request, epic_id=None):
    if request.method == 'POST':
        
        form = StoryForm(request.POST)
        if form.is_valid():
            story = form.save()
            return redirect("story_details", story.id)
        
    else:
        story = Story()
        if epic_id is not None:
            story.epic = get_object_or_404(Epic, id=epic_id)
        story.author = User.objects.get(username=request.user)
        form = StoryForm(instance=story)
        
    return render(request, 'story_form.html', {'form': form, 'current_sprint_id': Sprint.current().id})

@login_required
def story_edit(request, story_id):
    if request.method == 'POST':
        story = get_object_or_404(Story, id=story_id)
        form = StoryForm(request.POST, instance=story)
        if form.is_valid():
            form.save()
            return redirect("story_details", story.id)
        
    else:
        story = get_object_or_404(Story, id=story_id)
        form = StoryForm(instance=story)
        
    return render(request, 'story_form.html', {'form': form, 'current_sprint_id': Sprint.current().id})

@login_required
def story_delete(request, story_id):
    if request.method == 'POST':
        story = get_object_or_404(Story, id=story_id)
        story.delete()
        return redirect("index")
    else:
        story = get_object_or_404(Story, id=story_id)
        return render(request, 'deletion.html', {'object': story})

@login_required
def story_close(_, story_id):
    story = get_object_or_404(Story, id=story_id)
    story.close()
    return redirect('epic_details', story.epic.id)

def story_close_ajax(_, story_id):
    story = get_object_or_404(Story, id=story_id)
    story.close()
    return HttpResponse(story.to_json())

@login_required
def story_reaffect_ajax(_, story_id):
    story = get_object_or_404(Story, id=story_id)
    next_sprint = Sprint.next()
    story.sprints.add(next_sprint)
    story.save()
    return HttpResponse(story.to_json())

@login_required
def story_reopen(_, story_id):
    story = get_object_or_404(Story, id=story_id)
    story.reopen()
    return redirect('story_details', story_id)

@login_required
def epic_details(request, epic_id):
    epic = get_object_or_404(Epic, id=epic_id)
    return render(request, 'epic_details.html', {'epic': epic})

@login_required
def epic_create(request):
    if request.method == 'POST':
        
        form = EpicForm(request.POST)
        if form.is_valid():
            epic = form.save(commit=False)
            epic.author = User.objects.get(username=request.user)
            epic.save()
            return redirect("backlog_editor")
        
    else:
        form = EpicForm()
         
    return render(request, 'epic_form.html', {'form': form})

@login_required
def epic_edit(request, epic_id, from_=""):
    if request.method == 'POST':
        epic = get_object_or_404(Epic, id=epic_id)
        form = EpicForm(request.POST, instance=epic)
        if form.is_valid():
            form.save()
            if from_:
                return redirect(from_)
            else:
                return redirect("epic_details", epic.id)
    else:
        
        epic = get_object_or_404(Epic, id=epic_id)
        form = EpicForm(instance=epic)
    
    return render(request, 'epic_form.html', {'form': form})

@login_required
def epic_delete(request, epic_id):
    if request.method == 'POST':
        epic = get_object_or_404(Epic, id=epic_id)
        epic.delete()
        return redirect("index")
    else:
        epic = get_object_or_404(Epic, id=epic_id)
        return render(request, 'deletion.html', {'object': epic})

@login_required
def epic_value_update(request, epic_id):
    if request.method == 'POST':
        epic = get_object_or_404(Epic, id=epic_id)
        epic.value = request.POST["value"]
        epic.save()
        return redirect("backlog_editor")
    
@login_required
def epic_close(_, epic_id):
    epic = get_object_or_404(Epic, id=epic_id)
    epic.close()
    epic.save()
    return redirect("backlog_editor")

@login_required
def epic_reopen(_, epic_id):
    epic = get_object_or_404(Epic, id=epic_id)
    epic.reopen()
    return redirect("backlog_editor")

@login_required
def reports(request):
    return render(request, 'reports/report_index.html')
     
@login_required
def report_sprints(request):
    sprints = Sprint.objects.all()
    return render(request, 'reports/report_sprints.html', {'sprints': sprints})
     
@login_required
def report_projects(request):
    epics = Epic.objects.filter(closed=False)
    return render(request, 'reports/report_projects.html', {'epics': epics})

def report_activity(request):
    
    projects_activity = {}
    for project in Project.objects.all():
        projects_activity[project] = {}
        projects_activity[project]["current"] = 0
        projects_activity[project]["sixmonths"] = 0
        
    epics_activity = {}
    for epic in Epic.objects.all():
        epics_activity[epic] = {}
        epics_activity[epic]["current"] = 0
        epics_activity[epic]["sixmonths"] = 0
        
    current = True
    for sprint in Sprint.objects.filter(date_end__lt = datetime.today()).order_by('-date_start')[:12]:
        for story in sprint.stories.all():
            if not story.epic:
                continue
            if current:
                projects_activity[story.epic.project]["current"] += story.weight
                epics_activity[story.epic]["current"] += story.weight
            projects_activity[story.epic.project]["sixmonths"] += story.weight
            epics_activity[story.epic]["sixmonths"] += story.weight
        
        current = False
    
    epics_activity_cleaned = {epic: act for epic, act in epics_activity.items() if act["sixmonths"] > 0 }
    
    return render(request, 'reports/report_activity.html', {'projects_activity': projects_activity, 'epics_activity': epics_activity_cleaned})

@login_required
def comment_post(request):
    form = CommentForm(request.POST)
    if form.is_valid():
        comment = form.save(commit=False)
        comment.author = get_object_or_404(User, username=request.user)
        comment.save()
        return redirect(request.META['HTTP_REFERER'].split("#")[0] + "#a-comment-{}".format(comment.id))
    else:
        return redirect(request.META['HTTP_REFERER'])

@login_required
def comment_edit(request, comment_id):
    comment = get_object_or_404(Comment, id=comment_id)
    form = CommentForm(request.POST, instance=comment)
    if form.is_valid():
        form.save()
        return redirect(request.META['HTTP_REFERER'].split("#")[0] + "#a-comment-{}".format(comment_id))
    else:
        return redirect(request.META['HTTP_REFERER'])
    
@login_required
def comment_del(request, comment_id):
    comment = get_object_or_404(Comment, id=comment_id)
    comment.delete()
    return redirect(request.META['HTTP_REFERER'].split("#")[0] + "#a-comment-section")

@login_required
def search(request):
    qstr = request.GET["q"]
    
    results = []
    results += Epic.objects.filter(name__icontains=qstr)
    results += Story.objects.filter(name__icontains=qstr)
    
    results += Epic.objects.filter(description__icontains=qstr)
    results += Story.objects.filter(description__icontains=qstr)
    
    if len(results) == 1:
        r = results[0]
        if isinstance(r, Epic):
            return redirect("epic_details", r.id)
        else:
            return redirect("story_details", r.id)
    else:
        
        paginator = Paginator(results, 10)
        page = request.GET.get('page')
        results = paginator.get_page(page)
        
        return render(request, 'search_results.html', {'results': results, 'pages': range(1, paginator.num_pages + 1)})
    
    
    