from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.utils.translation import gettext_lazy as _
from django.http import HttpRequest
from django.shortcuts import render, get_object_or_404

from intervention.forms import NewInterventionForm, EditInterventionForm, ShareInterventionForm, NewRevocationForm, \
    RunCheckForm, NewWithdrawForm
from intervention.models import Intervention, Revocation
from intervention.tables import InterventionTable
from konova.contexts import BaseContext
from konova.decorators import *
from konova.forms import SimpleGeomForm, NewDocumentForm, RemoveModalForm
from konova.sub_settings.django_settings import DEFAULT_DATE_FORMAT
from konova.utils.message_templates import FORM_INVALID
from konova.utils.user_checks import in_group


@login_required
@any_group_check
def index_view(request: HttpRequest):
    """
    Renders the index view for Interventions

    Args:
        request (HttpRequest): The incoming request

    Returns:
        A rendered view
    """
    template = "generic_index.html"

    # Filtering by user access is performed in table filter inside of InterventionTableFilter class
    interventions = Intervention.objects.filter(
        deleted=None,  # not deleted
        next_version=None,  # only newest versions
    ).order_by(
        "-created__timestamp"
    )
    table = InterventionTable(
        request=request,
        queryset=interventions
    )
    context = {
        "table": table,
    }
    context = BaseContext(request, context).context
    return render(request, template, context)


@login_required
@default_group_required
def new_view(request: HttpRequest):
    """
    Renders a view for a new intervention creation

    Args:
        request (HttpRequest): The incoming request

    Returns:

    """
    template = "konova/form.html"
    form = NewInterventionForm(request.POST or None)
    if request.method == "POST":
        if form.is_valid():
            intervention = form.save(request.user)
            messages.success(request, _("Intervention {} added").format(intervention.title))
            return redirect("intervention:index")
        else:
            messages.error(request, _("Invalid input"))
    else:
        # For clarification: nothing in this case
        pass
    context = {
        "form": form,
    }
    context = BaseContext(request, context).context
    return render(request, template, context)


@login_required
def new_document_view(request: HttpRequest, id: str):
    """ Renders a form for uploading new documents

    Args:
        request (HttpRequest): The incoming request
        id (str): The intervention's id to which the new document will be related
    Returns:

    """
    intervention = get_object_or_404(Intervention, id=id)
    form = NewDocumentForm(request.POST or None, request.FILES or None, instance=intervention, user=request.user)
    return form.process_request(
        request,
        msg_success=_("Document added")
    )


@login_required
@any_group_check
def open_view(request: HttpRequest, id: str):
    """ Renders a detail view for viewing an intervention's data

    Args:
        request (HttpRequest): The incoming request
        id (str): The intervention's id

    Returns:

    """
    template = "intervention/detail/view.html"

    # Fetch data, filter out deleted related data
    intervention = get_object_or_404(Intervention, id=id)
    compensations = intervention.compensations.filter(
        deleted=None,
    )
    _user = request.user
    is_data_shared = intervention.is_shared_with(user=_user)

    geom_form = SimpleGeomForm(
        instance=intervention
    )

    # Inform user about revocation
    if intervention.legal.revocation:
        messages.error(
            request,
            _("This intervention has a revocation from {}").format(intervention.legal.revocation.date.strftime(DEFAULT_DATE_FORMAT)),
            extra_tags="danger",
        )

    context = {
        "intervention": intervention,
        "compensations": compensations,
        "has_access": is_data_shared,
        "geom_form": geom_form,
        "is_default_member": in_group(_user, DEFAULT_GROUP),
        "is_zb_member": in_group(_user, ZB_GROUP),
        "is_ets_member": in_group(_user, ETS_GROUP),
        "LANIS_LINK": intervention.get_LANIS_link()
    }

    if not is_data_shared:
        messages.info(request, _("Remember: This data has not been shared with you, yet. This means you can only read but can not edit or perform any actions like running a check or recording."))

    context = BaseContext(request, context).context
    return render(request, template, context)


@login_required
def edit_view(request: HttpRequest, id: str):
    """
    Renders a view for editing interventions

    Args:
        request (HttpRequest): The incoming request

    Returns:

    """
    template = "konova/form.html"
    intervention = get_object_or_404(Intervention, id=id)
    if request.method == "POST":
        form = EditInterventionForm(request.POST or None, instance=intervention)
        if form.is_valid():
            intervention = form.save(request.user)
            messages.success(request, _("{} edited").format(intervention))
            return redirect("intervention:index")
        else:
            messages.error(request, _("Invalid input"))
    form = EditInterventionForm(instance=intervention)
    context = {
        "form": form,
    }
    context = BaseContext(request, context).context
    return render(request, template, context)


@login_required
@default_group_required
def remove_view(request: HttpRequest, id: str):
    """ Renders a remove view for this intervention

    Args:
        request (HttpRequest): The incoming request
        id (str): The uuid id as string

    Returns:

    """
    obj = Intervention.objects.get(id=id)
    identifier = obj.identifier
    form = RemoveModalForm(request.POST or None, instance=obj, user=request.user)
    return form.process_request(
        request,
        _("{} removed").format(identifier),
        redirect_url=reverse("intervention:index")
    )


@login_required
@default_group_required
def remove_revocation_view(request: HttpRequest, id: str):
    """ Renders a remove view for a revocation

    Args:
        request (HttpRequest): The incoming request
        id (str): The revocation's id as string

    Returns:

    """
    obj = Revocation.objects.get(id=id)
    form = RemoveModalForm(request.POST or None, instance=obj, user=request.user)
    return form.process_request(
        request,
        _("Revocation removed"),
    )


@login_required
def share_view(request: HttpRequest, id: str, token: str):
    """ Performs sharing of an intervention

    If token given in url is not valid, the user will be redirected to the dashboard

    Args:
        request (HttpRequest): The incoming request
        id (str): Intervention's id
        token (str): Access token for intervention

    Returns:

    """
    user = request.user
    intervention = get_object_or_404(Intervention, id=id)
    # Check tokens
    if intervention.access_token == token:
        # Send different messages in case user has already been added to list of sharing users
        if intervention.is_shared_with(user):
            messages.info(
                request,
                _("{} has already been shared with you").format(intervention.identifier)
            )
        else:
            messages.success(
                request,
                _("{} has been shared with you").format(intervention.identifier)
            )
            intervention.users.add(user)
        return redirect("intervention:open", id=id)
    else:
        messages.error(
            request,
            _("Share link invalid"),
            extra_tags="danger",
        )
        return redirect("home")


@login_required
def create_share_view(request: HttpRequest, id: str):
    """ Renders sharing form for an intervention

    Args:
        request (HttpRequest): The incoming request
        id (str): Intervention's id

    Returns:

    """
    intervention = get_object_or_404(Intervention, id=id)
    form = ShareInterventionForm(request.POST or None, instance=intervention, request=request)
    if request.method == "POST":
        if form.is_valid():
            form.save()
            messages.info(
                request,
                _("Share settings updated")
            )
            return redirect(request.META.get("HTTP_REFERER", "home"))
    elif request.method == "GET":
        context = {
            "form": form,
        }
        context = BaseContext(request, context).context
        return render(request, form.template, context)
    else:
        raise NotImplementedError


@login_required
def run_check_view(request: HttpRequest, id: str):
    """ Renders check form for an intervention

    Args:
        request (HttpRequest): The incoming request
        id (str): Intervention's id

    Returns:

    """
    intervention = get_object_or_404(Intervention, id=id)
    form = RunCheckForm(request.POST or None, instance=intervention, user=request.user)
    if request.method == "POST":
        if form.is_valid():
            form.save()
            messages.info(
                request,
                _("Check performed")
            )
        else:
            messages.error(
                request,
                _("There has been errors on this intervention:"),
                extra_tags="danger"
            )
            for error_name, error_val in form.errors.items():
                messages.error(
                    request,
                    _("{}: {}").format(_(error_name), _(error_val)),
                    extra_tags="danger"
                )
        return redirect(request.META.get("HTTP_REFERER", "home"))
    elif request.method == "GET":
        context = {
            "form": form,
        }
        context = BaseContext(request, context).context
        return render(request, form.template, context)
    else:
        raise NotImplementedError


@login_required
def new_revocation_view(request: HttpRequest, id: str):
    """ Renders sharing form for an intervention

    Args:
        request (HttpRequest): The incoming request
        id (str): Intervention's id

    Returns:

    """
    intervention = get_object_or_404(Intervention, id=id)
    form = NewRevocationForm(request.POST or None, request.FILES or None, instance=intervention, user=request.user)
    if request.method == "POST":
        if form.is_valid():
            form.save()
            messages.info(
                request,
                _("Revocation added")
            )
        else:
            messages.error(
                request,
                FORM_INVALID,
                extra_tags="danger",
            )
        return redirect(request.META.get("HTTP_REFERER", "home"))
    elif request.method == "GET":
        context = {
            "form": form,
        }
        context = BaseContext(request, context).context
        return render(request, form.template, context)
    else:
        raise NotImplementedError


@login_required
def log_view(request: HttpRequest, id: str):
    """ Renders a log view using modal

    Args:
        request (HttpRequest): The incoming request
        id (str): The compensation's id

    Returns:

    """
    intervention = get_object_or_404(Intervention, id=id)
    template = "modal/modal_generic.html"
    body_template = "log.html"

    context = {
        "modal_body_template": body_template,
        "log": intervention.log.all().order_by("-timestamp"),
        "modal_title": _("Log"),
    }
    context = BaseContext(request, context).context
    return render(request, template, context)


@login_required
@default_group_required
def new_withdraw_view(request: HttpRequest, id: str):
    """ Renders a modal form view for creating withdraws

    Args:
        request (HttpRequest): The incoming request
        id (str): The intervention's id which shall get a new withdraw

    Returns:

    """
    intervention = get_object_or_404(Intervention, id=id)
    form = NewWithdrawForm(request.POST or None, instance=intervention, user=request.user)
    return form.process_request(
        request,
        msg_success=_("Withdraw added")
    )