from crispy_forms.bootstrap import Alert
from apps.common.fields.forms.dynamic_select import DynamicModelChoiceField
from apps.common.widgets.crispy.daisyui import Switch
from apps.common.widgets.crispy.submit import NoClassSubmit
from apps.common.widgets.tom_select import TomSelect, TransactionSelect
from apps.rules.models import (
    TransactionRule,
    TransactionRuleAction,
    UpdateOrCreateTransactionRuleAction,
)
from apps.transactions.forms import BulkEditTransactionForm
from apps.transactions.models import Transaction
from crispy_forms.bootstrap import AccordionGroup, FormActions, Accordion
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Column, Field, Layout, Row
from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _


class TransactionRuleForm(forms.ModelForm):
    class Meta:
        model = TransactionRule
        fields = "__all__"
        exclude = ("owner", "shared_with", "visibility")
        labels = {
            "on_create": _("Run on creation"),
            "on_update": _("Run on update"),
            "on_delete": _("Run on delete"),
            "trigger": _("If..."),
        }
        widgets = {"description": forms.widgets.TextInput}

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

        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.form_method = "post"
        self.helper.layout = Layout(
            Switch("active"),
            "name",
            Row(
                Column(Switch("on_update")),
                Column(Switch("on_create")),
                Column(Switch("on_delete")),
            ),
            "order",
            Switch("sequenced"),
            "description",
            "trigger",
            Alert(
                _("You can add actions to this rule in the next screen."), dismiss=False
            ),
        )

        if self.instance and self.instance.pk:
            self.helper.layout.append(
                FormActions(
                    NoClassSubmit("submit", _("Update"), css_class="btn btn-primary"),
                ),
            )
        else:
            self.helper.layout.append(
                FormActions(
                    NoClassSubmit("submit", _("Add"), css_class="btn btn-primary"),
                ),
            )


class TransactionRuleActionForm(forms.ModelForm):
    class Meta:
        model = TransactionRuleAction
        fields = ("value", "field", "order")
        labels = {
            "field": _("Set field"),
            "value": _("To"),
            "order": _("Order"),
        }
        widgets = {"field": TomSelect(clear_button=False)}

    def __init__(self, *args, **kwargs):
        self.rule = kwargs.pop("rule", None)

        super().__init__(*args, **kwargs)

        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.form_method = "post"
        # TO-DO: Add helper with available commands
        self.helper.layout = Layout(
            "order",
            "field",
            "value",
        )

        if self.instance and self.instance.pk:
            self.helper.layout.append(
                FormActions(
                    NoClassSubmit("submit", _("Update"), css_class="btn btn-primary"),
                ),
            )
        else:
            self.helper.layout.append(
                FormActions(
                    NoClassSubmit("submit", _("Add"), css_class="btn btn-primary"),
                ),
            )

    def clean(self):
        cleaned_data = super().clean()
        field = cleaned_data.get("field")

        if field and self.rule:
            # Create a queryset that excludes the current instance
            existing_action = TransactionRuleAction.objects.filter(
                rule=self.rule, field=field
            )

            if self.instance.pk:
                existing_action = existing_action.exclude(pk=self.instance.pk)

            if existing_action.exists():
                raise ValidationError(
                    _("A value for this field already exists in the rule.")
                )

        return cleaned_data

    def save(self, commit=True):
        instance = super().save(commit=False)
        instance.rule = self.rule
        if commit:
            instance.save()
        return instance


class UpdateOrCreateTransactionRuleActionForm(forms.ModelForm):
    class Meta:
        model = UpdateOrCreateTransactionRuleAction
        exclude = ("rule",)
        widgets = {
            "search_account_operator": TomSelect(clear_button=False),
            "search_type_operator": TomSelect(clear_button=False),
            "search_is_paid_operator": TomSelect(clear_button=False),
            "search_date_operator": TomSelect(clear_button=False),
            "search_reference_date_operator": TomSelect(clear_button=False),
            "search_amount_operator": TomSelect(clear_button=False),
            "search_description_operator": TomSelect(clear_button=False),
            "search_notes_operator": TomSelect(clear_button=False),
            "search_category_operator": TomSelect(clear_button=False),
            "search_internal_note_operator": TomSelect(clear_button=False),
            "search_internal_id_operator": TomSelect(clear_button=False),
            "search_mute_operator": TomSelect(clear_button=False),
        }

        labels = {
            "order": _("Order"),
            "search_account_operator": _("Operator"),
            "search_type_operator": _("Operator"),
            "search_is_paid_operator": _("Operator"),
            "search_date_operator": _("Operator"),
            "search_reference_date_operator": _("Operator"),
            "search_amount_operator": _("Operator"),
            "search_description_operator": _("Operator"),
            "search_notes_operator": _("Operator"),
            "search_category_operator": _("Operator"),
            "search_internal_note_operator": _("Operator"),
            "search_internal_id_operator": _("Operator"),
            "search_tags_operator": _("Operator"),
            "search_entities_operator": _("Operator"),
            "search_mute_operator": _("Operator"),
            "search_account": _("Account"),
            "search_type": _("Type"),
            "search_is_paid": _("Paid"),
            "search_date": _("Date"),
            "search_reference_date": _("Reference Date"),
            "search_amount": _("Amount"),
            "search_description": _("Description"),
            "search_notes": _("Notes"),
            "search_category": _("Category"),
            "search_internal_note": _("Internal Note"),
            "search_internal_id": _("Internal ID"),
            "search_tags": _("Tags"),
            "search_entities": _("Entities"),
            "search_mute": _("Mute"),
            "set_account": _("Account"),
            "set_type": _("Type"),
            "set_is_paid": _("Paid"),
            "set_date": _("Date"),
            "set_reference_date": _("Reference Date"),
            "set_amount": _("Amount"),
            "set_description": _("Description"),
            "set_tags": _("Tags"),
            "set_entities": _("Entities"),
            "set_notes": _("Notes"),
            "set_category": _("Category"),
            "set_internal_note": _("Internal Note"),
            "set_internal_id": _("Internal ID"),
            "set_mute": _("Mute"),
        }

    def __init__(self, *args, **kwargs):
        self.rule = kwargs.pop("rule", None)
        super().__init__(*args, **kwargs)

        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.form_method = "post"

        self.helper.layout = Layout(
            "order",
            Accordion(
                AccordionGroup(
                    _("Search Criteria"),
                    Field("filter", rows=1),
                    Row(
                        Column(
                            Field("search_type_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_type", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_is_paid_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_is_paid", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_mute_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_mute", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_account_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_account", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_entities_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_entities", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_date_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_date", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_reference_date_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_reference_date", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_description_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_description", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_amount_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_amount", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_category_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_category", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_tags_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_tags", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_notes_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_notes", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_internal_note_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_internal_note", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    Row(
                        Column(
                            Field("search_internal_id_operator"),
                            css_class="col-span-12 md:col-span-4",
                        ),
                        Column(
                            Field("search_internal_id", rows=1),
                            css_class="col-span-12 md:col-span-8",
                        ),
                    ),
                    active=True,
                ),
                AccordionGroup(
                    _("Set Values"),
                    Field("set_type", rows=1),
                    Field("set_is_paid", rows=1),
                    Field("set_mute", rows=1),
                    Field("set_account", rows=1),
                    Field("set_entities", rows=1),
                    Field("set_date", rows=1),
                    Field("set_reference_date", rows=1),
                    Field("set_description", rows=1),
                    Field("set_amount", rows=1),
                    Field("set_category", rows=1),
                    Field("set_tags", rows=1),
                    Field("set_notes", rows=1),
                    Field("set_internal_note", rows=1),
                    Field("set_internal_id", rows=1),
                    css_class="mb-3",
                    active=True,
                ),
                always_open=True,
            ),
        )

        if self.instance and self.instance.pk:
            self.helper.layout.append(
                FormActions(
                    NoClassSubmit("submit", _("Update"), css_class="btn btn-primary"),
                ),
            )
        else:
            self.helper.layout.append(
                FormActions(
                    NoClassSubmit("submit", _("Add"), css_class="btn btn-primary"),
                ),
            )

    def save(self, commit=True):
        instance = super().save(commit=False)
        instance.rule = self.rule
        if commit:
            instance.save()
        return instance


class DryRunCreatedTransacion(forms.Form):
    transaction = DynamicModelChoiceField(
        model=Transaction,
        to_field_name="id",
        label=_("Transaction"),
        required=True,
        queryset=Transaction.objects.none(),
        widget=TransactionSelect(clear_button=False, income=True, expense=True),
        help_text=_("Type to search for a transaction"),
    )

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

        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.layout = Layout(
            "transaction",
            FormActions(
                NoClassSubmit("submit", _("Test"), css_class="btn btn-primary"),
            ),
        )

        if self.data.get("transaction"):
            try:
                transaction = Transaction.objects.get(id=self.data.get("transaction"))
            except Transaction.DoesNotExist:
                transaction = None

            if transaction:
                self.fields["transaction"].queryset = Transaction.objects.filter(
                    id=transaction.id
                )


class DryRunDeletedTransacion(forms.Form):
    transaction = DynamicModelChoiceField(
        model=Transaction,
        to_field_name="id",
        label=_("Transaction"),
        required=True,
        queryset=Transaction.objects.none(),
        widget=TransactionSelect(clear_button=False, income=True, expense=True),
        help_text=_("Type to search for a transaction"),
    )

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

        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.layout = Layout(
            "transaction",
            FormActions(
                NoClassSubmit("submit", _("Test"), css_class="btn btn-primary"),
            ),
        )

        if self.data.get("transaction"):
            try:
                transaction = Transaction.objects.get(id=self.data.get("transaction"))
            except Transaction.DoesNotExist:
                transaction = None

            if transaction:
                self.fields["transaction"].queryset = Transaction.objects.filter(
                    id=transaction.id
                )


class DryRunUpdatedTransactionForm(BulkEditTransactionForm):
    transaction = DynamicModelChoiceField(
        model=Transaction,
        to_field_name="id",
        label=_("Transaction"),
        required=True,
        queryset=Transaction.objects.none(),
        widget=TransactionSelect(clear_button=False, income=True, expense=True),
        help_text=_("Type to search for a transaction"),
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper.layout.insert(0, "transaction")
        self.helper.layout.insert(1, HTML('<hr class="hr my-3" />'))

        # Change submit button
        self.helper.layout[-1] = FormActions(
            NoClassSubmit("submit", _("Test"), css_class="btn btn-primary")
        )

        if self.data.get("transaction"):
            try:
                transaction = Transaction.objects.get(id=self.data.get("transaction"))
            except Transaction.DoesNotExist:
                transaction = None

            if transaction:
                self.fields["transaction"].queryset = Transaction.objects.filter(
                    id=transaction.id
                )
