import openpyxl
import statistics
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import F, Sum, CharField, Value, Case, When, Subquery, OuterRef, Count, FloatField, Q, \
    IntegerField, ExpressionWrapper
from django.db.models.functions import Cast, Concat
from django.http import HttpResponse
from django.shortcuts import render, redirect
# Create your views here.
from django.urls import reverse_lazy
from django.utils import timezone
from django.views import View
from django.views.generic import TemplateView
from django_filters.views import FilterView
from openpyxl import Workbook
from openpyxl.utils import get_column_letter
from openpyxl.worksheet.datavalidation import DataValidation

from accounts.models import FifaAccount, FifaAccountBackupCode, CloseWebAppSnipes, ConsoleBotSetting, \
    CloseWebAppTransfers, TelegramMessage
from customrolepermissions.mixins import RequiredPermissionViewMixin
from customrolepermissions.permissions import has_permission_exactly
from futplus.celery_conf import app
from sniper.dashboard_cards import DischargePerDayLogChartDashboardCard
from sniper.filters import DischargeWithSnipeLogListFilter, DischargeMode2LogListFilter, DischargePerDayLogListFilter, \
    DischargeMode3LogListFilter
from sniper.models import SniperOrder, SniperAccount, SniperTradeItemLog, DischargeMode2, DischargePerDay
from sniper.tables import SniperOrdersTable, DischargeWithSnipeLogListTable, DischargeMode2LogListTable, \
    DischargePerDayLogListTable, DischargeMode3LogListTable
from utils import number_convertor_to_milion
from utils.dashboard_cards import DashboardLayout, DashboardRow
from utils.views import GenericListView, GenericFilterListView, BackUrlMixin



class SniperAddFile(LoginRequiredMixin, TemplateView):
    template_name = 'sbc/add_sbc_file.html'
    page_header = 'Add Sniper File'

    def get_extra_buttons(self):
        buttons = []
        url = f'{self.request.path}?download_example=true'
        buttons.append({
            'url': url,
            'text': 'Download Example',
            'color': 'btn-info'

        })
        return buttons

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['columns'] = ['Email                                 ',
                         'Password                              ', 'Platform',
                         'App Code                      ',
                         'Backup Code                            ', 'Amount(k)', 'Receiver', 'Coins To(k)',
                         'Need Proof', 'Empty To coins_to']
        return context


    def get(self, request, *args, **kwargs):
        context = super().get(request, *args, **kwargs)
        excel_headers = ['Email                                 ',
                         'Password                              ', 'Platform',
                         'App Code                      ',
                         'Backup Code                            ', 'Amount(k)', 'Receiver', 'Coins To(k)',
                         'Need Proof', 'Empty To coins_to']
        if request.GET.get('download_example'):
            response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
            response['Content-Disposition'] = f'attachment; filename="sniper_example.xlsx"'
            wb = Workbook()
            ws = wb.active

            ws.append(excel_headers)
            platform_validation = DataValidation(type="list", formula1='"xboxs,xbox360,ps4,ps5"', showDropDown=False)
            receiver_validation = DataValidation(type="list", formula1='"0,1"', showDropDown=False)
            proof_validation = DataValidation(type="list", formula1='"0,1"', showDropDown=False)
            ws.add_data_validation(platform_validation)
            ws.add_data_validation(receiver_validation)
            ws.add_data_validation(proof_validation)
            for i, header in enumerate(excel_headers, start=1):
                col_letter = get_column_letter(i)
                ws.column_dimensions[col_letter].width = max(len(header), 10)

            for i in range(10):
                row_index = i + 2
                ws.append(["" for _ in excel_headers])
                platform_validation.add(ws[f"C{row_index}"])
                receiver_validation.add(ws[f"G{row_index}"])
                proof_validation.add(ws[f"I{row_index}"])
            wb.save(response)
            return response
        return context

    def post(self, request, *args, **kwargs):
        sbc_file = request.FILES.get('file')
        if not sbc_file:
            messages.add_message(self.request, messages.ERROR, f'No file uploaded')
            return render(request, 'sbc/add_sbc_file.html')
        sniper_order = SniperOrder.objects.create(creator=request.user, file_name=sbc_file.name, status=1)
        wb_obj = openpyxl.load_workbook(sbc_file)
        sheet_obj = wb_obj.active
        max_row = sheet_obj.max_row
        for i in range(2, max_row + 1):
            ea_email = sheet_obj.cell(row=i, column=1).value
            ea_pass = sheet_obj.cell(row=i, column=2).value
            platform = sheet_obj.cell(row=i, column=3).value or 'ps4'
            app_code = sheet_obj.cell(row=i, column=4).value or ''
            backup_code = sheet_obj.cell(row=i, column=5).value or ''
            amount = (sheet_obj.cell(row=i, column=6).value or 0) * 1000
            receiver = sheet_obj.cell(row=i, column=7).value
            coin_to = (sheet_obj.cell(row=i, column=8).value or 0) * 1000
            need_proof = sheet_obj.cell(row=i, column=9).value or 0
            empty_to_coins_to = sheet_obj.cell(row=i, column=10).value or 0
            if ea_email:
                fifa_account, created = FifaAccount.objects.get_or_create(
                    user_name=ea_email
                )
                if fifa_account.platform in ['', None]:
                    fifa_account.platform = platform
                if not fifa_account.creator:
                    fifa_account.creator = request.user
                if ea_pass:
                    fifa_account.password = ea_pass
                fifa_account.save()

                if app_code or backup_code:
                    account_backup, created = FifaAccountBackupCode.objects.get_or_create(fifa_account=fifa_account)
                    if app_code:
                        account_backup.app_code = app_code
                    if backup_code:
                        account_backup.backup_code = backup_code
                    account_backup.save()

                SniperAccount.objects.get_or_create(
                    sniper_order=sniper_order, fifa_account=fifa_account, transfer_to=coin_to,
                    last_run_time=timezone.localtime() - timezone.timedelta(minutes=5),
                    receiver=receiver, need_proof=need_proof,
                    transfer_amount=amount, empty_size_transfer_limit=empty_to_coins_to
                )

        messages.success(request, "Sniper File Added")
        return redirect(reverse_lazy('sniper-add-file'))
        # return render(request, 'sbc/add_sbc_file.html')


@login_required
def sniper_add_file(request):
    if request.method == 'POST':
        sbc_file = request.FILES.get('file')
        sniper_order = SniperOrder.objects.create(creator=request.user, file_name=sbc_file.name, status=1)
        wb_obj = openpyxl.load_workbook(sbc_file)
        sheet_obj = wb_obj.active
        max_row = sheet_obj.max_row
        for i in range(2, max_row + 1):
            ea_email = sheet_obj.cell(row=i, column=1).value
            ea_pass = sheet_obj.cell(row=i, column=2).value
            app_code = sheet_obj.cell(row=i, column=3).value
            coin_to = sheet_obj.cell(row=i, column=4).value or 0
            receiver = sheet_obj.cell(row=i, column=5).value
            try:
                backup_code = sheet_obj.cell(row=i, column=7).value or ''
            except:
                backup_code = ''
            try:
                need_proof = sheet_obj.cell(row=i, column=8).value or 0
            except:
                need_proof = 0
            try:
                transfer_coin = sheet_obj.cell(row=i, column=9).value or 0
            except:
                transfer_coin = 0
            try:
                platform = sheet_obj.cell(row=i, column=10).value or 'ps'
            except:
                platform = 'ps'
            try:
                empty_to_coins_to = sheet_obj.cell(row=i, column=11).value or 0
            except:
                empty_to_coins_to = 0

            if ea_email:
                fifa_account, created = FifaAccount.objects.get_or_create(
                    user_name=ea_email
                )
                if fifa_account.platform in ['', None]:
                    fifa_account.platform = platform
                if not fifa_account.creator:
                    fifa_account.creator = request.user
                if ea_pass:
                    fifa_account.password = ea_pass
                fifa_account.save()

                account_backup, created = FifaAccountBackupCode.objects.get_or_create(fifa_account=fifa_account)
                account_backup.app_code = app_code
                account_backup.backup_code = backup_code
                account_backup.save()
                SniperAccount.objects.get_or_create(
                    sniper_order=sniper_order, fifa_account=fifa_account, transfer_to=coin_to,
                    last_run_time=timezone.localtime() - timezone.timedelta(minutes=5),
                    receiver=receiver, need_proof=need_proof,
                    transfer_amount=transfer_coin, empty_size_transfer_limit=empty_to_coins_to
                )

        messages.success(request, "Sniper File Added")
        return render(request, 'sbc/add_sbc_file.html')
    else:
        return render(request, 'sbc/add_sbc_file.html',
                      {'page_header': 'Add Sniper File',
                       'columns': ['Email', 'Password', 'App Code', 'Coin To', 'Receiver', 'Null',
                                   'Backup Code', 'Need Proof', 'Transfer Coin', 'Platform',
                                   'Empty To coins_to'],
                       })


class SniperOrdersListView(RequiredPermissionViewMixin, GenericListView):
    required_permission__ = 'sniper_workers__read'
    model = SniperOrder
    table_class = SniperOrdersTable

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)

    def get_table_data(self):
        query = self.get_queryset()
        price_taken_subquery = SniperTradeItemLog.objects.filter(
            sniper_account__sniper_order=OuterRef('pk'),
        ).annotate(
            price_taken=ExpressionWrapper(
                F('price') - (F('buy_now_price') - (F('buy_now_price') * 0.05)),
                output_field=FloatField()
            )
        ).values('sniper_account__sniper_order').annotate(
            total=Sum('price_taken')
        ).values('total')[:1]

        # Subquery برای total_price_receiver (سود خالص برگشتی به مشتری)
        receiver_income_subquery = SniperTradeItemLog.objects.filter(
            sniper_account__sniper_order=OuterRef('pk'),
            sniper_account__receiver=1,
            status=1
        ).annotate(
            price_receiver=ExpressionWrapper(
                (F('price') - (F('price') * 0.05)) - F('buy_now_price'),
                output_field=FloatField()
            )
        ).values('sniper_account__sniper_order').annotate(
            total=Sum('price_receiver')
        ).values('total')[:1]
        query = query.annotate(
            sum_accounts=Count('sniperaccount', distinct=True),
            sum_senders_success=Count(
                'sniperaccount',
                filter=Q(sniperaccount__receiver=0, sniperaccount__is_done=1),
                distinct=True
            ),
            sum_receivers_success=Count(
                'sniperaccount',
                filter=Q(sniperaccount__receiver=1, sniperaccount__is_done=1),
                distinct=True
            ),
            sum_fail=Count(
                'sniperaccount',
                filter=Q(sniperaccount__has_error=1),
                distinct=True
            ),
            sum_success=Count(
                'sniperaccount',
                filter=Q(sniperaccount__is_done=1, sniperaccount__has_error=0),
                distinct=True
            ),

            sum_price_taken=Subquery(price_taken_subquery, output_field=FloatField()),
            total_price_receiver=Subquery(receiver_income_subquery, output_field=FloatField()),
        ).annotate(
            miss_and_tax=ExpressionWrapper(
                100 - (F('total_price_receiver') / F('sum_price_taken') * 100),
                output_field=FloatField()
            )
        )
        return query


@login_required
def sniper_orders_excel(request, order_id):
    order = SniperOrder.objects.get(id=order_id)
    response = HttpResponse(content_type='application/vnd.ms-excel')
    response['Content-Disposition'] = f'attachment; filename="download_{order.file_name}"'
    wb = Workbook()
    ws = wb.active
    worker_list = SniperAccount.objects.filter(sniper_order__id=order_id).order_by('id')
    ws.append(
        ['user name', 'password', 'platform', 'is receiver', 'app code', 'backup code', 'search number',
         'coins before', 'current coin', 'coins to', 'coins taken', 'empty to coins taken',
         'active', 'is done', 'has error', 'error description', 'price taken', 'final coins', 'miss and tax'])
    for item in worker_list:
        price_taken, final_transfers, miss_and_tax = 0, 0, 0
        if item.receiver == 1:
            sniper_logs = SniperTradeItemLog.objects.filter(sniper_account_id=item.id).annotate(
                price_taken=F('price') - (F('buy_now_price') - (F('buy_now_price') * 0.05)),
            ).aggregate(
                sum_price_taken=Sum('price_taken'),
            )
            final_transfers = SniperTradeItemLog.objects.filter(sniper_account_id=item.id, status=1).annotate(
                price_receiver=(F('price') - (F('price') * 0.05)) - F('buy_now_price')
            ).aggregate(
                sum_price_receiver=Sum('price_receiver'),
            )
            price_taken = sniper_logs.get('sum_price_taken')
            final_transfers = final_transfers.get('sum_price_receiver')
            if final_transfers and price_taken:
                miss_and_tax = 100 - (final_transfers / price_taken * 100)
        ws.append([item.fifa_account.user_name, item.fifa_account.password, item.fifa_account.platform,
                   item.receiver,
                   item.fifa_account.account_backup_code.last().app_code,
                   item.fifa_account.account_backup_code.last().backup_code,
                   item.fifa_account.account_search.filter(
                       search_time__gt=timezone.localtime() - timezone.timedelta(hours=24)).count(),
                   item.coins_before, item.fifa_account.credit, item.transfer_to, item.coins_taken,
                   item.empty_size_transfer_limit, item.fifa_account.active,
                   item.is_done, item.has_error, item.error_description, price_taken, final_transfers, miss_and_tax
                   ])
    wb.save(response)
    return response


class CancelOrder(LoginRequiredMixin, View):
    def get(self, request, *args, **kwargs):
        order = SniperOrder.objects.get(id=kwargs.get('order_id'))
        sniper_workers = SniperAccount.objects.filter(sniper_order=order, is_done=False, has_error=False)
        for sniper_worker in sniper_workers:
            sniper_worker.has_error = True
            sniper_worker.must_done = True
            sniper_worker.error_description = 'manual deactivated'
            sniper_worker.save()
            try:
                app.control.revoke(sniper_worker.task_id, terminate=True, signal='SIGKILL')
            except:
                pass
            sniper_worker.fifa_account.active = False
            sniper_worker.fifa_account.login_status = 0
            sniper_worker.fifa_account.driver = False
            sniper_worker.fifa_account.save()

        messages.add_message(self.request, messages.SUCCESS, 'Successful stopped')
        return redirect(reverse_lazy('sniper-orders-list'))


class DischargeWithSnipeLogListView(RequiredPermissionViewMixin, GenericFilterListView):
    required_permission__all = 'discharge__read__all'
    model = CloseWebAppSnipes
    table_class = DischargeWithSnipeLogListTable
    filterset_class = DischargeWithSnipeLogListFilter

    def get_card_data(self):
        cards_data = []
        miss_and_tax_24_hour = miss_and_tax_7_days = miss_and_tax_31_days = 0
        query = self.get_queryset()
        query = query.filter(
            Q(error_desc__isnull=True) |
            Q(error_desc='') |
            Q(error_desc='missed')
        )
        price_taken_24_hour = query.filter(
            insert_time__gt=timezone.localtime() - timezone.timedelta(hours=24)
        ).annotate(
            price_taken=F('player_price') - (
                    F('player_min_price_from_futbin') - (F('player_min_price_from_futbin') * 0.05)),
        ).aggregate(
            sum_price_taken=Sum('price_taken'),
        ).get('sum_price_taken')
        final_transfers_24_hour = query.filter(
            insert_time__gt=timezone.localtime() - timezone.timedelta(hours=24)
        ).exclude(winner_account=None).annotate(
            price_receiver=(F('player_price') - (F('player_price') * 0.05)) - F('player_min_price_from_futbin')
        ).aggregate(
            sum_price_receiver=Sum('price_receiver'),
        ).get('sum_price_receiver')
        if final_transfers_24_hour and price_taken_24_hour:
            miss_and_tax_24_hour = 100 - (final_transfers_24_hour / price_taken_24_hour * 100)
        # --------------------- #
        price_taken_7_days = query.filter(
            insert_time__gt=timezone.localtime() - timezone.timedelta(days=7)
        ).annotate(
            price_taken=F('player_price') - (
                    F('player_min_price_from_futbin') - (F('player_min_price_from_futbin') * 0.05)),
        ).aggregate(
            sum_price_taken=Sum('price_taken'),
        ).get('sum_price_taken')
        final_transfers_7_days = query.filter(
            insert_time__gt=timezone.localtime() - timezone.timedelta(days=7)
        ).exclude(winner_account=None).annotate(
            price_receiver=(F('player_price') - (F('player_price') * 0.05)) - F('player_min_price_from_futbin')
        ).aggregate(
            sum_price_receiver=Sum('price_receiver'),
        ).get('sum_price_receiver')
        if final_transfers_7_days and price_taken_7_days:
            miss_and_tax_7_days = 100 - (final_transfers_7_days / price_taken_7_days * 100)
        # --------------------- #
        price_taken_31_days = query.filter(
            insert_time__gt=timezone.localtime() - timezone.timedelta(days=31)
        ).annotate(
            price_taken=F('player_price') - (
                    F('player_min_price_from_futbin') - (F('player_min_price_from_futbin') * 0.05)),
        ).aggregate(
            sum_price_taken=Sum('price_taken'),
        ).get('sum_price_taken')
        final_transfers_31_days = query.filter(
            insert_time__gt=timezone.localtime() - timezone.timedelta(days=31)
        ).exclude(winner_account=None).annotate(
            price_receiver=(F('player_price') - (F('player_price') * 0.05)) - F('player_min_price_from_futbin')
        ).aggregate(
            sum_price_receiver=Sum('price_receiver'),
        ).get('sum_price_receiver')
        if final_transfers_31_days and price_taken_31_days:
            miss_and_tax_31_days = 100 - (final_transfers_31_days / price_taken_31_days * 100)

        cards_data.append({'name': 'miss&tax 24 hour',
                           'info': f'{round(miss_and_tax_24_hour, ndigits=2)}'})
        cards_data.append({'name': 'miss&tax 7 days',
                           'info': f'{round(miss_and_tax_7_days, ndigits=2)}'})
        cards_data.append({'name': 'miss&tax 31 days',
                           'info': f'{round(miss_and_tax_31_days, ndigits=2)}'})
        return cards_data

    def page_header(self):
        return 'Discharge Logs'

    def get_table_data(self):
        query = self.get_queryset().select_related('first_account')

        new_query = query.annotate(
            first_account_user=F('first_account__user_name'),
            status=Case(
                When(error=True, then=F('error_desc')),
                When(second_side_done=True, then=Value('success')),
                default=Value('running...'),
                output_field=CharField()
            ),
            miss_value=Subquery(SniperTradeItemLog.objects.annotate(
                player_asset=F('player_card__asset_id')
            ).filter(
                player_asset=OuterRef('player_asset_id'), status=0
            ).values('player_asset').annotate(
                miss_count1=Count('player_asset', output_field=FloatField())
            ).values('miss_count1')),
            all_value=Subquery(SniperTradeItemLog.objects.annotate(
                player_asset=F('player_card__asset_id')
            ).filter(
                player_asset=OuterRef('player_asset_id'),
                # status=1
            ).values('player_asset').annotate(
                success_count1=Count('player_asset', output_field=FloatField())
            ).values('success_count1')),
            miss_value_24=Subquery(SniperTradeItemLog.objects.annotate(
                player_asset=F('player_card__asset_id')
            ).filter(
                player_asset=OuterRef('player_asset_id'), status=0,
                action_time__gte=timezone.localtime() - timezone.timedelta(hours=24),
            ).values('player_asset').annotate(
                miss_count2=Count('player_asset', output_field=FloatField())
            ).values('miss_count2'), output_field=FloatField()),
            all_value_24=Subquery(SniperTradeItemLog.objects.annotate(
                player_asset=F('player_card__asset_id')
            ).filter(
                player_asset=OuterRef('player_asset_id'),
                # status=1,
                action_time__gte=timezone.localtime() - timezone.timedelta(hours=24),
            ).values('player_asset').annotate(
                success_count2=Count('player_asset', output_field=FloatField())
            ).values('success_count2'), output_field=FloatField()),
            console_name=F('first_account__console__name')
        )
        return new_query

    # def is_rel(self):
    #     return has_permission_exactly(self.request.user, self.required_permission__rel)


class DischargeWithMode2LogListView(RequiredPermissionViewMixin, GenericFilterListView):
    required_permission__all = 'discharge__read__all'
    model = DischargeMode2
    table_class = DischargeMode2LogListTable
    filterset_class = DischargeMode2LogListFilter

    def get_card_data(self):
        cards_data = []
        miss_and_tax_24_hour = miss_and_tax_7_days = miss_and_tax_31_days = 0
        query = self.get_queryset()
        query = query.filter(
            status__in=['success', 'failed']
        )
        price_taken_24_hour = query.filter(
            create_time__gt=timezone.localtime() - timezone.timedelta(hours=24)
        ).aggregate(
            sum_avg_price=Sum('avg_price'),
            sum_end_price=Sum('end_price'),
            sum_site_price=Sum('site_price'),
            objects_count=Count('id')
        )
        if price_taken_24_hour.get('sum_avg_price'):
            numerator_24 = price_taken_24_hour.get('sum_avg_price')*.05 + price_taken_24_hour.get('sum_end_price')*.05
            miss_and_tax_24_hour = ((numerator_24 + price_taken_24_hour.get('sum_site_price') - price_taken_24_hour.get('sum_avg_price')) / (numerator_24 + (
                    price_taken_24_hour.get('sum_end_price') - price_taken_24_hour.get('sum_avg_price'))))*100
        else:
            miss_and_tax_24_hour = 0
        # ------------------ #
        price_taken_7_days = query.filter(
            create_time__gt=timezone.localtime() - timezone.timedelta(days=7)
        ).aggregate(
            sum_avg_price=Sum('avg_price'),
            sum_end_price=Sum('end_price'),
            sum_site_price=Sum('site_price'),
            objects_count=Count('id')
        )
        if price_taken_7_days.get('sum_avg_price'):
            numerator_7 = price_taken_7_days.get('sum_avg_price') * .05 + price_taken_7_days.get('sum_end_price')*.05
            miss_and_tax_7_days = ((numerator_7 + price_taken_7_days.get('sum_site_price') - price_taken_7_days.get('sum_avg_price')) / (numerator_7 + (price_taken_7_days.get('sum_end_price') - price_taken_7_days.get('sum_avg_price')))) * 100
        else:
            miss_and_tax_7_days = 0
        # ------------------ #
        price_taken_31_days = query.filter(
            create_time__gt=timezone.localtime() - timezone.timedelta(days=31)
        ).aggregate(
            sum_avg_price=Sum('avg_price'),
            sum_end_price=Sum('end_price'),
            sum_site_price=Sum('site_price'),
            objects_count=Count('id')
        )
        if price_taken_31_days.get('sum_avg_price'):
            numerator_31 = price_taken_31_days.get('sum_avg_price') * .05 + price_taken_31_days.get('sum_end_price')*.05
            miss_and_tax_31_days = ((numerator_31 + price_taken_31_days.get('sum_site_price') - price_taken_31_days.get('sum_avg_price')) / (numerator_31 + (price_taken_31_days.get('sum_end_price') - price_taken_31_days.get('sum_avg_price')))) * 100
        else:
            miss_and_tax_31_days = 0
        # ------------------ #
        local_now = timezone.localtime()
        moved_price_1_hour = query.filter(
            create_time__gt=local_now - timezone.timedelta(hours=1),
        ).annotate(
            transfer_coin=(F('end_price') - F('avg_price')) - (F('end_price') * .05)
        ).aggregate(
            sum_success_discharge=Sum('transfer_coin')
        ).get('sum_success_discharge')
        moved_price_24_hour = query.filter(
            create_time__gt=local_now - timezone.timedelta(hours=24),
        ).annotate(
            transfer_coin=(F('end_price') - F('avg_price')) - (F('end_price') * .05)
        ).aggregate(
            sum_success_discharge=Sum('transfer_coin')
        ).get('sum_success_discharge')
        last_1000_transfer = query.annotate(
            transfer_coin=(F('end_price') - F('avg_price')) - (F('end_price') * .05)
        ).order_by('-id').values_list('transfer_coin', flat=True)[:1000]
        if last_1000_transfer:
            avg_last_1000_transfer = statistics.mean(last_1000_transfer)
        else:
            avg_last_1000_transfer = 0

        moved_card_24_hour = query.filter(
            create_time__gt=local_now - timezone.timedelta(hours=24),
        ).count()

        moved_account_24_hour = query.filter(
            create_time__gt=local_now - timezone.timedelta(hours=24),
        ).values('fifa_account').annotate(counter=Count('fifa_account')).count()

        discharge_start_coin_greater2 = ConsoleBotSetting.objects.get(
            name='discharge_start_coin_greater')
        discharge_start_coin_greater3 = ConsoleBotSetting.objects.get(
            name='discharge_with_mode3_lowest_target_price')
        ready_to_move_accounts = FifaAccount.objects.filter(
            Q(delete_console_reason=None) | Q(delete_console_reason=''),
            console__is_active=True,
            credit__gt=discharge_start_coin_greater2.int_value,
            credit__lt=discharge_start_coin_greater3.int_value
        ).count()

        ready_not_work_accounts = FifaAccount.objects.filter(
            Q(delete_console_reason=None) | Q(delete_console_reason=''),
            console__is_active=True,
            credit__gt=discharge_start_coin_greater2.int_value,
            credit__lt=discharge_start_coin_greater3.int_value
        ).exclude(
            id__in=query.filter(
                create_time__gt=local_now - timezone.timedelta(hours=24),
            ).values_list('fifa_account__id', flat=True)
        ).count()

        u7buy_cards_errors = TelegramMessage.objects.filter(
            text__icontains='We were unable to get a card from u7buy',
            create_time__gt=timezone.localtime() - timezone.timedelta(hours=24)
        ).count()


        cards_data.append({'name': 'miss&tax 24 hour',
                           'info': f'{round(miss_and_tax_24_hour, ndigits=2)}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'miss&tax 7 days',
                           'info': f'{round(miss_and_tax_7_days, ndigits=2)}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'miss&tax 31 days',
                           'info': f'{round(miss_and_tax_31_days, ndigits=2)}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': '1 hour',
                           'info': f'{number_convertor_to_milion(moved_price_1_hour or 0)}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': '24 hour',
                           'info': f'{number_convertor_to_milion(moved_price_24_hour or 0)}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': '24 h count',
                           'info': f'{moved_card_24_hour:,}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'pool - not worked - worked (24 h)',
                           'info': f'{ready_to_move_accounts:,} - {ready_not_work_accounts:,} - {moved_account_24_hour:,}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'avg 1000',
                           'info': f'{number_convertor_to_milion(avg_last_1000_transfer or 0)}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'u7 error 24h',
                           'info': f'{u7buy_cards_errors}',
                           'box_css_class': 'fw-bold'})
        return cards_data

    def page_header(self):
        return 'Discharge Logs'

    def get_table_data(self):
        query = self.get_queryset().select_related('fifa_account', 'mule')

        new_query = query.annotate(
            first_account_user=F('fifa_account__user_name'),
            new_status=Case(
                When(status='success', then=Value('success')),
                When(status='failed', then=Value('success')),
                When(status='not_bought', then=Value('not_bought')),
                default=Value('running...'),
                output_field=CharField()
            ),
            numerator=F('avg_price') * .05 + F('end_price') * .05,
            tax=Cast((((F('numerator') + (F('site_price') - F('avg_price'))) / (F('numerator') + (F('end_price') - F('avg_price')))) * 100) * 100,
                     output_field=IntegerField())/100.0,
            console_name=F('fifa_account__console__name'),
            has_star=Case(
                When(mule__is_api=True, then=Value(True)),
                default=Value(False),
            ),
            provider_type=Case(
                When(mule__is_api=True, then=Concat(F('mule__site_name'), Value('*'), output_field=CharField())),
                default=F('mule__site_name'),
            )
        )
        return new_query


class DischargePerDayLogListView(RequiredPermissionViewMixin, GenericFilterListView):
    required_permission__all = 'discharge__read__all'
    model = DischargePerDay
    filterset_class = DischargePerDayLogListFilter
    table_class = DischargePerDayLogListTable
    dashboard_layout = DashboardLayout(
            DashboardRow(
                DischargePerDayLogChartDashboardCard,

                css_class='row maximizable small-up-1 medium-up-1 large-up-1 align-center',
                data_equalizer='',
                data_equalize_on='large',
                data_equalize_by_row='true',
            ),
        )

    def get_context_data(self, **kwargs):
        if 'dashboard_layout' not in kwargs:
            kwargs['dashboard_layout'] = self.dashboard_layout.construct(self.request, **self.kwargs)

        if 'filter' not in kwargs:
            kwargs['filter'] = self.get_filterset(self.get_filterset_class())

        kwargs['global_row_expanded'] = 'expanded'
        return super().get_context_data(**kwargs)

    def get_queryset(self):
        return None

    def get_table_data(self):
        query = super().get_table_data()
        query = query.values('create_time').annotate(
            sum_income_credit=Sum('income_credit', output_field=FloatField()),
            sum_usdt_amount=Sum('usdt_amount', output_field=FloatField()),
            sum_euro_amount=Sum('euro_amount', output_field=FloatField()),
        ).order_by('create_time')
        return query


class DischargeWithMode3LogListView(RequiredPermissionViewMixin, GenericFilterListView):
    required_permission__all = 'discharge__read__all'
    model = CloseWebAppTransfers
    table_class = DischargeMode3LogListTable
    filterset_class = DischargeMode3LogListFilter

    def get_queryset(self):
        return super().get_queryset().filter(
            for_discharge=True
        ).select_related('first_account', 'second_account')

    def get_card_data(self):
        cards_data = []
        miss_and_tax_24_hour = miss_and_tax_7_days = miss_and_tax_31_days = 0
        query = self.get_queryset()
        query = query.filter(
            second_side_done=True,
        )
        price_taken_24_hour = query.filter(
            create_time__gt=timezone.localtime() - timezone.timedelta(hours=24)
        ).aggregate(
            sum_avg_price=Sum('start_price'),
            sum_end_price=Sum('buy_now_price'),
            sum_site_price=Sum('start_price'),
            objects_count=Count('id')
        )
        if price_taken_24_hour.get('sum_avg_price'):
            numerator_24 = price_taken_24_hour.get('sum_avg_price')*.05 + price_taken_24_hour.get('sum_end_price')*.05
            miss_and_tax_24_hour = ((numerator_24 + price_taken_24_hour.get('sum_site_price') - price_taken_24_hour.get('sum_avg_price')) / (numerator_24 + (
                    price_taken_24_hour.get('sum_end_price') - price_taken_24_hour.get('sum_avg_price'))))*100
        else:
            miss_and_tax_24_hour = 0
        # ------------------ #
        price_taken_7_days = query.filter(
            create_time__gt=timezone.localtime() - timezone.timedelta(days=7)
        ).aggregate(
            sum_avg_price=Sum('start_price'),
            sum_end_price=Sum('buy_now_price'),
            sum_site_price=Sum('start_price'),
            objects_count=Count('id')
        )
        if price_taken_7_days.get('sum_avg_price'):
            numerator_7 = price_taken_7_days.get('sum_avg_price') * .05 + price_taken_7_days.get('sum_end_price')*.05
            miss_and_tax_7_days = ((numerator_7 + price_taken_7_days.get('sum_site_price') - price_taken_7_days.get('sum_avg_price')) / (numerator_7 + (price_taken_7_days.get('sum_end_price') - price_taken_7_days.get('sum_avg_price')))) * 100
        else:
            miss_and_tax_7_days = 0
        # ------------------ #
        price_taken_31_days = query.filter(
            create_time__gt=timezone.localtime() - timezone.timedelta(days=31)
        ).aggregate(
            sum_avg_price=Sum('start_price'),
            sum_end_price=Sum('buy_now_price'),
            sum_site_price=Sum('start_price'),
            objects_count=Count('id')
        )
        if price_taken_31_days.get('sum_avg_price'):
            numerator_31 = price_taken_31_days.get('sum_avg_price') * .05 + price_taken_31_days.get('sum_end_price')*.05
            miss_and_tax_31_days = ((numerator_31 + price_taken_31_days.get('sum_site_price') - price_taken_31_days.get('sum_avg_price')) / (numerator_31 + (price_taken_31_days.get('sum_end_price') - price_taken_31_days.get('sum_avg_price')))) * 100
        else:
            miss_and_tax_31_days = 0
        # ------------------ #
        local_now = timezone.localtime()
        moved_price_1_hour = query.filter(
            create_time__gt=local_now - timezone.timedelta(hours=1),
        ).annotate(
            transfer_coin=(F('buy_now_price') - F('start_price')) - (F('buy_now_price') * .05)
        ).aggregate(
            sum_success_discharge=Sum('transfer_coin')
        ).get('sum_success_discharge')
        moved_price_24_hour = query.filter(
            create_time__gt=local_now - timezone.timedelta(hours=24),
        ).annotate(
            transfer_coin=(F('buy_now_price') - F('start_price')) - (F('buy_now_price') * .05)
        ).aggregate(
            sum_success_discharge=Sum('transfer_coin')
        ).get('sum_success_discharge')
        # last_1000_transfer = query.annotate(
        #     transfer_coin=(F('buy_now_price') - F('start_price')) - (F('buy_now_price') * .05)
        # ).order_by('-id').values_list('transfer_coin', flat=True)[:1000]
        # avg_last_1000_transfer = statistics.mean(last_1000_transfer)

        avg_last_24_hour = query.filter(
            create_time__gt=local_now - timezone.timedelta(hours=24)
        ).annotate(
            transfer_coin=(F('buy_now_price') - F('start_price')) - (F('buy_now_price') * .05)
        ).order_by('-id').values_list('transfer_coin', flat=True)
        if avg_last_24_hour:
            avg_last_24_h_transfer = statistics.mean(avg_last_24_hour)
        else:
            avg_last_24_h_transfer = 0

        moved_card_24_hour = query.filter(
            create_time__gt=local_now - timezone.timedelta(hours=24),
        ).count()

        moved_account_24_hour = query.filter(
            create_time__gt=local_now - timezone.timedelta(hours=24),
        ).values('second_account').annotate(counter=Count('second_account')).count()

        discharge_with_mode3_lowest_target_price = ConsoleBotSetting.objects.get(
            name='discharge_with_mode3_lowest_target_price')
        ready_to_move_accounts = FifaAccount.objects.filter(
            Q(delete_console_reason=None) | Q(delete_console_reason=''),
            console__is_active=True,
            credit__gt=discharge_with_mode3_lowest_target_price.int_value
        ).count()
        ready_not_worked = FifaAccount.objects.filter(
            Q(delete_console_reason=None) | Q(delete_console_reason=''),
            console__is_active=True,
            credit__gt=discharge_with_mode3_lowest_target_price.int_value
        ).exclude(id__in=query.filter(
            create_time__gt=local_now - timezone.timedelta(hours=24),
        ).values_list('second_account__id', flat=True)).count()


        cards_data.append({'name': 'miss&tax 24 hour',
                           'info': f'{round(miss_and_tax_24_hour, ndigits=2)}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'miss&tax 7 days',
                           'info': f'{round(miss_and_tax_7_days, ndigits=2)}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'miss&tax 31 days',
                           'info': f'{round(miss_and_tax_31_days, ndigits=2)}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': '1 hour',
                           'info': f'{number_convertor_to_milion(moved_price_1_hour or 0)}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': '24 hour',
                           'info': f'{number_convertor_to_milion(moved_price_24_hour or 0)}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': '24 h count',
                           'info': f'{moved_card_24_hour:,}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'pool - not worked - worked (24 h)',
                           'info': f'{ready_to_move_accounts} - {ready_not_worked} - {moved_account_24_hour:,}',
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'avg 24 hour',
                           'info': f'{number_convertor_to_milion(avg_last_24_h_transfer or 0)}',
                           'box_css_class': 'fw-bold'})
        return cards_data

    def page_header(self):
        return 'Discharge Mode 3'

    def get_table_data(self):
        query = self.get_queryset()

        new_query = query.annotate(
            first_account_user=F('second_account__user_name'),
            new_status=Case(
                When(second_side_done=True, then=Value('success')),
                When(error=True, then=Value('not_bought')),
                default=Value('running...'),
                output_field=CharField()
            ),
            numerator=F('start_price') * .05 + F('buy_now_price') * .05,
            tax=Cast((((F('numerator') + (F('buy_now_price') - F('start_price'))) / (F('numerator') + (F('buy_now_price') - F('start_price')))) * 100) * 100,
                     output_field=IntegerField())/100.0,
            console_name=F('second_account__console__name'),
            mule_user=F('first_account__user_name'),
            transfered_coin=(F('buy_now_price') - F('start_price')) - (F('buy_now_price') * .05),
            # has_star=Case(
            #     When(mule__is_api=True, then=Value(True)),
            #     default=Value(False),
            # ),
            # provider_type=Case(
            #     When(mule__is_api=True, then=Concat(F('mule__site_name'), Value('*'), output_field=CharField())),
            #     default=F('mule__site_name'),
            # )
        )
        return new_query
