import random

from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import PermissionDenied
from django.db.models import Q
from django.http import FileResponse
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.views import View
from django.views.generic import CreateView, UpdateView, DetailView, FormView
from django_tables2 import SingleTableView

from tournament.forms import TeamForm, JoinTeam
from tournament.models import Team
from tournament.views import AdminMixin, TeamMixin
from .forms import SignUpForm, TFJMUserForm, AdminUserForm, CoachUserForm
from .models import TFJMUser, Document, Solution, MotivationLetter, Synthesis
from .tables import UserTable


class CreateUserView(CreateView):
    model = TFJMUser
    form_class = SignUpForm
    template_name = "registration/signup.html"


class MyAccountView(LoginRequiredMixin, UpdateView):
    model = TFJMUser
    template_name = "member/my_account.html"

    def get_form_class(self):
        return AdminUserForm if self.request.user.organizes else TFJMUserForm \
            if self.request.user.role == "3participant" else CoachUserForm

    def get_object(self, queryset=None):
        return self.request.user


class UserDetailView(LoginRequiredMixin, DetailView):
    model = TFJMUser
    form_class = TFJMUserForm
    context_object_name = "tfjmuser"

    def dispatch(self, request, *args, **kwargs):
        if isinstance(request.user, AnonymousUser):
            raise PermissionDenied

        self.object = self.get_object()

        if not request.user.admin \
                and (self.object.team is not None and request.user not in self.object.team.tournament.organizers.all())\
                and self.request.user != self.object:
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        if "view_as" in request.POST:
            session = request.session
            session["admin"] = request.user.pk
            obj = self.get_object()
            session["_fake_user_id"] = obj.pk
            return redirect(request.path)
        return self.get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        context["title"] = str(self.object)

        return context


class AddTeamView(LoginRequiredMixin, CreateView):
    model = Team
    form_class = TeamForm

    def form_valid(self, form):
        if self.request.user.organizes:
            form.add_error('name', _("You can't organize and participate at the same time."))
            return self.form_invalid(form)

        if self.request.user.team:
            form.add_error('name', _("You are already in a team."))
            return self.form_invalid(form)

        team = form.instance
        alphabet = "0123456789abcdefghijklmnopqrstuvwxyz0123456789"
        code = ""
        for i in range(6):
            code += random.choice(alphabet)
        team.access_code = code
        team.validation_status = "0invalid"

        team.save()
        team.refresh_from_db()

        self.request.user.team = team
        self.request.user.save()

        return super().form_valid(form)

    def get_success_url(self):
        return reverse_lazy("member:my_team")


class JoinTeamView(LoginRequiredMixin, FormView):
    model = Team
    form_class = JoinTeam
    template_name = "tournament/team_form.html"

    def form_valid(self, form):
        team = form.cleaned_data["team"]

        if self.request.user.organizes:
            form.add_error('access_code', _("You can't organize and participate at the same time."))
            return self.form_invalid(form)

        if self.request.user.team:
            form.add_error('access_code', _("You are already in a team."))
            return self.form_invalid(form)

        if self.request.user.role == '2coach' and len(team.encadrants) == 3:
            form.add_error('access_code', _("This team is full of coachs."))
            return self.form_invalid(form)

        if self.request.user.role == '3participant' and len(team.participants) == 6:
            form.add_error('access_code', _("This team is full of participants."))
            return self.form_invalid(form)

        self.request.user.team = team
        self.request.user.save()
        return super().form_valid(form)

    def get_success_url(self):
        return reverse_lazy("member:my_team")


class MyTeamView(TeamMixin, View):
    def get(self, request, *args, **kwargs):
        return redirect("tournament:team_detail", pk=request.user.team.pk)


class DocumentView(LoginRequiredMixin, View):
    def get(self, request, *args, **kwargs):
        doc = Document.objects.get(file=self.kwargs["file"])

        grant = request.user.admin

        if isinstance(doc, Solution) or isinstance(doc, Synthesis) or isinstance(doc, MotivationLetter):
            grant = grant or doc.team == request.user.team or request.user in doc.team.tournament.organizers.all()

        if isinstance(doc, Synthesis) and request.user.organizes:
            grant = True

        if isinstance(doc, Solution):
            for pool in doc.pools.all():
                if pool.round == 2 and timezone.now() < doc.tournament.date_solutions_2:
                    continue
                if self.request.user.team in pool.teams.all():
                    grant = True

        if not grant:
            raise PermissionDenied

        return FileResponse(doc.file, content_type="application/pdf")


class ProfileListView(AdminMixin, SingleTableView):
    model = TFJMUser
    queryset = TFJMUser.objects.order_by("role", "last_name", "first_name")
    table_class = UserTable
    template_name = "member/profile_list.html"
    extra_context = dict(title=_("All profiles"))


class OrphanedProfileListView(AdminMixin, SingleTableView):
    model = TFJMUser
    queryset = TFJMUser.objects.filter((Q(role="2coach") | Q(role="3participant")) & Q(team__isnull=True))\
        .order_by("role", "last_name", "first_name")
    table_class = UserTable
    template_name = "member/profile_list.html"
    extra_context = dict(title=_("Orphaned profiles"))


class OrganizersListView(AdminMixin, SingleTableView):
    model = TFJMUser
    queryset = TFJMUser.objects.filter(Q(role="0admin") | Q(role="1volunteer"))\
        .order_by("role", "last_name", "first_name")
    table_class = UserTable
    template_name = "member/profile_list.html"
    extra_context = dict(title=_("Organizers"))


class ResetAdminView(AdminMixin, View):
    def dispatch(self, request, *args, **kwargs):
        if "_fake_user_id" in request.session:
            del request.session["_fake_user_id"]
        return redirect(request.GET["path"])