import django_filters
from django import forms
from django.contrib.auth.models import User as django_user
from django.db.models import Q, IntegerField
from django.db.models.functions import Cast
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django_filters import CharFilter
from django_filters.filters import BooleanFilter
from rolepermissions.roles import retrieve_role

from accounts import crispy_layouts
from accounts.consts import FifaAccountPlatforms
from accounts.models import FifaAccount, PlayerCard, FifaAccountLog, FifaAccountCreditLog, Console, MuleAccounts, \
    FifaAccountWorkError, ItemPack
from futplus.roles import AnyRole
from trade.consts import ConsoleTradeOneQualityName
from utils.date_utils import normalize_month_range, get_filter_by_date_range_Q
from utils.date_utils.filters import DateTimePickerFilter
from utils.filters_fields import get_boolean_filter
from utils.select2_form_fields import Select2MultipleWidget, ModelSelect2Widget, Select2Widget


class UserListFilter(django_filters.FilterSet):
    class Meta:
        model = django_user
        fields = ['is_active']

        class form(forms.Form):
            helper = crispy_layouts.UserListFilterHelper()

    is_active = get_boolean_filter(label=_('Active'), field_name='is_active')
    role = django_filters.MultipleChoiceFilter(
        label=_('Role (include)'),
        method='filter__role',
        choices=[[r.get_name(), r.verbose_name] for r in AnyRole],
        widget=Select2MultipleWidget(
            attrs={
                'data-placeholder': _('Role ...'),
            },
        ),
    )
    role_not = django_filters.MultipleChoiceFilter(
        label=_('Role (exclude)'),
        method='filter__role_not',
        choices=[[r.get_name(), r.verbose_name] for r in AnyRole],
        widget=Select2MultipleWidget(
            attrs={
                'data-placeholder': _('Role ...'),
            },
        ),
    )

    def filter__full_name(self, queryset, field_name, filter_value):
        queryset = queryset.filter(
            Q(account__full_name__icontains=filter_value) |
            Q(username__icontains=filter_value)
        )
        return queryset

    def filter__role(self, queryset, field_name, filter_values):
        roles = [retrieve_role(value) for value in filter_values]
        if roles:
            queryset = queryset.filter(groups__name__in=[role.get_name() for role in roles]).distinct()
        return queryset

    def filter__role_not(self, queryset, field_name, filter_values):
        roles = [retrieve_role(value) for value in filter_values]
        if roles:
            queryset = queryset.exclude(groups__name__in=[role.get_name() for role in roles]).distinct()
        return queryset


class FifaAccountsFilter(django_filters.FilterSet):
    user_name = CharFilter(field_name='user_name', lookup_expr='iexact', label='User Name')
    pre_console = CharFilter(field_name='previous_console__name', lookup_expr='iexact', label='Pre-Console')
    console = CharFilter(field_name='console__name', lookup_expr='iexact', label='Console')
    exc_deleted = BooleanFilter(field_name='delete_console_reason', method='has_delete_console_reason',
                                label='Exc-Deleted')

    class Meta:
        model = FifaAccount
        fields = ['user_name', 'account_played_games', 'pre_console', 'console']

        class form(forms.Form):
            helper = crispy_layouts.FifaAccountsFilterHelper()


    def has_delete_console_reason(self, queryset, field_name, filter_values):
        if filter_values:
            queryset = queryset.filter(Q(delete_console_reason=None) | Q(delete_console_reason=''))
        return queryset

    # delete_club_renewal = get_boolean_filter(label=_('Delete Club Renewal'), field_name='delete_club_renewal')


class PlayerCardListFilter(django_filters.FilterSet):
    class Meta:
        model = PlayerCard
        fields = ['asset_id', 'rating', 'team', 'rare']

        class form(forms.Form):
            helper = crispy_layouts.PlayerCardListFilterHelper()


class FifaAccountLogsFilter(django_filters.FilterSet):
    des_contains = CharFilter(field_name='description', lookup_expr='icontains')

    class Meta:
        model = FifaAccountLog
        fields = ['des_contains', ]

        class form(forms.Form):
            helper = crispy_layouts.FifaAccountLogsFilterHelper()


class SystemLogsFilter(django_filters.FilterSet):
    des_contains = CharFilter(field_name='description', lookup_expr='icontains')

    class Meta:
        model = FifaAccountLog
        fields = ['des_contains', ]

        class form(forms.Form):
            helper = crispy_layouts.FifaAccountLogsFilterHelper()


class ConsoleListFilter(django_filters.FilterSet):
    range_number = django_filters.RangeFilter(field_name='name')

    class Meta:
        fields = ['range_number']

        class form(forms.Form):
            helper = crispy_layouts.ConsoleListFilterHelper()


class PCListFilter(django_filters.FilterSet):
    range_number = django_filters.RangeFilter(field_name='pc_name_int', label='Name Range')

    class Meta:
        fields = ['range_number']

        class form(forms.Form):
            helper = crispy_layouts.ConsoleListFilterHelper()

    def filter_queryset(self, queryset):
        query = queryset.annotate(
            pc_name_int=Cast('pc__name', output_field=IntegerField())
        )
        return super().filter_queryset(query)


class DailyCreditGeneratedReportFilterSet(django_filters.FilterSet):
    # TODO: sync it with MonthlySaleForecastReportFilterSet
    class Meta:
        model = FifaAccountCreditLog
        fields = []

        class form(forms.Form):  # exact this name :)
            helper = crispy_layouts.DailyCreditGeneratedReportFilterSetHelper()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    investor = django_filters.ModelChoiceFilter(
        queryset=django_user.objects.filter(user_permissions__codename='is_investor'),
        label='Investor',
        method='investor__equal'
    )
    exclude_investor = django_filters.ModelChoiceFilter(
        queryset=django_user.objects.filter(user_permissions__codename='is_investor'),
        label='Exc-Investor',
        method='investor__not_equal'
    )
    # start_date = DateTimeFilter(
    #     label=_('From date'), field_name='create_time', method='filter__date',
    #     initial=(lambda: normalize_month_range(start_date=timezone.localtime() - timezone.timedelta(days=31),
    #                                            future_months=0)[0]),
    # )
    # end_date = DateTimeFilter(
    #     label=_('To date'), field_name='create_time', method='filter__date',
    #     initial=(lambda: normalize_month_range(future_months=0)[1]),
    # )
    previous_console = django_filters.ModelChoiceFilter(
        queryset=Console.objects.all().order_by('name'),
        label='Pre-Console',
        method='previous_console__equal',
        widget=Select2Widget,
        # widget=ModelSelect2Widget(
        #     queryset=Console.objects.all(),
        #     search_fields=['name__contains'])
    )
    console = django_filters.ModelChoiceFilter(
        queryset=Console.objects.all().order_by('name'),
        label='Console',
        method='console__equal',
        widget=Select2Widget,
        # widget=ModelSelect2Widget(
        #     queryset=Console.objects.all(),
        #     search_fields=['name__contains'])
    )
    fifa_account = django_filters.ModelChoiceFilter(
        queryset=FifaAccount.objects.all(),
        label='Fifa Account',
        method='fifa_account__equal',
        widget=ModelSelect2Widget(
            queryset=FifaAccount.objects.all(),
            search_fields=['user_name__contains'])

    )
    quality_name = django_filters.CharFilter(
        label='Quality',
        method='quality__equal',
        widget=Select2Widget(
            choices=ConsoleTradeOneQualityName,
            attrs={
                'data-placeholder': _('------'),
            },
        )
    )

    period_time = django_filters.CharFilter(
        label='Period',
        method='fake_filter',
        widget=Select2Widget(
            choices=(
                ('daily', 'Daily'),
            ),
            attrs={
                'data-placeholder': _('------'),
            },
        )
    )

    start_date = DateTimePickerFilter(
        required=False,
        label=_('From date'), field_name='create_time', method='filter__date',
        initial=(lambda: normalize_month_range(
            start_date=timezone.localtime() - timezone.timedelta(days=31),
            future_months=2)[0]),
    )
    end_date = DateTimePickerFilter(
        required=False,
        label=_('To date'), field_name='create_time', method='filter__date',
        initial=(lambda: normalize_month_range(future_months=0)[1]),
    )

    def investor__equal(self, queryset, name, value, *args, **kwargs):
        if value:
            queryset = queryset.filter(fifa_account__console__investor=value)
        return queryset

    def investor__not_equal(self, queryset, name, value, *args, **kwargs):
        if value:
            queryset = queryset.exclude(fifa_account__console__investor=value)
        return queryset

    def previous_console__equal(self, queryset, name, value, *args, **kwargs):
        if value:
            queryset = queryset.filter(fifa_account__previous_console=value)
        return queryset

    def console__equal(self, queryset, name, value, *args, **kwargs):
        if value:
            queryset = queryset.filter(fifa_account__console=value)
        return queryset

    def fifa_account__equal(self, queryset, name, value, *args, **kwargs):
        if value:
            queryset = queryset.filter(fifa_account=value)
        return queryset

    def quality__equal(self, queryset, name, value, *args, **kwargs):
        if value:
            queryset = queryset.filter(fifa_account__console_trade_one_quality=value)
        return queryset

    def filter__date(self, queryset, field_name, filter_value, *args, **kwargs):
        if filter_value and not getattr(self.form, f'__filter_by_{field_name}', None):
            setattr(self.form, f'__filter_by_{field_name}', True)
            c = self.form.cleaned_data
            date_range_Q = get_filter_by_date_range_Q(
                field_name, start_date=c.get('start_date'), end_date=c.get('end_date'))
            queryset = queryset.filter(date_range_Q)
        return queryset

    def fake_filter(self, queryset, field_name, filter_value, *args, **kwargs):
        return queryset


class MuleAccountsListFilter(django_filters.FilterSet):
    exclude_investor = django_filters.ModelChoiceFilter(
        queryset=django_user.objects.filter(user_permissions__codename='is_investor'),
        label='Exc-Investor',
        method='investor__not_equal',
        widget=Select2Widget,
    )
    is_deleted = django_filters.BooleanFilter(
        field_name='deleted', label='Deactive',
        widget=Select2Widget(
            choices=[
                (True, _('DeActive')),
                (False, _('Active')),
            ],
            attrs={
                'data-placeholder': _('------'),
            },
        )
    )
    fifa_account_platform = django_filters.MultipleChoiceFilter(
        choices=FifaAccountPlatforms,
        required=False,
        field_name='fifa_account__platform',
        lookup_expr='iexact',
        widget=Select2MultipleWidget,
    )

    def investor__not_equal(self, queryset, name, value, *args, **kwargs):
        if value:
            queryset = queryset.exclude(investors__in=[value])
        return queryset

    class Meta:
        model = MuleAccounts
        fields = ['exclude_investor']

        class form(forms.Form):
            helper = crispy_layouts.MuleAccountsListFilterHelper()


class FifaAccountWorkErrorListFilterSet(django_filters.FilterSet):
    console = CharFilter(field_name='fifa_account__console__name', lookup_expr='iexact', label='Console')
    fifa_account = CharFilter(field_name='fifa_account__user_name', lookup_expr='iexact', label='User Name')
    solve_status_f = django_filters.CharFilter(
        label='Solve Status',
        method='status__equal',
        widget=Select2Widget(
            choices=(('-', 'Not Solved'), ('solved', 'Solved')),
            attrs={
                'data-placeholder': _('------'),
            },
        )
    )

    def status__equal(self, queryset, name, value, *args, **kwargs):
        if value == '-':
            queryset = queryset.filter(Q(solve_status='') | Q(solve_status=None))
        elif value:
            queryset = queryset.filter(solve_status=value)
        return queryset

    class Meta:
        model = FifaAccountWorkError
        fields = []

        class form(forms.Form):  # exact this name :)
            helper = crispy_layouts.FifaAccountWorkErrorListFilterSetHelper()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)


class FifaAccountDetailWorkerErrorListFilterSet(django_filters.FilterSet):
    class Meta:
        model = FifaAccountWorkError
        fields = []

        class form(forms.Form):  # exact this name :)
            helper = crispy_layouts.FifaAccountDetailWorkerErrorListFilterSetHelper()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    console = CharFilter(field_name='fifa_account__console__name', lookup_expr='iexact', label='Console')
    fifa_account = CharFilter(field_name='fifa_account__user_name', lookup_expr='iexact', label='User Name')
    solve_status_f = django_filters.CharFilter(
        label='Solve Status',
        method='status__equal',
        widget=Select2Widget(
            choices=(('-', 'Not Solved'), ('solved', 'Solved')),
            attrs={
                'data-placeholder': _('------'),
            },
        )
    )

    def status__equal(self, queryset, name, value, *args, **kwargs):
        if value == '-':
            queryset = queryset.filter(Q(solve_status='') | Q(solve_status=None))
        elif value:
            queryset = queryset.filter(solve_status=value)
        return queryset


class ItemPackChartReportFilterSet(DailyCreditGeneratedReportFilterSet):
    class Meta:
        model = ItemPack
        fields = []

        class form(forms.Form):  # exact this name :)
            helper = crispy_layouts.DailyCreditGeneratedReportFilterSetHelper()

    quality_name = django_filters.CharFilter(
        label='Pack Id',
        method='id__equal',
    )

    period_time = django_filters.CharFilter(
        label='Period',
        method='fake_filter',
        widget=Select2Widget(
            choices=(
                (2, '2 Hour'),
                (4, '4 Hour'),
                (12, '12 Hour'),
            ),
            attrs={
                'data-placeholder': _('------'),
            },
        )
    )

    def id__equal(self, queryset, name, value, *args, **kwargs):
        if value:
            queryset = queryset.filter(pack_id=int(value))
        return queryset

    def fake_filter(self, queryset, field_name, filter_value, *args, **kwargs):
        return queryset