import django_filters
from django import forms
from django.contrib.auth.models import User as django_user
from django.db.models import F, Case, When, IntegerField, Value, OuterRef, Subquery
from django.db.models.functions import Coalesce
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from accounts.models import FifaAccount, Console
from trade import crispy_layouts
from trade.consts import ConsoleTradeOneQualityName
from trade.models import ConsoleTradeOneQuality, ConsoleTradeInvestDailyProfitLog, ConsoleTradeOneHistory
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 ModelSelect2Widget, Select2Widget


class ConsoleTradeQualityReportFilterSet(django_filters.FilterSet):
    class Meta:
        model = ConsoleTradeOneQuality
        fields = []

        class form(forms.Form):  # exact this name :)
            helper = crispy_layouts.ConsoleTradeQualityReportFilterSetHelper()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    start_date = DateTimePickerFilter(
        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 = DateTimePickerFilter(
        label=_('To date'), field_name='create_time', method='filter__date',
        initial=(lambda: normalize_month_range(future_months=0)[1]),
    )

    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


class DailyInvestTradeGenerateReportFilterSet(django_filters.FilterSet):
    class Meta:
        model = ConsoleTradeInvestDailyProfitLog
        fields = []

        class form(forms.Form):  # exact this name :)
            helper = crispy_layouts.DailyInvestTradeGenerateReportFilterSetHelper()

    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',
        widget=Select2Widget,
    )
    exclude_investor = django_filters.ModelChoiceFilter(
        queryset=django_user.objects.filter(user_permissions__codename='is_investor'),
        label='Exc-Investor',
        method='investor__not_equal',
        widget=Select2Widget,
    )
    start_date = DateTimePickerFilter(
        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 = DateTimePickerFilter(
        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 = django_filters.CharFilter(
        label='Quality',
        method='quality__equal',
        widget=Select2Widget(
            choices=ConsoleTradeOneQualityName,
            attrs={
                'data-placeholder': _('------'),
            },
        )
    )

    # start_date = DatePickerFilter(
    #     label=_('From date'), field_name='date', method='filter__date',
    #     initial=(lambda: normalize_month_range(future_months=3)[0]),
    # )
    # end_date = DatePickerFilter(
    #     label=_('To date'), field_name='date', method='filter__date',
    #     initial=(lambda: normalize_month_range(future_months=3)[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(quality_name=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


class ConsoleInvestTradeFilterSet(django_filters.FilterSet):
    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.CharFilter(
        # queryset=FifaAccount.objects.all(),
        label='Fifa Account',
        method='fifa_account__user_name__equal',
        # widget=ModelSelect2Widget(
        #     queryset=FifaAccount.objects.all(),
        #     search_fields=['user_name__contains'])

    )
    completed = get_boolean_filter(label=_('Completed'), field_name='end_time', method='check_completed', )

    class Meta:
        model = ConsoleTradeOneHistory
        fields = ['quality_name']

        class form(forms.Form):  # exact this name :)
            helper = crispy_layouts.ConsoleInvestTradeFilterSetHelper()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def console__equal(self, queryset, name, value, *args, **kwargs):
        if value:
            queryset = queryset.filter(fifa_account__console=value)
        return queryset

    def fifa_account__user_name__equal(self, queryset, name, value, *args, **kwargs):
        if value:
            queryset = queryset.filter(fifa_account__user_name=value)
        return queryset

    def check_completed(self, queryset, name, value, *args, **kwargs):
        if value:
            queryset = queryset.exclude(end_time=None)
        return queryset


class ConsoleInvestChangeQualityFilterSet(django_filters.FilterSet):
    current_quality = django_filters.CharFilter(
        label='Quality',
        method='quality__equal',
        widget=Select2Widget(
            choices=(('None', 'None Quality'), ) + ConsoleTradeOneQualityName,
            attrs={
                'data-placeholder': _('------'),
            },
        )
    )
    console_start_number = django_filters.NumberFilter(
        label='Console Start',
        field_name='console__name',
        lookup_expr='gte'
    )
    console_end_number = django_filters.NumberFilter(
        label='Console End',
        field_name='console__name',
        lookup_expr='lt'
    )
    stock_bronze1_less = django_filters.NumberFilter(
        label=_('Bronze1 Less'), method='stock_less__func', field_name='bronze1')
    stock_bronze1_greater = django_filters.NumberFilter(
        label=_('Bronze1 Greater'), method='stock_greater__func', field_name='bronze1')
    stock_silver0_less = django_filters.NumberFilter(
        label=_('Silver0 less'), method='stock_less__func', field_name='silver0')
    stock_silver0_greater = django_filters.NumberFilter(
        label=_('Silver0 greater'), method='stock_greater__func', field_name='silver0')
    stock_silver1_less = django_filters.NumberFilter(
        label=_('Silver1 less'), method='stock_less__func', field_name='silver1')
    stock_silver1_greater = django_filters.NumberFilter(
        label=_('Silver1 greater'), method='stock_greater__func', field_name='silver1')
    stock_gold0_less = django_filters.NumberFilter(
        label=_('Gold0 Less'), method='stock_less__func', field_name='gold0')
    stock_gold0_greater = django_filters.NumberFilter(
        label=_('Gold0 Greater'), method='stock_greater__func', field_name='gold0')
    stock_gold1_less = django_filters.NumberFilter(
        label=_('Gold1 Less'), method='stock_less__func', field_name='gold1')
    stock_gold1_greater = django_filters.NumberFilter(
        label=_('Gold1 Greater'), method='stock_greater__func', field_name='gold1')
    stock_position_modifier_less = django_filters.NumberFilter(
        label=_('Position_modifier Less'), method='stock_less__func', field_name='position_modifier')
    stock_position_modifier_greater = django_filters.NumberFilter(
        label=_('Position_modifier Greater'), method='stock_greater__func', field_name='position_modifier')

    class Meta:
        model = FifaAccount
        fields = []

        class form(forms.Form):  # exact this name :)
            helper = crispy_layouts.ConsoleInvestChangeQualityFilterSetHelper()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.form.initial['stock_bronze1_less'] = -1
        self.form.initial['stock_bronze1_greater'] = -1
        self.form.initial['stock_silver0_less'] = -1
        self.form.initial['stock_silver0_greater'] = -1
        self.form.initial['stock_silver1_less'] = -1
        self.form.initial['stock_silver1_greater'] = -1
        self.form.initial['stock_gold0_less'] = -1
        self.form.initial['stock_gold0_greater'] = -1
        self.form.initial['stock_gold1_less'] = -1
        self.form.initial['stock_gold1_greater'] = -1
        self.form.initial['stock_position_modifier_less'] = -1
        self.form.initial['stock_position_modifier_greater'] = -1

    def quality__equal(self, queryset, name, value, *args, **kwargs):
        if value == 'None':
            value = None
            queryset = queryset.filter(console_trade_one_quality=value)
        if value:
            queryset = queryset.filter(console_trade_one_quality=value)
        return queryset

    def stock_less__func(self, queryset, name, value, *args, **kwargs):
        if value >= 0:
            queryset = queryset.filter(
                last_trade_history_id__gt=0
            ).annotate(**{f'stock_{name}_items': Coalesce(Subquery(ConsoleTradeOneHistory.objects.filter(
                id=OuterRef('last_trade_history_id'),
                # quality_name=name,
            ).annotate(
                stock=Case(
                    When(quality_name=f'{name}', then=F('transfer_list_items_count') + F(f'club_{name}_items')),
                    default=F(f'club_{name}_items'),
                    output_field=IntegerField()),
            ).values_list('stock', flat=True), output_field=IntegerField()), Value(0)),
                          }).filter(**{f'stock_{name}_items__lt': value})
            # a = ConsoleTradeOneHistory.objects.filter(
            #     id__in=queryset.values_list('last_trade_history_id', flat=True),
            #     # quality_name=name,
            # ).annotate(
            #     stock=Case(
            #         When(quality_name=f'{name}', then=F('transfer_list_items_count') + F(f'club_{name}_items')),
            #         default=F(f'club_{name}_items'),
            #         output_field=IntegerField()),
            #
            # ).filter(**{f'stock__lt': value}).values_list('id', flat=True)
            # queryset = queryset.filter(last_trade_history_id__in=a)
        return queryset

    def stock_greater__func(self, queryset, name, value, *args, **kwargs):
        if value >= 0:
            queryset = queryset.filter(
                last_trade_history_id__gt=0
            ).annotate(**{f'stock_{name}_items': Coalesce(Subquery(ConsoleTradeOneHistory.objects.filter(
                id=OuterRef('last_trade_history_id'),
                # quality_name=name,
            ).annotate(
                stock=Case(
                    When(quality_name=f'{name}', then=F('transfer_list_items_count') + F(f'club_{name}_items')),
                    default=F(f'club_{name}_items'),
                    output_field=IntegerField()),
            ).values_list('stock', flat=True), output_field=IntegerField()), Value(0)),
                          }).filter(**{f'stock_{name}_items__gt': value})
            # queryset = queryset.filter(last_trade_history_id__gt=0)
            # a = ConsoleTradeOneHistory.objects.filter(
            #     id__in=queryset.values_list('last_trade_history_id', flat=True),
            #     # quality_name=name,
            # ).annotate(
            #     stock=Case(
            #         When(quality_name=f'{name}', then=F('transfer_list_items_count') + F(f'club_{name}_items')),
            #         default=F(f'club_{name}_items'),
            #         output_field=IntegerField()),
            #
            # ).filter(**{f'stock__gt': value}).values_list('id', flat=True)
            # queryset = queryset.filter(last_trade_history_id__in=a)
        return queryset
