import copy

import nh3
from django import forms
from django.conf import settings
from django.contrib.auth import get_user_model
from django.utils import timezone
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from froide.helper.widgets import BootstrapSelect
from tinymce.widgets import TinyMCE

from .models import GovernmentPlan, GovernmentPlanUpdate, PlanRating, PlanStatus

ALLOWED_TAGS = {
    "a",
    "strong",
    "b",
    "i",
    "em",
    "ul",
    "ol",
    "li",
    "p",
    "h3",
    "h4",
    "h5",
    "blockquote",
}


class BleachField(forms.CharField):
    """Bleach form field"""

    def to_python(self, value):
        """
        Strips any dodgy HTML tags from the input.
        Mark the return value as template safe.
        """
        if value in self.empty_values:
            return self.empty_value
        cleaned_html = nh3.clean(value, tags=ALLOWED_TAGS, link_rel="noopener")
        return mark_safe(cleaned_html)


class GovernmentPlanForm(forms.ModelForm):
    description = BleachField(
        required=False, widget=TinyMCE(attrs={"cols": 80, "rows": 30})
    )

    class Meta:
        model = GovernmentPlan
        fields = "__all__"


class GovernmentPlanUpdateForm(forms.ModelForm):
    content = BleachField(
        required=False, widget=TinyMCE(attrs={"cols": 80, "rows": 30})
    )

    class Meta:
        model = GovernmentPlanUpdate
        fields = "__all__"


class GovernmentPlanUpdateProposalForm(forms.ModelForm):
    title = forms.CharField(
        label=_("title"),
        help_text=_("Summarize the update in a title."),
        widget=forms.TextInput(
            attrs={
                "class": "form-control",
            }
        ),
    )
    content = forms.CharField(
        required=False,
        label=_("details"),
        help_text=_("Optionally give more details."),
        widget=forms.Textarea(attrs={"class": "form-control", "rows": "3"}),
    )
    url = forms.URLField(
        label=_("source URL"),
        help_text=_("Please give provide a link."),
        widget=forms.URLInput(
            attrs={"class": "form-control", "placeholder": "https://"}
        ),
    )
    status = forms.ChoiceField(
        label=_("status"),
        help_text=_("Has the status of the plan changed?"),
        choices=[("", "---")] + PlanStatus.choices,
        required=False,
        widget=BootstrapSelect,
    )
    rating = forms.TypedChoiceField(
        label=_("rating"),
        help_text=_("What's your rating of the current implementation?"),
        choices=[("", "---")] + PlanRating.choices,
        coerce=int,
        empty_value=None,
        required=False,
        widget=BootstrapSelect,
    )

    class Meta:
        model = GovernmentPlanUpdate
        fields = (
            "title",
            "content",
            "url",
            "status",
            "rating",
        )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def save(self, plan, user):
        """
        This doesn't save instance, but saves
        the change proposal.
        """
        data = self.cleaned_data
        plan.proposals = plan.proposals or {}
        plan.proposals[user.id] = {
            "data": data,
            "timestamp": timezone.now().isoformat(),
        }
        plan.save(update_fields=["proposals"])
        return plan


class GovernmentPlanUpdateAcceptProposalForm(GovernmentPlanUpdateProposalForm):
    def __init__(self, *args, **kwargs):
        self.plan = kwargs.pop("plan")
        super().__init__(*args, **kwargs)

    def get_proposals(self):
        data = copy.deepcopy(self.plan.proposals)
        user_ids = self.plan.proposals.keys()
        user_map = {
            str(u.id): u for u in get_user_model().objects.filter(id__in=user_ids)
        }
        status_dict = dict(PlanStatus.choices)
        rating_dict = dict(PlanRating.choices)
        for user_id, v in data.items():
            v["user"] = user_map[user_id]
            data[user_id]["data"]["rating_label"] = rating_dict.get(
                data[user_id]["data"]["rating"]
            )
            data[user_id]["data"]["status_label"] = status_dict.get(
                data[user_id]["data"]["status"]
            )
        return data

    def save(
        self,
        proposal_id=None,
        delete_proposals=None,
    ):
        update = super(forms.ModelForm, self).save(commit=False)
        update.plan = self.plan

        if delete_proposals is None:
            delete_proposals = []
        if proposal_id:
            proposals = self.get_proposals()
            proposal_user = proposals[proposal_id]["user"]
            proposal_user.send_mail(
                _("Your proposal for the plan “%s” was accepted") % self.plan.title,
                _(
                    "Hello,\n\nA moderator has accepted your proposal for an update to the plan "
                    "“{title}”. An update will be published soon.\n\nAll the Best,\n{site_name}"
                ).format(title=self.plan.title, site_name=settings.SITE_NAME),
                priority=False,
            )
            user_org = proposal_user.organization_set.all().first()
            if user_org:
                update.organization = user_org
            delete_proposals.append(proposal_id)

        self.delete_proposals(delete_proposals)
        update.save()
        return update

    def delete_proposals(self, delete_proposals):
        for pid in delete_proposals:
            if pid in self.plan.proposals:
                del self.plan.proposals[pid]
        if not self.plan.proposals:
            self.plan.proposals = None
        self.plan.save(update_fields=["proposals"])
