# Create your views here.
import datetime
import os
import random
import re
import time
from urllib.parse import urlencode

import cloudscraper
import openpyxl
import requests
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.db.models import F, Sum, QuerySet, CharField, When, Case, Value, Q, Count, IntegerField, Subquery, OuterRef, \
    DateTimeField, ExpressionWrapper, BooleanField, TextField, Exists
from django.db.models.functions import Coalesce, Extract, Cast, Concat
from django.http import HttpResponseRedirect, HttpResponse, JsonResponse, FileResponse
from django.shortcuts import render, redirect
from django.urls import reverse_lazy, reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.views import View
from django.views.generic import FormView, DeleteView, TemplateView
from django.views.generic.detail import SingleObjectMixin
from django_filters.views import FilterView
from django_redis import get_redis_connection
from openpyxl import Workbook
from rolepermissions.exceptions import RoleDoesNotExist
from rolepermissions.permissions import revoke_permission, grant_permission, available_perm_names
from rolepermissions.roles import get_user_roles, remove_role, assign_role


from accounts.consts import TRADE_ACCESS_DICT, CONSOLE_USER_MODE
from accounts.dashboard_cards import InvestTradeSalaryChartDashboardCard, \
    InvestTradeSalaryGenerateChartDashboardCard, ConsoleInvestTradeItemsCountLogChartDashboardCard, \
    ConsoleInvestTradeSoldItemsCountLogChartDashboardCard, ConsoleInvestTradeWinItemsCountLogChartDashboardCard, \
    SBCSquadSalaryChartDashboardCard, SBCSquadTradeSalaryChartDashboardCard, ItemPackChartReportChartDashboardCard, \
    SBCSquadTradeSalary2ChartDashboardCard, SBCSquadTradeSalary3ChartDashboardCard, \
    SBCSquadTradeSalary4ChartDashboardCard
from accounts.filters import UserListFilter, FifaAccountsFilter, PlayerCardListFilter, FifaAccountLogsFilter, \
    ConsoleListFilter, DailyCreditGeneratedReportFilterSet, MuleAccountsListFilter, FifaAccountWorkErrorListFilterSet, \
    FifaAccountDetailWorkerErrorListFilterSet, ItemPackChartReportFilterSet, SystemLogsFilter, PCListFilter
from accounts.forms import UserRoleForm, UserPermissionForm, FifaAccountUpdateForm, MuleAccountFileCreateForm, \
    FifaProxyCreateForm, FifaAccountSpecialProxyForm, ConsoleUpdateForm, SimpleFileUploadForm, AddAccountsViewForm, \
    ConsoleFileFilterForm, ConsoleAccountManagementForm
from accounts.mixins import RestrictedUserMixin
from accounts.models import FifaAccount, FifaAccountLog, FifaProxy, FifaAccountBackupCode, Console, PC, MuleAccounts, \
    PlayerCard, VerifiedIp, CloseWebAppSnipes, InvestorOperators, ItemPack, ProgramVersion, \
    FifaAccountCreditLog, ConsoleBotSetting, FifaAccountRequest, FifaAccountWorkError, \
    FifaAccountCurrentItems, OutlookCreateWorker, NewOutlookAccount, ConsolePowerCommand, PCPowerCommand, \
    AccountPackData, NewConsoleAccount, CloseWebAppTransfers, FifaAccountSearch, ConsoleLastStatus, \
    ConsoleReadingAccounts, FifaAccountDisable, ArduinoPort
from accounts.tables import FifaAccountsTable, FifaAccountLogsTable, AccountTable, MuleAccountsTable, \
    FifaProxyListTable, PlayerCardTable, ConsoleTable, PackItemTable, \
    FifaAccountWorkErrorListTable, FifaAccountDetailWorkErrorListTable, OutlookCreateWorkerTable, SystemLogsTable, \
    ConsolesCommandPowerTable, PCsCommandPowerTable, AddAccountsViewTable, SummaryTable, ConsoleAccountsActionTable
from customrolepermissions.mixins import RequiredPermissionViewMixin
from customrolepermissions.permissions import has_permission_exactly, grant_perm_names, possible_perm_names
from futplus.settings import BASE_DIR, TIME_ZONE, MEDIA_ROOT
from sbc import ARZBAZI_REPORT_GROUP_ID, ARZBAZI_REPORT_TOPIC_LOGS_THREAD_MESSAGE_ID
from sbc.consts import RED_STATUS
from sbc.models import SBCWorker, SBCType, SBCProcess, SBCOrder, AccountCheckHealthyOrder, AccountCheckHealthyWorker
from sbc.public_methods import user_agent
from sniper.models import DischargeMode2, StartDischargeBot
from squad_battle.models import FifaAccountSquadGame, FifaAccountMomentsGame
from trade.models import ConsoleTradeOneHistory, ConsoleInvestTradeItemsCountLog
from utils import number_convertor_to_milion
from utils.dashboard_cards import DashboardLayout, DashboardRow
from utils.models import SystemLog
from utils.query_extra_func import ToCharTZ
from utils.views import GenericListView, GenericFilterListView, GenericUpdateView, GenericFormView, GenericFormTableView


class FifaAccountsFilterListView(RequiredPermissionViewMixin, GenericFilterListView):
    required_permission__ = 'fifa_account__read'
    model = FifaAccount
    table_class = FifaAccountsTable
    filterset_class = FifaAccountsFilter
    export_key = 'fifa_accounts'

    def get_queryset(self) -> QuerySet:
        return super().get_queryset().select_related('pc').annotate(
            app_code=Subquery(
                FifaAccountBackupCode.objects.filter(
                    fifa_account=OuterRef('id')
                ).values('app_code')[:1]
            )
        )

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)
    # def get_queryset(self):
    #     return super().get_queryset().filter(creator=self.request.user)


class FifaAccountLogsView(GenericFilterListView):
    model = FifaAccountLog
    table_class = FifaAccountLogsTable
    filterset_class = FifaAccountLogsFilter
    back_url = reverse_lazy('fifa-accounts-list')
    export_key = 'fifa_accounts_log'

    extra_js = """
            <script>
              document.addEventListener('DOMContentLoaded', function () {
                if (window.location.hash === "#bottomEnd") {
                  setTimeout(function () {
                    window.scrollTo({ top: document.body.scrollHeight, behavior: "smooth" });
                  }, 300);
                }
              });
            </script>
            """

    def __init__(self, *args, **kwargs):
        self.table_class.top_pagination = True
        super().__init__(*args, **kwargs)

    def get_queryset(self):
        fifa_account_id = self.kwargs.get('pk')
        fifa_account_user_name = self.kwargs.get('email')
        if fifa_account_id:
            return self.model.objects.using('logs').filter(fifa_account_id=fifa_account_id).distinct('log_time').order_by('log_time')
        if fifa_account_user_name:
            try:
                fifa_acc = FifaAccount.objects.get(user_name=fifa_account_user_name)
            except FifaAccount.DoesNotExist:
                return QuerySet()
            return self.model.objects.using('logs').filter(fifa_account_id=fifa_acc.id).order_by('pk')
            # return self.model.objects.filter(fifa_account__user_name=fifa_account_user_name).order_by('pk')

    def get_extra_buttons(self):
        buttons = []
        queryset = self.get_queryset()
        total_items = queryset.count()
        per_page = self.paginate_by
        last_page = (total_items // per_page) + (1 if total_items % per_page else 0)
        url = f'{self.request.path}?page={last_page}#bottomEnd'
        buttons.append({
            'url': url,
            'text': f'Go End',
            'color': 'btn-info'

        })
        return buttons


class SystemLogsView(GenericFilterListView):
    model = SystemLog
    table_class = SystemLogsTable
    filterset_class = SystemLogsFilter
    # back_url = reverse_lazy('fifa-accounts-list')
    export_key = 'system_log'

    def get_queryset(self):
        worker_name = self.kwargs.get('worker_name')
        if worker_name:
            return self.model.objects.filter(worker_name=worker_name).order_by('pk')
        return []


class FifaProxyListView(GenericListView):
    model = FifaProxy
    table_class = FifaProxyListTable
    export_key = 'fifa_proxy_list'

    def get_card_data(self):
        cards_data = []
        sum_usage = self.object_list.aggregate(sum_usage=Sum('usage_count')).get('sum_usage') or 0
        cards_data.append({'name': 'Use Count',
                           'info': sum_usage,
                           'box_css_class': 'fw-bold'})
        return cards_data

    def get_queryset(self):
        return super().get_queryset().annotate(
            usage_count=Coalesce(Subquery(FifaAccount.objects.filter(
                # Q(delete_console_reason=None) | Q(delete_console_reason=''),
                proxy__id=OuterRef('pk'),
            ).values('proxy').annotate(
                use_count=Count('id')
            ).values('use_count'), output_field=IntegerField()), Value(0))
        )


class FifaProxyDeleteView(LoginRequiredMixin, RequiredPermissionViewMixin, DeleteView):
    model = FifaProxy
    success_url = reverse_lazy('fifa-proxy-list')
    required_permission__all = 'fifa_proxy__delete'

    def get(self, request, *args, **kwargs):
        # delete without confirm
        return self.post(request, *args, **kwargs)


@login_required
def add_proxy_file(request):
    if request.method == 'POST':
        proxy_file = request.FILES.get('file')
        proxies = proxy_file.readlines()
        for proxy in proxies:
            # proxy = str(proxy[:-2])[2:-1]
            proxy_item = proxy.decode(encoding="utf-8").replace('\n', '').replace('  ', '').replace('\r', '')
            if proxy_item == '':
                continue
            proxy_splitted = proxy_item.split(':')
            proxy_ip = proxy_splitted[0]
            proxy_port = proxy_splitted[1]
            if len(proxy_splitted) == 2:
                proxy_user = 'simon_2052'
                proxy_pass = '36987rdr'
            else:
                proxy_user = proxy_splitted[2]
                proxy_pass = proxy_splitted[3]
            # print(proxy_splitted)
            # print('#')
            FifaProxy.objects.get_or_create(ip_address=proxy_ip, port=proxy_port, user_name=proxy_user,
                                            password=proxy_pass)

        messages.success(request, "proxy File added")
        return render(request, 'sbc/add_sbc_file.html')
    else:
        return render(request, 'sbc/add_sbc_file.html', {'page_header': 'Add Proxy File'})


class FifaProxyCreateView(RequiredPermissionViewMixin, GenericFormView):
    required_permission__all = 'mule_accounts__create'
    form_class = FifaProxyCreateForm
    success_url = reverse_lazy('add-proxy-file')

    def page_header(self):
        return 'Add Proxy File'

    def form_valid(self, form):
        type_name = form.cleaned_data.get('type_name')
        proxy_file = form.files.get('proxy_file')
        proxies = proxy_file.readlines()
        for proxy in proxies:
            # proxy = str(proxy[:-2])[2:-1]
            proxy_item = proxy.decode(encoding="utf-8").replace('\n', '').replace('  ', '').replace('\r', '')
            if proxy_item == '':
                continue
            proxy_splitted = proxy_item.split(':')
            proxy_ip = proxy_splitted[0]
            proxy_port = proxy_splitted[1]
            if len(proxy_splitted) == 2:
                proxy_user = 'simon_2052'
                proxy_pass = '36987rdr'
            else:
                proxy_user = proxy_splitted[2]
                proxy_pass = proxy_splitted[3]

            proxy_object, created = FifaProxy.objects.get_or_create(
                ip_address=proxy_ip, port=proxy_port, user_name=proxy_user, password=proxy_pass)
            if type_name:
                proxy_object.type_name = type_name
                proxy_object.save()

        messages.success(self.request, "proxy File added")
        return super().form_valid(form)

    # def get_form_kwargs(self):
    #     kwargs = super().get_form_kwargs()
    #     kwargs['user'] = self.request.user
    #     return kwargs


class FifaAccountSpecialProxyUpdateForm(RequiredPermissionViewMixin, GenericFormView):
    required_permission__all = 'mule_accounts__create'
    form_class = FifaAccountSpecialProxyForm
    success_url = reverse_lazy('use-special-proxy')

    def form_valid(self, form):
        sbc_file = form.files.get('accounts_file')
        type_name = form.cleaned_data.get('type_name')
        remove_old_proxy = form.cleaned_data.get('remove_old_proxy')
        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
            if ea_email:
                try:
                    fifa_account = FifaAccount.objects.get(user_name=ea_email)
                except:
                    messages.error(self.request, f'account with user name {ea_email} does not exists')
                    break
                if remove_old_proxy:
                    fifa_account.proxy = None
                    fifa_account.save(update_fields=['proxy'])
                if type_name:
                    proxy_item = FifaProxy.objects.filter(type_name=type_name).annotate(
                        usage_count=Coalesce(Subquery(FifaAccount.objects.filter(
                            # Q(delete_console_reason=None) | Q(delete_console_reason=''),
                            proxy__id=OuterRef('pk'),
                        ).values('proxy').annotate(
                            use_count=Count('id')
                        ).values('use_count'), output_field=IntegerField()), Value(0))
                    ).order_by('usage_count').first()
                    if proxy_item and not fifa_account.proxy:
                        fifa_account.proxy = proxy_item
                        fifa_account.save(update_fields=['proxy'])
        return super().form_valid(form)


class AddAccountsView(GenericFormTableView):
    success_url = reverse_lazy('fifa-account-add')
    page_header = 'Add Accounts'
    table_class = AddAccountsViewTable
    form_class = AddAccountsViewForm

    def form_valid(self, form):
        delete_reason = form.cleaned_data.get('delete_console_reason', None)
        console_user_mode = form.cleaned_data.get('console_user_mode', None)
        sbc_file = self.request.FILES.get('upload_file')
        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
            try:
                ea_pass = sheet_obj.cell(row=i, column=2).value
                platform = sheet_obj.cell(row=i, column=3).value
                app_code = sheet_obj.cell(row=i, column=4).value
            except:
                ea_pass = ''
                platform = ''
                app_code = ''
            try:
                console_name = sheet_obj.cell(row=i, column=5).value
                name_in_console = sheet_obj.cell(row=i, column=6).value
            except:
                console_name = ''
                name_in_console = ''
            try:
                pc_name = sheet_obj.cell(row=i, column=7).value
                pc_any_desk_code = sheet_obj.cell(row=i, column=8).value
                pc_any_desk_code_2 = sheet_obj.cell(row=i, column=9).value
            except:
                pc_name = ''
                pc_any_desk_code = ''
                pc_any_desk_code_2 = ''
            # try:
            #     delete_club_number = sheet_obj.cell(row=i, column=9).value
            # except:
            #     delete_club_number = 0
            try:
                delete_club_renewal = sheet_obj.cell(row=i, column=10).value
                if delete_club_renewal == 'False':
                    delete_club_renewal = False
            except:
                delete_club_renewal = False
            try:
                xbox_pass = sheet_obj.cell(row=i, column=11).value
            except:
                xbox_pass = ''
            try:
                previous_console_name = sheet_obj.cell(row=i, column=12).value
            except:
                previous_console_name = ''
            try:
                backup_code = sheet_obj.cell(row=i, column=13).value
            except:
                backup_code = None
            try:
                xbox_email = sheet_obj.cell(row=i, column=14).value
            except:
                xbox_email = None

            if ea_email:
                fifa_account, created = FifaAccount.objects.get_or_create(
                    user_name=ea_email)
                fifa_account.creator = self.request.user
                if platform:
                    fifa_account.platform = platform
                if ea_pass:
                    fifa_account.password = ea_pass
                if console_name:
                    console, created = Console.objects.get_or_create(name=int(console_name))
                    fifa_account.console = console
                    # fifa_account.use_special_squad = True
                    if previous_console_name:
                        previous_console = Console.objects.get(name=int(previous_console_name))
                        fifa_account.previous_console = previous_console
                    elif fifa_account.previous_console is None:
                        fifa_account.previous_console = console
                    if console.investor:
                        fifa_account.investor = console.investor
                        inv = InvestorOperators.objects.filter(investor=console.investor).first()
                        if inv:
                            for operator in inv.operators.all():
                                fifa_account.operators.add(operator)
                if name_in_console:
                    fifa_account.name_in_console = name_in_console
                # if delete_club_number:
                #     fifa_account.delete_club_number = delete_club_number
                if delete_club_renewal:
                    fifa_account.delete_club_renewal = delete_club_renewal
                if delete_reason not in [None, '-1']:
                    fifa_account.delete_console_reason = delete_reason
                if console_user_mode not in [None, 0]:
                    fifa_account.console_user_mode = console_user_mode
                if pc_name:
                    pc, created = PC.objects.get_or_create(name=pc_name)
                    if pc_any_desk_code:
                        pc.any_desk_code = pc_any_desk_code
                        pc.save()
                    if pc_any_desk_code_2:
                        pc.any_desk_code_2 = pc_any_desk_code_2
                        pc.save()
                    fifa_account.pc = pc

                if xbox_pass:
                    fifa_account.xbox_pass = xbox_pass
                if xbox_email:
                    fifa_account.xbox_email = xbox_email
                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()

        messages.success(self.request, "fifa accounts added")
        return super().form_valid(form)

    def get_table_data(self):
        return [{}]

@login_required
def fifa_accounts_add(request):
    if request.method == 'POST':
        sbc_file = request.FILES.get('file')
        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
            try:
                ea_pass = sheet_obj.cell(row=i, column=2).value
                platform = sheet_obj.cell(row=i, column=3).value
                app_code = sheet_obj.cell(row=i, column=4).value
            except:
                ea_pass = ''
                platform = ''
                app_code = ''
            try:
                console_name = sheet_obj.cell(row=i, column=5).value
                name_in_console = sheet_obj.cell(row=i, column=6).value
            except:
                console_name = ''
                name_in_console = ''
            try:
                pc_name = sheet_obj.cell(row=i, column=7).value
                pc_any_desk_code = sheet_obj.cell(row=i, column=8).value
                pc_any_desk_code_2 = sheet_obj.cell(row=i, column=9).value
            except:
                pc_name = ''
                pc_any_desk_code = ''
                pc_any_desk_code_2 = ''
            # try:
            #     delete_club_number = sheet_obj.cell(row=i, column=9).value
            # except:
            #     delete_club_number = 0
            try:
                delete_club_renewal = sheet_obj.cell(row=i, column=10).value
                if delete_club_renewal == 'False':
                    delete_club_renewal = False
            except:
                delete_club_renewal = False
            try:
                xbox_pass = sheet_obj.cell(row=i, column=11).value
            except:
                xbox_pass = ''
            try:
                previous_console_name = sheet_obj.cell(row=i, column=12).value
            except:
                previous_console_name = ''
            try:
                backup_code = sheet_obj.cell(row=i, column=13).value
            except:
                backup_code = None
            try:
                xbox_email = sheet_obj.cell(row=i, column=14).value
            except:
                xbox_email = None

            if ea_email:
                fifa_account, created = FifaAccount.objects.get_or_create(
                    user_name=ea_email)
                fifa_account.creator = request.user
                if platform:
                    fifa_account.platform = platform
                if ea_pass:
                    fifa_account.password = ea_pass
                if console_name:
                    console, created = Console.objects.get_or_create(name=int(console_name))
                    fifa_account.console = console
                    # fifa_account.use_special_squad = True
                    if previous_console_name:
                        previous_console = Console.objects.get(name=int(previous_console_name))
                        fifa_account.previous_console = previous_console
                    elif fifa_account.previous_console is None:
                        fifa_account.previous_console = console
                    if console.investor:
                        fifa_account.investor = console.investor
                        inv = InvestorOperators.objects.filter(investor=console.investor).first()
                        if inv:
                            for operator in inv.operators.all():
                                fifa_account.operators.add(operator)
                if name_in_console:
                    fifa_account.name_in_console = name_in_console
                # if delete_club_number:
                #     fifa_account.delete_club_number = delete_club_number
                if delete_club_renewal:
                    fifa_account.delete_club_renewal = delete_club_renewal
                if pc_name:
                    pc, created = PC.objects.get_or_create(name=pc_name)
                    if pc_any_desk_code:
                        pc.any_desk_code = pc_any_desk_code
                        pc.save()
                    if pc_any_desk_code_2:
                        pc.any_desk_code_2 = pc_any_desk_code_2
                        pc.save()
                    fifa_account.pc = pc

                if xbox_pass:
                    fifa_account.xbox_pass = xbox_pass
                if xbox_email:
                    fifa_account.xbox_email = xbox_email
                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()

        messages.success(request, "fifa accounts added")
        return render(request, 'sbc/add_sbc_file.html')
    else:
        return render(request, 'sbc/add_sbc_file.html',
                      {'page_header': 'Add Accounts',
                       'columns': ['EA Email', 'EA Password', 'Platform', 'App Code', 'Console Name',
                                   'Name in Console', 'PC Name', 'PC AnyDesk Code', 'PC AnyDesk Code 2',
                                   'Delete Club Renewal', 'XBOX Password', 'Previous Console Name', 'BackUp Code',
                                   'XBOX Email'],
                       })


class FifaAccountUpdateView(RequiredPermissionViewMixin, GenericUpdateView):
    required_permission__ = 'fifa_account__update'
    model = FifaAccount
    form_class = FifaAccountUpdateForm
    success_url = reverse_lazy('console-worker-logs')
    back_url = reverse_lazy('console-worker-logs')

    @property
    def page_header(self):
        return 'Update %s' % self.object.user_name

    # this bellow added because rel users get multiple object on get_queryset
    def get_queryset(self) -> QuerySet:
        return super().get_queryset().distinct('pk')

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


class MuleAccountsListView(RequiredPermissionViewMixin, GenericFilterListView):
    required_permission__ = 'mule_accounts__read'
    model = MuleAccounts
    table_class = MuleAccountsTable
    export_key = 'mule_accounts'
    filterset_class = MuleAccountsListFilter

    def get_card_data(self):
        cards_data = []
        sum_credit = self.get_queryset().aggregate(sum_credit=Sum('fifa_account__credit')).get('sum_credit')

        cards_data.append({'name': 'sum credit',
                           'info': f'{number_convertor_to_milion(sum_credit or 0)}'})
        return cards_data

    def get_queryset(self):
        disable_qs = FifaAccountDisable.objects.filter(fifa_account=OuterRef('fifa_account'), disable_mode=0)
        return super().get_queryset().annotate(
            credit=F('fifa_account__credit'),
            is_disabled=Exists(disable_qs),
        ).order_by('-credit')

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


@login_required
def manage_mule_accounts(request):
    if request.method == 'POST':
        mule_accounts = MuleAccounts.objects.all()
        for mule_account in mule_accounts:
            mule_account.delete()
        sbc_file = request.FILES.get('file')
        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):
            # print('max_row = ',max_row)
            ea_email = sheet_obj.cell(row=i, column=1).value
            if ea_email:
                fifa_account = FifaAccount.objects.get(user_name=ea_email)
                SBCWorker.objects.filter(
                    running_platform='inject', fifa_account=fifa_account
                ).update(
                    has_error=False, error_description=''
                )
                MuleAccounts.objects.create(fifa_account=fifa_account)

                messages.success(request, "mule accounts added")
        return render(request, 'sbc/add_sbc_file.html')
    else:
        return render(request, 'sbc/add_sbc_file.html', {'page_header': 'Manage Mule Accounts'})


class MuleAccountFileCreateView(RequiredPermissionViewMixin, GenericFormView):
    required_permission__all = 'mule_accounts__create'
    form_class = MuleAccountFileCreateForm
    success_url = reverse_lazy('mule-accounts-file-create')

    def check_last_sbc_workers(self, fifa_account):
        last_sbc_workers = SBCWorker.objects.filter(
            fifa_account=fifa_account, is_done=False, has_error=False, running_platform='web').first()
        return last_sbc_workers

    def page_header(self):
        return 'Manage Mule Accounts'

    def form_valid(self, form):
        new_investors = form.cleaned_data.get('investors')
        mule_file = form.files.get('mule_file')
        wb_obj = openpyxl.load_workbook(mule_file)
        sheet_obj = wb_obj.active
        max_row = sheet_obj.max_row
        new_mule_fifa_accounts = []

        for i in range(2, max_row + 1):
            ea_email = sheet_obj.cell(row=i, column=1).value
            if ea_email:
                try:
                    fifa_account = FifaAccount.objects.get(user_name=ea_email)
                except Exception as error:
                    messages.error(self.request, f"error on account {ea_email} , error : {error}")
                    return self.form_invalid(form)
                new_mule_fifa_accounts.append(fifa_account)
        SBCWorker.objects.filter(
            running_platform='inject', fifa_account__in=new_mule_fifa_accounts
        ).update(
            has_error=False, error_description=''
        )
        for account_item_2 in new_mule_fifa_accounts:
            mule_item_2, created = MuleAccounts.objects.get_or_create(fifa_account=account_item_2)
            # if mule_item_2.creator and mule_item_2.creator != self.request.user and not self.request.user.is_superuser:
            #     messages.error(self.request, f'{mule_item_2.fifa_account.user_name} already created by other user.')
            #     return super().form_valid(form)
            if not mule_item_2.creator:
                mule_item_2.creator = self.request.user
                mule_item_2.save()
        current_active_mules = MuleAccounts.objects.filter(
            Q(investors__in=MuleAccounts.objects.filter(
                fifa_account__in=new_mule_fifa_accounts).values_list('investors', flat=True)) |
            Q(investors__in=new_investors)
        )
        current_active_mules_2 = list(current_active_mules.filter(
            deleted=False
        ).values_list('fifa_account__id', flat=True))
        current_active_mules.update(deleted=True)
        for account_item in new_mule_fifa_accounts:
            mule_item, created = MuleAccounts.objects.get_or_create(fifa_account=account_item)
            if not mule_item.investors.all() and not new_investors.all():
                messages.error(self.request, 'Select Investor')
                return super().form_valid(form)
            # elif not mule_item.investors.all():
            elif new_investors.all():
                for investor_item in new_investors.all():
                    mule_item.investors.add(investor_item)
            mule_item.deleted = False
            mule_item.error = False
            mule_item.error_description = None
            mule_item.save()
        messages.success(self.request, "Mule Accounts Added")
        # add sbc order after
        sbc_order = SBCOrder.objects.create(creator=self.request.user, file_name='mule_change_auto.xlsx', status=1)
        sbc_workers = []
        for account_item_3 in FifaAccount.objects.filter(id__in=current_active_mules_2):
            account_item_3.refresh_from_db()
            account_item_3.active = False
            account_item_3.save()
            # exist_sbc = self.check_last_sbc_workers(account_item_3)
            # if not exist_sbc:
            SBCWorker.objects.filter(
                fifa_account=account_item_3, is_done=False, has_error=False,
                running_platform__in=['web', 'mule_web_sell_items']
            ).update(
                has_error=True,
                error_description='new mule replaced',
                must_done=True,
            )
            sbc_workers.append(SBCWorker(
                fifa_account=account_item_3, sbc_order=sbc_order,
                last_run_time=timezone.localtime() - datetime.timedelta(hours=3),
                manual_loyal=False, running_platform='mule_web_sell_items',
                order_active_squad=False,
                order_active_squad_formation=None,
                complete_number=5,
            ))
        SBCWorker.objects.bulk_create(sbc_workers)
        sbc_order.workers_count = len(sbc_workers)
        sbc_order.save(update_fields=['workers_count'])
        messages.success(self.request, "SBC Order Created")
        # add check healthy for new mules
        request_order = AccountCheckHealthyOrder.objects.create(
            creator=self.request.user, file_name='new_mules_auto.xlsx', status=1)
        for fifa_acc_item in new_mule_fifa_accounts:
            running_platform = 'web'
            AccountCheckHealthyWorker.objects.filter(
                fifa_account=fifa_acc_item, is_done=False, has_error=False, must_done=False
            ).update(
                has_error=True,
                error_description='new mule replaced',
                must_done=True,
            )
            AccountCheckHealthyWorker.objects.create(
                fifa_account=fifa_acc_item, request_order=request_order,
                running_platform=running_platform,
                sell_items=1,
                sell_club_items=1
            )
        messages.success(self.request, "Mules added successful")

        return super().form_valid(form)

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs


class ArchiveMuleAccountView(LoginRequiredMixin, TemplateView):
    template_name = 'public/success.html'

    def get_context_data(self, **kwargs):
        return {'message': 'Save Description Success', 'back_url': reverse_lazy("console-worker-logs")}

    def get(self, request, *args, **kwargs):
        query_params = request.GET.copy()
        mule_account_id = query_params.pop('archive_mule_account_id', None)
        if mule_account_id:
            mule_account = MuleAccounts.objects.filter(id=mule_account_id[0]).last()
            mule_account.deleted = True
            mule_account.save(update_fields=['deleted'])
            mule_user_name = mule_account.fifa_account.user_name
            messages.add_message(self.request, messages.SUCCESS, f'Archive {mule_user_name} success')
            base_url = reverse('mule-accounts-list')
            new_url = f"{base_url}?{urlencode(query_params)}" if query_params else base_url
            return HttpResponseRedirect(new_url)
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

    def post(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)


class UserListView(RequiredPermissionViewMixin, GenericFilterListView):
    required_permission__all = 'user__read'
    model = User
    table_class = AccountTable
    filterset_class = UserListFilter
    create_url = reverse_lazy('user-list-url')
    page_header = _('Users List')

    def get_queryset(self):
        queryset = super().get_queryset().filter(
            # is_superuser=False,
        ).prefetch_related(
            'groups',
        )
        return queryset


class UserPermissionView(RestrictedUserMixin, SingleObjectMixin, FormView):
    required_permission__ = 'user_permission__update'
    template_name = 'account/user-permission.html'
    model = User
    form_class = UserPermissionForm
    pk_url_kwarg = 'user_id'
    back_url = reverse_lazy('user-list-url')
    success_url = reverse_lazy('user-list-url')

    object = None

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super().get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super().post(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        kwargs['roles'] = [
            r.verbose_name
            for r in sorted(get_user_roles(self.object), key=lambda r: getattr(r, 'order', 1000))
        ]
        kwargs['username'] = self.get_user().username
        return super().get_context_data(**kwargs)

    def get_user(self) -> User:
        return self.object

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        user = self.get_user()
        kwargs['available_permissions'] = available_perm_names(user)
        kwargs['possible_permissions'] = possible_perm_names(user)
        kwargs['grant_permissions'] = grant_perm_names(user)
        return kwargs

    def get_initial(self):
        user = self.get_user()
        initials = {
            'is_active': user.is_active,
        }
        return initials

    def form_valid(self, form):
        """ If the form is valid, redirect to the supplied URL. """
        user = self.get_user()
        grant_permissions = grant_perm_names(user)

        is_active = form.cleaned_data.pop('is_active', False)
        if is_active != user.is_active:
            user.is_active = is_active
            user.save()

        for (permission, value) in form.cleaned_data.items():
            user_has_perm = has_permission_exactly(user, permission)

            if permission in grant_permissions:
                pass  # don't set or unset Grant permissions.

            elif value and not user_has_perm:
                grant_permission(user, permission)

            elif not value and user_has_perm:
                revoke_permission(user, permission)

        # to renew user.profile.update_date and force recreate related template cache segments
        user.save(force_update=True)

        messages.info(self.request, _('Permissions of `%s` updated.') % user.username)
        return HttpResponseRedirect(reverse('user-permission', kwargs={'user_id': user.id}))


class UserRoleView(RestrictedUserMixin, FormView):
    required_permission__all = 'user_role__update'
    template_name = 'account/user-role.html'
    form_class = UserRoleForm
    pk_url_kwarg = 'user_id'
    page_header = _('Users List')

    object = None

    def get_initial(self):
        initial = super().get_initial()
        initial['roles'] = [r.get_name() for r in get_user_roles(self.user)]
        return initial

    def get_context_data(self, **kwargs):
        kwargs['roles'] = [r.verbose_name for r in get_user_roles(self.object)]
        return super().get_context_data(**kwargs)

    def form_valid(self, form):
        roles = form.cleaned_data['roles']
        old_user_roles = set(r.get_name() for r in get_user_roles(self.user))
        new_user_roles = set(roles)

        for role_name in (old_user_roles - new_user_roles):
            remove_role(self.user, role_name)

        for role_name in (new_user_roles - old_user_roles):
            try:
                assign_role(self.user, role_name)
            except RoleDoesNotExist:
                pass

        # to renew user.profile.update_date and force recreate related template cache segments
        self.user.save(force_update=True)

        return super().form_valid(form)

    @property
    def back_url(self):
        return self.get_success_url()

    def get_success_url(self):
        return reverse('user-permission', kwargs={'user_id': self.user.id})


class PlayerCardListView(GenericFilterListView):
    model = PlayerCard
    table_class = PlayerCardTable
    filterset_class = PlayerCardListFilter
    create_url = reverse_lazy('player-cards-list')
    page_header = _('Players Card List')


class ConsolesReportView(RequiredPermissionViewMixin, LoginRequiredMixin, TemplateView):
    required_permission__ = 'console_report__read'
    model = Console

    def get(self, request, *args, **kwargs):
        last_sbc = SBCType.objects.filter(console_can_use=True, must_done=1).order_by('priority').last()
        first_sbc = SBCType.objects.filter(console_can_use=True, must_done=1).order_by('priority').first()
        today = datetime.datetime.now()
        target_dayofweek = 4  # Thursday
        current_dayofweek = today.weekday()  # Today
        timezone_local_now = timezone.localtime()
        if target_dayofweek <= current_dayofweek:
            # target is in the current week
            last_thursday = today - datetime.timedelta(current_dayofweek - target_dayofweek)

        else:
            # target is in the previous week
            last_thursday = (today -
                             datetime.timedelta(weeks=1) +
                             datetime.timedelta(target_dayofweek - current_dayofweek))
        response = HttpResponse(content_type='application/vnd.ms-excel')
        response['Content-Disposition'] = f'attachment; filename="console_detail_part_one.xlsx"'
        wb = Workbook()
        ws = wb.active
        active_consoles = self.get_queryset().filter(is_active=True).order_by(
            'name'
        ).prefetch_related('fifaaccount_set')
        ws.append(
            ['id', 'console name', 'current account', 'all account', 'completed games',
             'uncompleted games', 'zero games',
             'play 1 hour', 'play 2 hour', 'play 6 hour', 'play 12 hour', 'play 24 hour', 'play 31 days', 'play all',
             'all account play 31 day', 'all account play all',
             'account last sbc done', 'account first sbc done', 'account last sbc need', 'account first sbc need',
             'first play', 'trade history', 'web checked', 'complete',
             '', '', '', '',
             'xbox360 accounts', 'completed games', 'uncompleted games', 'zero games',
             'xboxs accounts', 'completed games', 'uncompleted games', 'zero games',
             # 'ps accounts', 'completed games', 'uncompleted games', 'zero games',
             ]
        )
        for item in active_consoles:
            console_last_sbc_need = 0
            console_first_sbc_need = 0
            console_last_sbc_complete = SBCProcess.objects.filter(
                worker__fifa_account__console=item,
                is_done=True, start_time__gte=last_thursday,
                sbc_type=last_sbc, worker__running_platform='console',
            ).select_related('worker').distinct('worker__fifa_account').count()
            console_first_sbc_complete = SBCProcess.objects.filter(
                worker__fifa_account__console=item,
                is_done=True, start_time__gte=last_thursday,
                sbc_type=first_sbc, worker__running_platform='console',
            ).select_related('worker').distinct('worker__fifa_account').count()
            if last_sbc:
                console_last_sbc_need = SBCType.objects.filter(
                    console_can_use=True, must_done=1, id=last_sbc.id,
                ).exclude(
                    id__in=SBCProcess.objects.filter(
                        sbc_number__in=SBCType.objects.filter(
                            console_can_use=True, must_done=1
                        ).values_list('sbc_number', flat=True),
                        worker__fifa_account__console=item, is_done=True
                    ).distinct('sbc_type').values_list('sbc_type__id', flat=True)
                ).count()
            if first_sbc:
                console_first_sbc_need = SBCType.objects.filter(
                    console_can_use=True, must_done=1, id=first_sbc.id,
                ).exclude(
                    id__in=SBCProcess.objects.filter(
                        sbc_number__in=SBCType.objects.filter(
                            console_can_use=True, must_done=1
                        ).values_list('sbc_number', flat=True),
                        worker__fifa_account__console=item, is_done=True
                    ).distinct('sbc_type').values_list('sbc_type__id', flat=True)
                ).count()
            console_squad_games = FifaAccountSquadGame.objects.filter(
                fifa_account__in=item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason='')
                ),
            )
            all_accounts_console_squad_games = FifaAccountSquadGame.objects.filter(
                fifa_account__in=item.previous_console_fifa_account.all(),
            )
            first_play = console_squad_games.order_by('create_time').first()
            if first_play:
                first_play_time = first_play.create_time
            else:
                first_play_time = ''
            ws.append([
                item.id, item.name,
                item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                ).count(),
                item.previous_console_fifa_account.all().count(),
                item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    account_played_games__gte=F('allowed_play_game'),
                ).count(),
                item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    account_played_games__lt=F('allowed_play_game'), account_played_games__gt=0,
                ).count(),
                item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    account_played_games=0
                ).count(),
                console_squad_games.filter(
                    # fifa_account__in=item.fifaaccount_set.all(),
                    create_time__gt=timezone_local_now - timezone.timedelta(hours=1)
                ).count(),
                console_squad_games.filter(
                    # fifa_account__in=item.fifaaccount_set.all(),
                    create_time__gt=timezone_local_now - timezone.timedelta(hours=2)
                ).count(),
                console_squad_games.filter(
                    # fifa_account__in=item.fifaaccount_set.all(),
                    create_time__gt=timezone_local_now - timezone.timedelta(hours=6)
                ).count(),
                console_squad_games.filter(
                    # fifa_account__in=item.fifaaccount_set.all(),
                    create_time__gt=timezone_local_now - timezone.timedelta(hours=12)
                ).count(),
                console_squad_games.filter(
                    # fifa_account__in=item.fifaaccount_set.all(),
                    create_time__gt=timezone_local_now - timezone.timedelta(hours=24)
                ).count(),
                console_squad_games.filter(
                    # fifa_account__in=item.fifaaccount_set.all(),
                    create_time__gt=timezone_local_now - timezone.timedelta(days=31)
                ).count(),
                console_squad_games.filter(
                    # fifa_account__in=item.fifaaccount_set.all(),
                ).count(),
                all_accounts_console_squad_games.filter(
                    create_time__gt=timezone_local_now - timezone.timedelta(days=31)
                ).count(),
                all_accounts_console_squad_games.filter(
                ).count(),
                console_last_sbc_complete,
                console_first_sbc_complete,
                console_last_sbc_need,
                console_first_sbc_need,
                str(first_play_time),
                ConsoleTradeOneHistory.objects.filter(
                    fifa_account__console=item,
                    create_time__gt=timezone_local_now - timezone.timedelta(hours=24),
                ).count(),
                ConsoleTradeOneHistory.objects.filter(
                    fifa_account__console=item,
                    create_time__gt=timezone_local_now - timezone.timedelta(hours=24),
                ).exclude(
                    move_items_from_unassigned=None,
                ).count(),
                ConsoleTradeOneHistory.objects.filter(
                    fifa_account__console=item,
                    create_time__gt=timezone_local_now - timezone.timedelta(hours=24),
                    credit_after__gt=0
                ).count(),
                '', '', '', '',
                item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    platform='xbox360').count(),
                item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    platform='xbox360', account_played_games__gte=F('allowed_play_game')).count(),
                item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    platform='xbox360', account_played_games__lt=F('allowed_play_game'), account_played_games__gt=0,
                ).count(),
                item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    platform='xbox360', account_played_games=0).count(),

                item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    platform='xboxs').count(),
                item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    platform='xboxs', account_played_games__gte=F('allowed_play_game')).count(),
                item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    platform='xboxs', account_played_games__lt=F('allowed_play_game'), account_played_games__gt=0,
                ).count(),
                item.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    platform='xboxs', account_played_games=0).count(),

                # item.fifaaccount_set.filter(
                #     Q(delete_console_reason=None) | Q(delete_console_reason=''),
                #     platform='ps').count(),
                # item.fifaaccount_set.filter(
                #     Q(delete_console_reason=None) | Q(delete_console_reason=''),
                #     platform='ps', account_played_games__gte=F('allowed_play_game')).count(),
                # item.fifaaccount_set.filter(
                #     Q(delete_console_reason=None) | Q(delete_console_reason=''),
                #     platform='ps', account_played_games__lt=F('allowed_play_game'), account_played_games__gt=0,
                # ).count(),
                # item.fifaaccount_set.filter(
                #     Q(delete_console_reason=None) | Q(delete_console_reason=''),
                #     platform='ps', account_played_games=0).count(),
                # item.fifaaccount_set.filter(
                #     Q(delete_console_reason=None) | Q(delete_console_reason=''),
                #     platform='ps5').count(),
                # item.fifaaccount_set.filter(
                #     Q(delete_console_reason=None) | Q(delete_console_reason=''),
                #     platform='ps5', account_played_games__gte=F('allowed_play_game')).count(),
                # item.fifaaccount_set.filter(
                #     Q(delete_console_reason=None) | Q(delete_console_reason=''),
                #     platform='ps5', account_played_games__lt=F('allowed_play_game'), account_played_games__gt=0,
                # ).count(),
                # item.fifaaccount_set.filter(
                #     Q(delete_console_reason=None) | Q(delete_console_reason=''),
                #     platform='ps5', account_played_games=0).count(),
            ])
        # ws2 = wb.create_sheet('console detail')
        # ws2.append(['id', 'console name', 'name in console', 'platform', 'user name', 'credit',
        #             'played games', 'squad special games', 'play all', 'play 31 d',
        #             'play last 31 d', 'play last 14 d', 'play last 7 d', 'play last 24 h', 'play 24 h',
        #             'completed sbc', 'login count 48', 'login count 24', 'request count 48',
        #             'description', 'error description'])
        # for fifa_acc in FifaAccount.objects.exclude(
        #         console=None
        # ).filter(console__in=active_consoles).order_by(
        #     'console__name'
        # ).select_related(
        #     'console'
        # ).prefetch_related(
        #     'account_request', 'fifaaccountsquadgame_set'
        # ):
        #     account_complete_sbc = SBCProcess.objects.filter(
        #         sbc_type__console_can_use=True,
        #         sbc_type__must_done=1,
        #         is_done=True, start_time__gte=last_thursday,
        #         worker__in=fifa_acc.sbcworker_set.all(),
        #     ).select_related('sbc_type').distinct('sbc_type').count()
        #
        #     last_worker = fifa_acc.sbcworker_set.last()
        #     last_game_time = fifa_acc.fifaaccountsquadgame_set.last()
        #     if last_game_time:
        #         last_game_time = last_game_time.create_time
        #     else:
        #         last_game_time = timezone_local_now
        #     ws2.append([
        #         fifa_acc.console.id, fifa_acc.console.name,
        #         fifa_acc.name_in_console,
        #         fifa_acc.platform,
        #         fifa_acc.user_name,
        #         fifa_acc.credit,
        #         fifa_acc.account_played_games,
        #         int(fifa_acc.squad_special_game_one) + int(fifa_acc.squad_special_game_two),
        #         fifa_acc.fifaaccountsquadgame_set.all().count(),
        #         fifa_acc.fifaaccountsquadgame_set.filter(
        #             create_time__gt=timezone_local_now - timezone.timedelta(days=31)
        #         ).count(),
        #         fifa_acc.fifaaccountsquadgame_set.filter(
        #             create_time__gt=last_game_time - timezone.timedelta(days=31)
        #         ).count(),
        #         fifa_acc.fifaaccountsquadgame_set.filter(
        #             create_time__gt=last_game_time - timezone.timedelta(days=14)
        #         ).count(),
        #         fifa_acc.fifaaccountsquadgame_set.filter(
        #             create_time__gt=last_game_time - timezone.timedelta(days=7)
        #         ).count(),
        #         fifa_acc.fifaaccountsquadgame_set.filter(
        #             create_time__gt=last_game_time - timezone.timedelta(hours=24)
        #         ).count(),
        #         fifa_acc.fifaaccountsquadgame_set.filter(
        #             create_time__gt=timezone_local_now - timezone.timedelta(hours=24)
        #         ).count(),
        #         account_complete_sbc,
        #         int(fifa_acc.account_request.filter(
        #             create_time__gt=timezone_local_now - timezone.timedelta(hours=48),
        #             link='https://accounts.ea.com/connect/auth?client_id=FUTWEB_BK_OL_SERVER&redirect_uri=nucleus:rest&response_type=code&access_token'
        #         ).count()),
        #         int(fifa_acc.account_request.filter(
        #             create_time__gt=timezone_local_now - timezone.timedelta(hours=24),
        #             link='https://accounts.ea.com/connect/auth?client_id=FUTWEB_BK_OL_SERVER&redirect_uri=nucleus:rest&response_type=code&access_token'
        #         ).count()),
        #         int(fifa_acc.account_request.filter(
        #             create_time__gt=timezone_local_now - timezone.timedelta(hours=48),
        #         ).count()),
        #         last_worker.description if last_worker else '',
        #         last_worker.error_description if last_worker else '',
        #         str(fifa_acc.delete_console_reason),
        #     ])

        # ws3 = wb.create_sheet('accounts detail')
        # ws3.append(['id', 'console name', 'name in console', 'platform', 'user name',
        #             'played games', 'description', 'error description'])
        # imperfect_accounts = SBCWorker.objects.filter(
        #     is_done=False, has_error=True, running_platform='console'
        # ).order_by('fifa_account_id').distinct('fifa_account_id').values_list('fifa_account__id', flat=True)
        # for fifa_acc in FifaAccount.objects.exclude(
        #         console=None
        # ).filter(
        #     console__in=active_consoles
        # ).filter(
        #     account_played_games__lt=F('allowed_play_game'), id__in=imperfect_accounts
        # ).select_related('console').order_by('console__name'):
        #     last_worker2 = fifa_acc.sbcworker_set.last()
        #     ws3.append([
        #         fifa_acc.console.id, fifa_acc.console.name,
        #         fifa_acc.name_in_console,
        #         fifa_acc.platform,
        #         fifa_acc.user_name,
        #         fifa_acc.account_played_games,
        #         last_worker2.description if last_worker2 else '',
        #         last_worker2.error_description if last_worker2 else '',
        #     ])

        # ws4 = wb.create_sheet('snipes detail')
        # ws4.append(['console name', 'success 7', 'miss 7', 'success and miss 7', 'miss rate 7',
        #             'success', 'miss', 'success and miss', 'miss rate'])
        # for item in active_consoles:
        #     result = CloseWebAppSnipes.objects.filter(first_account__in=item.fifaaccount_set.all())
        #     success_7 = result.exclude(
        #         winner_account=None,
        #     ).filter(
        #         insert_time__gt=timezone_local_now - timezone.timedelta(days=7),
        #     ).annotate(
        #         transfer_coin=(F('player_price') - F('player_min_price_from_futbin')) - (
        #                 (F('player_price') + F('player_min_price_from_futbin')) * .05)
        #     ).aggregate(sum_transfer_coin=Sum('transfer_coin')).get('sum_transfer_coin')
        #     # miss_7 = result.filter(
        #     #     winner_account=None,
        #     #     insert_time__gt=timezone_local_now - timezone.timedelta(days=7),
        #     # ).annotate(
        #     #     transfer_coin=F('player_price') - F('player_min_price_from_futbin')
        #     # ).aggregate(sum_transfer_coin=Sum('transfer_coin')).get('sum_transfer_coin')
        #     success_and_miss_7 = result.filter(
        #         insert_time__gt=timezone_local_now - timezone.timedelta(days=7),
        #     ).annotate(
        #         transfer_coin=F('player_price') - F('player_min_price_from_futbin')
        #     ).aggregate(sum_transfer_coin=Sum('transfer_coin')).get('sum_transfer_coin')
        #
        #     miss_7 = (success_and_miss_7 or 0) - (success_7 or 0)
        #     miss_rate_7 = (miss_7 / (success_and_miss_7 or 1)) * 100
        #
        #     success = result.exclude(
        #         winner_account=None,
        #     ).annotate(
        #         transfer_coin=(F('player_price') - F('player_min_price_from_futbin')) - (
        #                 (F('player_price') + F('player_min_price_from_futbin')) * .05)
        #     ).aggregate(sum_transfer_coin=Sum('transfer_coin')).get('sum_transfer_coin')
        #     # miss = result.filter(
        #     #     winner_account=None,
        #     # ).annotate(
        #     #     transfer_coin=F('player_price') - F('player_min_price_from_futbin')
        #     # ).aggregate(sum_transfer_coin=Sum('transfer_coin')).get('sum_transfer_coin')
        #     success_and_miss = result.annotate(
        #         transfer_coin=F('player_price') - F('player_min_price_from_futbin')
        #     ).aggregate(sum_transfer_coin=Sum('transfer_coin')).get('sum_transfer_coin')
        #     miss = (success_and_miss or 0) - (success or 0)
        #     miss_rate = (miss / (success_and_miss or 1)) * 100
        #     ws4.append([
        #         item.name,
        #         str(success_7),
        #         str(miss_7),
        #         str(success_and_miss_7),
        #         str(miss_rate_7),
        #         str(success),
        #         str(miss),
        #         str(success_and_miss),
        #         str(miss_rate)
        #     ])

        wb.save(response)
        return response

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


class ConsolesReportPart2View(RequiredPermissionViewMixin, LoginRequiredMixin, TemplateView):
    required_permission__ = 'console_report__read'
    model = Console

    def get(self, request, *args, **kwargs):
        # last_sbc = SBCType.objects.filter(console_can_use=True, must_done=1).order_by('priority').last()
        # first_sbc = SBCType.objects.filter(console_can_use=True, must_done=1).order_by('priority').first()
        today = datetime.datetime.now()
        target_dayofweek = 4  # Thursday
        current_dayofweek = today.weekday()  # Today
        timezone_local_now = timezone.localtime()
        if target_dayofweek <= current_dayofweek:
            # target is in the current week
            last_thursday = today - datetime.timedelta(current_dayofweek - target_dayofweek)

        else:
            # target is in the previous week
            last_thursday = (today -
                             datetime.timedelta(weeks=1) +
                             datetime.timedelta(target_dayofweek - current_dayofweek))
        repeatable_sbcs = SBCType.objects.exclude(
            expire_time=None,
        ).filter(
            repeatable__in=['immediately', 'daily']
        ).filter(
            expire_time__gt=timezone.localtime() + timezone.timedelta(hours=12),
            must_done=1,
        )
        first_repeatable = repeatable_sbcs.first()
        if first_repeatable:
            first_repeatable_id = first_repeatable.id
            first_repeatable_name = first_repeatable.name
        else:
            first_repeatable_id = 0
            first_repeatable_name = ''
        response = HttpResponse(content_type='application/vnd.ms-excel')
        response['Content-Disposition'] = f'attachment; filename="console_detail_part_two.xlsx"'
        wb = Workbook()
        ws = wb.active
        active_consoles = self.get_queryset().filter(is_active=True).order_by(
            'name'
        ).values_list('id', flat=True)
        ws2 = wb.create_sheet('console detail')
        ws2.append(['id', 'console name', 'name in console', 'platform', 'gamer_tag', 'user name', 'credit',
                    'request 24 h', 'request 12 h', 'login count 24', 'login count 48',
                    'completed sbc', 'discharge 72 h', 'discharge all', 'first discharge', 'try discharge 72 h',
                    'played games', 'squad special games', 'play all',
                    # 'play 31 d', 'play last 31 d', 'play last 14 d', 'play last 7 d', 'play last 24 h',
                    'allowed 24 h',
                    'play 24 h',
                    'search 48 h',
                    'trade access',
                    'unopened packs',
                    'moments', 'moment time',
                    f'{first_repeatable_name}',
                    'description', 'error description', 'delete reason',
                    'xbox email', 'xbox pass', 'user mode',
                    # 'semi_pro', 'pro',
                    'last status', 'last run time', 'console status',
                    'create time', 'last play time', 'last sbc done', 'last trade time', ''])
        # todo : add some url for all accounts .
        if not kwargs.get('report_all') and not request.GET.get('report_all'):
            query = FifaAccount.objects.exclude(
                delete_console_reason='account_disable'
            )
        else:
            query = FifaAccount.objects.all()
        logins_and_requests = FifaAccountRequest.objects.using('logs').filter(
                create_time__gt=timezone_local_now - timezone.timedelta(hours=48)
            ).values('fifa_account_id').annotate(
                request_24_hour=Count('id', filter=Q(create_time__gt=timezone_local_now - timezone.timedelta(hours=24))),
                request_12_hour=Count('id', filter=Q(create_time__gt=timezone_local_now - timezone.timedelta(hours=12))),
                login_24_hour=Count('id', filter=Q(
                    create_time__gt=timezone_local_now - timezone.timedelta(hours=24),
                    link__startswith='https://accounts.ea.com/connect/auth'
                )),
                login_48_hour=Count('id', filter=Q(
                    create_time__gt=timezone_local_now - timezone.timedelta(hours=48),
                    link__startswith='https://accounts.ea.com/connect/auth'
                ))
            )
        logins_and_requests_dict = {entry['fifa_account_id']: entry for entry in logins_and_requests}
        for fifa_acc in query.exclude(
                console=None
        ).filter(
            console__id__in=active_consoles
        ).order_by(
            'console__name'
        ).annotate(
            last_worker_id=Subquery(SBCWorker.objects.filter(
                fifa_account__id=OuterRef('pk'),
            ).order_by().values('id').reverse()[:1]),
            last_worker_description=Subquery(SBCWorker.objects.filter(
                id=OuterRef('last_worker_id'),
            ).values('description')[:1]),
            last_worker_error_description=Subquery(SBCWorker.objects.filter(
                id=OuterRef('last_worker_id'),
            ).values('error_description')[:1]),
            play_all=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
                fifa_account__id=OuterRef('pk')
            ).values('fifa_account').annotate(
                use_count=Count('id')
            ).values('use_count'), output_field=IntegerField()), Value(0)),
            play_24_hour=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
                fifa_account__id=OuterRef('pk'),
                create_time__gt=timezone_local_now - timezone.timedelta(hours=24)
            ).values('fifa_account').annotate(
                use_count=Count('id')
            ).values('use_count'), output_field=IntegerField()), Value(0)),
            last_game_time=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
                fifa_account__id=OuterRef('pk'),
            ).order_by().values('create_time').reverse()[:1], output_field=DateTimeField()), Value(None)),
            last_game_time_1=Case(
                When(last_game_time__isnull=False, then=F('last_game_time')),
                default=timezone_local_now, output_field=DateTimeField()),
            play_last_24_hour=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
                fifa_account__id=OuterRef('pk'),
                create_time__gt=OuterRef('last_game_time_1') - timezone.timedelta(hours=24)
            ).values('fifa_account').annotate(
                use_count=Count('id')
            ).values('use_count'), output_field=IntegerField()), Value(0)),
            # request_24_hour=Coalesce(Subquery(FifaAccountRequest.objects.using('logs').filter(
            #     fifa_account_id=OuterRef('pk'),
            #     create_time__gt=timezone_local_now - timezone.timedelta(hours=24)
            # ).values('fifa_account_id').annotate(
            #     use_count=Count('id')
            # ).values('use_count'), output_field=IntegerField()), Value(0)),
            # login_24_hour=Coalesce(Subquery(FifaAccountRequest.objects.using('logs').filter(
            #     fifa_account_id=OuterRef('pk'),
            #     create_time__gt=timezone_local_now - timezone.timedelta(hours=24),
            #     link='https://accounts.ea.com/connect/auth?client_id=FC24_JS_WEB_APP&redirect_uri=nucleus:rest&response_type=code&access_token'
            # ).values('fifa_account').annotate(
            #     use_count=Count('id')
            # ).values('use_count'), output_field=IntegerField()), Value(0)),
            # login_48_hour=Coalesce(Subquery(FifaAccountRequest.objects.using('logs').filter(
            #     fifa_account_id=OuterRef('pk'),
            #     create_time__gt=timezone_local_now - timezone.timedelta(hours=48),
            #     link='https://accounts.ea.com/connect/auth?client_id=FC24_JS_WEB_APP&redirect_uri=nucleus:rest&response_type=code&access_token'
            # ).values('fifa_account').annotate(
            #     use_count=Count('id')
            # ).values('use_count'), output_field=IntegerField()), Value(0)),
            search_48_hour=Coalesce(Subquery(FifaAccountSearch.objects.filter(
                fifa_account__id=OuterRef('pk'),
                search_time__gt=timezone_local_now - timezone.timedelta(hours=48)
            ).values('fifa_account_id').annotate(
                use_count=Count('id')
            ).values('use_count'), output_field=IntegerField()), Value(0)),
            done_moments=Coalesce(Subquery(FifaAccountMomentsGame.objects.filter(
                fifa_account__id=OuterRef('pk'),
                win_status=True,
                need_fix_squad=False,
            ).values('fifa_account').annotate(
                use_count=Count('id')
            ).values('use_count'), output_field=IntegerField()), Value(0)),
            last_moment_time=Coalesce(Subquery(FifaAccountMomentsGame.objects.filter(
                win_status=True,
                fifa_account__id=OuterRef('pk'),
                need_fix_squad=False,
            ).order_by().values('create_time').reverse()[:1], output_field=DateTimeField()), Value(None)),
            daily_sbc_compeleted=Coalesce(Subquery(SBCProcess.objects.filter(
                is_done=True,
                sbc_type__id=first_repeatable_id,
                worker__fifa_account__id=OuterRef('pk'),
            ).values('worker__fifa_account').annotate(
                use_count=Count('id')
            ).values('use_count'), output_field=IntegerField()), Value(0)),
            last_worker_status=Subquery(SBCWorker.objects.filter(
                id=OuterRef('last_worker_id'),
            ).exclude(
                status__startswith='key in use'
            ).values('status')[:1]),
            last_console_worker_status=Coalesce(Subquery(SBCWorker.objects.filter(
                running_platform='console',
                fifa_account__id=OuterRef('pk'),
            ).order_by().values('status').reverse()[:1], output_field=TextField()), Value(None)),
            last_sbc_time=Coalesce(Subquery(SBCProcess.objects.filter(
                is_done=True,
                worker__fifa_account__id=OuterRef('pk'),
            ).order_by().values('create_time').reverse()[:1], output_field=DateTimeField()), Value(None)),
            last_trade_time=Coalesce(Subquery(ConsoleTradeOneHistory.objects.filter(
                fifa_account__id=OuterRef('pk'),
            ).order_by().values('update_time').reverse()[:1], output_field=DateTimeField()), Value(None)),
            completed_sbc=Coalesce(Subquery(SBCProcess.objects.filter(
                sbc_type__must_done=1, sbc_type__console_can_use=True,
                worker__fifa_account__id=OuterRef('id'),
                is_done=True
            ).values_list(
                'worker__fifa_account__id', flat=True
            ).annotate(
                complete_count=Count('sbc_type__id', distinct=True)
            ).values_list('complete_count', flat=True)[:1]), Value(0)),
            count_discharge=Coalesce(Subquery(DischargeMode2.objects.filter(
                status__in=['success', 'failed'],
                create_time__gte=timezone.localtime() - timezone.timedelta(hours=72),
                fifa_account__id=OuterRef('id'),
            ).values(
                'fifa_account__id'
            ).annotate(
                count_di=Count('fifa_account__id')
            ).values('count_di')[:1], output_field=IntegerField()), Value(0)) + Coalesce(
                Subquery(CloseWebAppTransfers.objects.filter(
                    second_side_done=True,
                    create_time__gte=timezone.localtime() - timezone.timedelta(hours=72),
                    for_discharge=True,
                    second_account__id=OuterRef('id'),
                ).values(
                    'second_account__id'
                ).annotate(
                    count_di_3=Count('second_account__id')
                ).values('count_di_3')[:1], output_field=IntegerField()), Value(0)),
            try_discharge=Coalesce(Subquery(StartDischargeBot.objects.filter(
                create_time__gte=timezone.localtime() - timezone.timedelta(hours=72),
                fifa_account__id=OuterRef('id'),
            ).values(
                'fifa_account__id'
            ).annotate(
                count_di=Count('fifa_account__id')
            ).values('count_di')[:1], output_field=IntegerField()), Value(0)),
            # try_discharge=Coalesce(Subquery(DischargeMode2.objects.filter(
            #     create_time__gte=timezone.localtime() - timezone.timedelta(hours=72),
            #     fifa_account__id=OuterRef('id'),
            # ).values(
            #     'fifa_account__id'
            # ).annotate(
            #     count_di=Count('fifa_account__id')
            # ).values('count_di')[:1], output_field=IntegerField()), Value(0)) + Coalesce(
            #     Subquery(CloseWebAppTransfers.objects.filter(
            #         create_time__gte=timezone.localtime() - timezone.timedelta(hours=72),
            #         for_discharge=True,
            #         second_account__id=OuterRef('id'),
            #     ).values(
            #         'second_account__id'
            #     ).annotate(
            #         count_di_3=Count('second_account__id')
            #     ).values('count_di_3')[:1], output_field=IntegerField()), Value(0)),
            count_discharge_all=Coalesce(Subquery(DischargeMode2.objects.filter(
                status__in=['success', 'failed'],
                fifa_account__id=OuterRef('id'),
            ).values(
                'fifa_account__id'
            ).annotate(
                count_di=Count('fifa_account__id')
            ).values('count_di')[:1], output_field=IntegerField()), Value(0)) + Coalesce(
                Subquery(CloseWebAppTransfers.objects.filter(
                    second_side_done=True,
                    for_discharge=True,
                    second_account__id=OuterRef('id'),
                ).values(
                    'second_account__id'
                ).annotate(
                    count_di_3=Count('second_account__id')
                ).values('count_di_3')[:1], output_field=IntegerField()), Value(0)),
            first_discharge_time=Coalesce(
                Subquery(
                    DischargeMode2.objects.filter(
                        status__in=['success', 'failed'],
                        fifa_account__id=OuterRef('id'),
                    ).order_by('create_time').values('create_time')[:1]
                ),
                Subquery(
                    CloseWebAppTransfers.objects.filter(
                        second_side_done=True,
                        for_discharge=True,
                        second_account__id=OuterRef('id'),
                    ).order_by('create_time').values('create_time')[:1]
                ),
                Value(None, output_field=DateTimeField())
            ),
            count_packs=Coalesce(Subquery(AccountPackData.objects.filter(
                fifa_account__id=OuterRef('id'),
                coins__lt=100,
            ).values(
                'fifa_account__id'
            ).annotate(
                count_pa=Count('fifa_account__id')
            ).values('count_pa')[:1], output_field=IntegerField()), Value(0))

        ).select_related(
            'console'
        ).values(
            'id',
            'console__id',
            'console__name',
            'name_in_console',
            'platform',
            'gamer_tag',
            'user_name',
            'credit',
            'console_trade_one_quality',
            'account_played_games',
            'squad_special_game_one',
            'squad_special_game_two',
            'allowed_play_game_day',
            # 'last_worker_id',
            'last_worker_description',
            'last_worker_error_description',
            'play_all',
            'play_24_hour',
            # 'last_game_time',
            # 'play_last_24_hour',
            # 'request_24_hour',
            # 'search_48_hour',
            # 'login_24_hour',
            # 'login_48_hour',
            'done_moments',
            'last_moment_time',
            'daily_sbc_compeleted',
            'trade_access',
            'delete_console_reason',
            'xbox_email',
            'xbox_pass',
            'last_worker_status',
            'last_console_worker_status',
            'create_time',
            'last_run_time',
            'last_sbc_time',
            'last_trade_time',
            'completed_sbc',
            'count_discharge',
            'count_discharge_all',
            'first_discharge_time',
            'try_discharge',
            'count_packs',
            'console_user_mode',

        ):
            # account_complete_sbc = SBCProcess.objects.filter(
            #     sbc_type__console_can_use=True,
            #     sbc_type__must_done=1,
            #     is_done=True, start_time__gte=last_thursday,
            #     worker__in=fifa_acc.sbcworker_set.all(),
            # ).select_related('sbc_type').distinct('sbc_type').count()

            # account_complete_sbc = SBCType.objects.filter(
            #     console_can_use=True, must_done=1,
            #     id__in=SBCProcess.objects.filter(
            #         sbc_number__in=SBCType.objects.filter(
            #             console_can_use=True, must_done=1
            #         ).values_list('sbc_number', flat=True),
            #         worker__fifa_account__id=fifa_acc.get('id'), is_done=True
            #     ).distinct('sbc_type').values_list('sbc_type__id', flat=True)
            # ).count()

            # last_worker = fifa_acc.sbcworker_set.last()
            # last_game_time_1 = FifaAccountSquadGame.objects.filter(fifa_account__id=fifa_acc.get('id')).last()
            last_game_time_1 = fifa_acc.get('last_game_time')
            if last_game_time_1:
                last_game_time = last_game_time_1
            else:
                last_game_time = timezone_local_now
            create_time = fifa_acc.get('create_time')
            last_play_time = last_game_time_1 if last_game_time_1 else None
            last_sbc_time = fifa_acc.get('last_sbc_time')
            last_trade_time = fifa_acc.get('last_trade_time')
            last_moment_time = fifa_acc.get('last_moment_time')
            first_discharge_time = fifa_acc.get('first_discharge_time')
            ws2.append([
                fifa_acc.get('console__id'),
                fifa_acc.get('console__name'),
                fifa_acc.get('name_in_console'),
                fifa_acc.get('platform'),
                fifa_acc.get('gamer_tag'),
                fifa_acc.get('user_name'),
                fifa_acc.get('credit'),
                int(logins_and_requests_dict.get(fifa_acc.get('id'), {}).get('request_24_hour', 0)),
                int(logins_and_requests_dict.get(fifa_acc.get('id'), {}).get('request_12_hour', 0)),
                int(logins_and_requests_dict.get(fifa_acc.get('id'), {}).get('login_24_hour', 0)),
                int(logins_and_requests_dict.get(fifa_acc.get('id'), {}).get('login_48_hour', 0)),
                int(fifa_acc.get('completed_sbc') or 0),
                int(fifa_acc.get('count_discharge') or 0),
                int(fifa_acc.get('count_discharge_all') or 0),
                first_discharge_time.replace(tzinfo=None) if first_discharge_time else None,
                int(fifa_acc.get('try_discharge') or 0),
                fifa_acc.get('account_played_games'),
                ",".join([str(int(fifa_acc.get('squad_special_game_one'))), str(int(fifa_acc.get('squad_special_game_two')))]),
                # fifa_acc.fifaaccountsquadgame_set.all().count(),
                int(fifa_acc.get('play_all')),
                # FifaAccountSquadGame.objects.filter(fifa_account__id=fifa_acc.get('id')).all().count(),
                # '', '', '', '',
                # fifa_acc.fifaaccountsquadgame_set.filter(
                #     create_time__gt=timezone_local_now - timezone.timedelta(days=31)
                # ).count(),
                # fifa_acc.fifaaccountsquadgame_set.filter(
                #     create_time__gt=last_game_time - timezone.timedelta(days=31)
                # ).count(),
                # fifa_acc.fifaaccountsquadgame_set.filter(
                #     create_time__gt=last_game_time - timezone.timedelta(days=14)
                # ).count(),
                # fifa_acc.fifaaccountsquadgame_set.filter(
                #     create_time__gt=last_game_time - timezone.timedelta(days=7)
                # ).count(),
                # FifaAccountSquadGame.objects.filter(
                #     fifa_account__id=fifa_acc.get('id'),
                #     create_time__gt=last_game_time - timezone.timedelta(hours=24)
                # ).count(),
                # str(fifa_acc.get('play_last_24_hour')),
                int(fifa_acc.get('allowed_play_game_day')),
                int(fifa_acc.get('play_24_hour')),
                # int(fifa_acc.get('request_24_hour') or 0),
                # int(fifa_acc.get('login_48_hour') or 0),
                # int(fifa_acc.get('login_24_hour') or 0),
                int(fifa_acc.get('search_48_hour') or 0),
                str(TRADE_ACCESS_DICT.get(fifa_acc.get('trade_access'))),
                int(fifa_acc.get('count_packs') or 0),
                int(fifa_acc.get('done_moments') or 0),
                last_moment_time.replace(tzinfo=None) if last_moment_time else None,
                int(fifa_acc.get('daily_sbc_compeleted') or 0),
                fifa_acc.get('last_worker_description'),
                fifa_acc.get('last_worker_error_description'),
                str(fifa_acc.get('delete_console_reason')),
                str(fifa_acc.get('xbox_email')),
                str(fifa_acc.get('xbox_pass')),
                dict(CONSOLE_USER_MODE).get(fifa_acc.get('console_user_mode')) or '',
                # '', '',
                str(fifa_acc.get('last_worker_status')),
                str(fifa_acc.get('last_run_time')),
                str(fifa_acc.get('last_console_worker_status')),
                create_time.replace(tzinfo=None) if create_time else None,
                last_play_time.replace(tzinfo=None) if last_play_time else None,
                last_sbc_time.replace(tzinfo=None) if last_sbc_time else None,
                last_trade_time.replace(tzinfo=None) if last_trade_time else None,
                fifa_acc.get('console_trade_one_quality'),
                # fifa_acc.fifaaccountsquadgame_set.filter(
                #     difficulty='semi_pro'
                # ).count(),
                # fifa_acc.fifaaccountsquadgame_set.filter(
                #     difficulty='professional'
                # ).count(),
            ])
        wb.save(response)
        return response

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


class ConsolesReportPart3View(RequiredPermissionViewMixin, LoginRequiredMixin, TemplateView):
    required_permission__ = 'console_report__read'
    model = Console

    def get(self, request, *args, **kwargs):
        # last_sbc = SBCType.objects.filter(console_can_use=True, must_done=1).order_by('priority').last()
        # first_sbc = SBCType.objects.filter(console_can_use=True, must_done=1).order_by('priority').first()
        today = datetime.datetime.now()
        target_dayofweek = 4  # Thursday
        current_dayofweek = today.weekday()  # Today
        timezone_local_now = timezone.localtime()
        if target_dayofweek <= current_dayofweek:
            # target is in the current week
            last_thursday = today - datetime.timedelta(current_dayofweek - target_dayofweek)

        else:
            # target is in the previous week
            last_thursday = (today -
                             datetime.timedelta(weeks=1) +
                             datetime.timedelta(target_dayofweek - current_dayofweek))
        response = HttpResponse(content_type='application/vnd.ms-excel')
        response['Content-Disposition'] = f'attachment; filename="console_detail_part_three.xlsx"'
        wb = Workbook()
        ws = wb.active
        active_consoles = self.get_queryset().filter(is_active=True).order_by(
            'name'
        ).prefetch_related('fifaaccount_set')
        ws4 = wb.create_sheet('snipes detail')
        ws4.append(['console name', 'success 7', 'miss 7', 'success and miss 7', 'miss rate 7',
                    'success', 'miss', 'success and miss', 'miss rate'])
        for item in active_consoles:
            result = CloseWebAppSnipes.objects.filter(first_account__in=item.fifaaccount_set.all())
            success_7 = result.exclude(
                winner_account=None,
            ).filter(
                insert_time__gt=timezone_local_now - timezone.timedelta(days=7),
            ).annotate(
                transfer_coin=(F('player_price') - F('player_min_price_from_futbin')) - (
                        (F('player_price') + F('player_min_price_from_futbin')) * .05)
            ).aggregate(sum_transfer_coin=Sum('transfer_coin')).get('sum_transfer_coin')
            # miss_7 = result.filter(
            #     winner_account=None,
            #     insert_time__gt=timezone_local_now - timezone.timedelta(days=7),
            # ).annotate(
            #     transfer_coin=F('player_price') - F('player_min_price_from_futbin')
            # ).aggregate(sum_transfer_coin=Sum('transfer_coin')).get('sum_transfer_coin')
            success_and_miss_7 = result.filter(
                insert_time__gt=timezone_local_now - timezone.timedelta(days=7),
            ).annotate(
                transfer_coin=F('player_price') - F('player_min_price_from_futbin')
            ).aggregate(sum_transfer_coin=Sum('transfer_coin')).get('sum_transfer_coin')

            miss_7 = (success_and_miss_7 or 0) - (success_7 or 0)
            miss_rate_7 = (miss_7 / (success_and_miss_7 or 1)) * 100

            success = result.exclude(
                winner_account=None,
            ).annotate(
                transfer_coin=(F('player_price') - F('player_min_price_from_futbin')) - (
                        (F('player_price') + F('player_min_price_from_futbin')) * .05)
            ).aggregate(sum_transfer_coin=Sum('transfer_coin')).get('sum_transfer_coin')
            # miss = result.filter(
            #     winner_account=None,
            # ).annotate(
            #     transfer_coin=F('player_price') - F('player_min_price_from_futbin')
            # ).aggregate(sum_transfer_coin=Sum('transfer_coin')).get('sum_transfer_coin')
            success_and_miss = result.annotate(
                transfer_coin=F('player_price') - F('player_min_price_from_futbin')
            ).aggregate(sum_transfer_coin=Sum('transfer_coin')).get('sum_transfer_coin')
            miss = (success_and_miss or 0) - (success or 0)
            miss_rate = (miss / (success_and_miss or 1)) * 100
            ws4.append([
                item.name,
                str(success_7),
                str(miss_7),
                str(success_and_miss_7),
                str(miss_rate_7),
                str(success),
                str(miss),
                str(success_and_miss),
                str(miss_rate)
            ])

        wb.save(response)
        return response

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


class ConsolesReportPart4View(RequiredPermissionViewMixin, LoginRequiredMixin, TemplateView):
    required_permission__all = 'console_report__read__all'
    model = FifaAccount

    def get(self, request, *args, **kwargs):
        response = HttpResponse(content_type='application/vnd.ms-excel')
        response['Content-Disposition'] = f'attachment; filename="console_detail_part_four.xlsx"'
        wb = Workbook()
        ws = wb.active
        fifa_accounts = FifaAccount.objects.exclude(console=None).filter(
            Q(delete_console_reason=None) | Q(delete_console_reason=''),
        )
        trades_history = ConsoleTradeOneHistory.objects.exclude(fifa_account__console=None).filter(
            Q(fifa_account__delete_console_reason=None) | Q(fifa_account__delete_console_reason=''),
        ).order_by('fifa_account', '-create_time').distinct('fifa_account')
        ws4 = wb.create_sheet('trade detail')
        ws4.append(['console', 'account', 'bronze1', 'silver1', 'gold0', 'gold1', 'transfer list',
                    'quality', 'new quality'])
        for item in trades_history:
            ws4.append([
                getattr(item.fifa_account.console, 'name', '---'),
                item.fifa_account.user_name,
                item.club_bronze1_items,
                item.club_silver1_items,
                item.club_gold0_items,
                item.club_gold1_items,
                item.transfer_list_items_count,
                item.fifa_account.console_trade_one_quality,
                item.fifa_account.console_trade_one_quality_new,
            ])
        for account_item in fifa_accounts.exclude(id__in=trades_history.values_list('fifa_account__id', flat=True)):
            ws4.append([
                getattr(account_item.console, 'name', '---'),
                account_item.user_name,
                account_item.console_trade_one_quality,
                account_item.console_trade_one_quality_new,
            ])

        wb.save(response)
        return response

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


def check_verified_ip(request):
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        request_ip = x_forwarded_for.split(',')[0]
    else:
        request_ip = request.META.get('REMOTE_ADDR')
    if request_ip in VerifiedIp.objects.all().values_list('ip_address', flat=True):
        return JsonResponse({'ip': request_ip, 'verified': True})
    else:
        return JsonResponse({'ip': request_ip, 'verified': False})


class ConsoleListView(RequiredPermissionViewMixin, GenericFilterListView):
    required_permission__ = 'consoles_command__create'
    model = Console
    table_class = ConsoleTable
    page_header = _('Console List')
    filterset_class = ConsoleListFilter

    def get_extra_buttons(self):
        buttons = []
        range_count = self.get_queryset().count()
        range_number_min = int(self.request.GET.get('range_number_min', 0))
        range_number_max = int(self.request.GET.get('range_number_max', 0))
        range_number = ''
        if range_number_max and range_number_max and range_number_min < range_number_max:
            range_number = f'&range_number_min={range_number_min}&range_number_max={range_number_max}'
        if has_permission_exactly(self.request.user, 'manager_commands'):
            buttons.append({
                'url': f'{reverse_lazy("action-console")}?action=trade_one_all&state=deactive' + range_number,
                'text': f'DeActive Trade({range_count})',
                'color': 'btn-danger'

            })
            buttons.append({
                'url': f'{reverse_lazy("action-console")}?action=discharge_all&state=active' + range_number,
                'text': f'Active Discharge({range_count})',
                'color': 'btn-success'

            })
            buttons.append({
                'url': f'{reverse_lazy("action-console")}?action=discharge_all&state=deactive' + range_number,
                'text': f'DeActive Discharge({range_count})',
                'color': 'btn-danger'

            })
            buttons.append({
                'url': f'{reverse_lazy("action-console")}?action=squad_all&state=active' + range_number,
                'text': f'Active Squad({range_count})',
                'color': 'btn-success'

            })
            buttons.append({
                'url': f'{reverse_lazy("action-console")}?action=squad_all&state=deactive' + range_number,
                'text': f'DeActive Squad({range_count})',
                'color': 'btn-danger'

            })
            buttons.append({
                'url': f'{reverse_lazy("action-console")}?action=sbc_all&state=active' + range_number,
                'text': f'Active SBC({range_count})',
                'color': 'btn-success'

            })
            buttons.append({
                'url': f'{reverse_lazy("action-console")}?action=sbc_all&state=deactive' + range_number,
                'text': f'DeActive SBC({range_count})',
                'color': 'btn-danger'

            })
            buttons.append({
                'url': f'{reverse_lazy("action-console")}?action=active_all&state=active' + range_number,
                'text': f'Active({range_count})',
                'color': 'btn-success'

            })
            buttons.append({
                'url': f'{reverse_lazy("action-console")}?action=active_all&state=deactive' + range_number,
                'text': f'DeActive({range_count})',
                'color': 'btn-danger'

            })
        return buttons

    def get_queryset(self) -> QuerySet:
        query_set = super().get_queryset()
        query_set1 = query_set.distinct().order_by('name').annotate(
            trade_one_state=Case(
                When(Q(fifaaccount__run_console_trade_one=True) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('deactive')),
                When(Q(fifaaccount__run_console_trade_one=False) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('active')),
                # default=Value('active'),
                output_field=CharField()
            ),
            trade_one_text=Case(
                When(Q(fifaaccount__run_console_trade_one=True) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('Deactive Trade')),
                When(Q(fifaaccount__run_console_trade_one=False) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('Active Trade')),
                # default=Value('Active Trade'),
                output_field=CharField()
            ),

            discharge_state=Case(
                When(Q(fifaaccount__run_discharge=True) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('deactive')),
                When(Q(fifaaccount__run_discharge=False) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('active')),
                # default=Value('active'),
                output_field=CharField()
            ),
            discharge_text=Case(
                When(Q(fifaaccount__run_discharge=True) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('Deactive Discharge')),
                When(Q(fifaaccount__run_discharge=False) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('Active Discharge')),
                # default=Value('Active Discharge'),
                output_field=CharField()
            ),

            squad_state=Case(
                When(Q(fifaaccount__run_squad_battle=True) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('deactive')),
                When(Q(fifaaccount__run_squad_battle=False) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('active')),
                # default=Value('active'),
                output_field=CharField()
            ),
            squad_text=Case(
                When(Q(fifaaccount__run_squad_battle=True) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('Deactive Squad')),
                When(Q(fifaaccount__run_squad_battle=False) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('Active Squad')),
                # default=Value('Active Squad'),
                output_field=CharField()
            ),

            sbc_state=Case(
                When(Q(fifaaccount__run_sbc=True) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('deactive')),
                When(Q(fifaaccount__run_sbc=False) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('active')),
                # default=Value('active'),
                output_field=CharField()
            ),
            sbc_text=Case(
                When(Q(fifaaccount__run_sbc=True) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('Deactive SBC')),
                When(Q(fifaaccount__run_sbc=False) &
                     Q(Q(fifaaccount__delete_console_reason=None) | Q(fifaaccount__delete_console_reason='')),
                     then=Value('Active SBC')),
                # default=Value('Active SBC'),
                output_field=CharField()
            ),
            active_state=Case(
                When(is_active=True, then=Value('deactive')),
                default=Value('active'),
                output_field=CharField()
            ),
            active_text=Case(
                When(is_active=True, then=Value('Deactive')),
                default=Value('Active'),
                output_field=CharField()
            ),
        ).exclude(
            Q(trade_one_state=None) | Q(discharge_state=None) | Q(squad_state=None) | Q(sbc_state=None)
        )

        # query_set = query_set.annotate(
        #     fifa_account_list=Subquery(FifaAccount.objects.filter(console_id=OuterRef('pk')).values_list('id'))
        # )
        return query_set1

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


# todo : fix bellow and usage
class ConsoleAction(RequiredPermissionViewMixin, LoginRequiredMixin, TemplateView):
    template_name = 'public/success.html'
    required_permission__ = 'consoles_command__create'
    model = Console

    def get(self, request, *args, **kwargs):
        data = self.request.GET
        console_id = data.get('console_id')
        action = data.get('action')
        state = data.get('state')
        range_number_min = int(data.get('range_number_min', 0))
        range_number_max = int(data.get('range_number_max', 0))
        if console_id and action and state:
            console_object = Console.objects.get(id=console_id)
            if action == 'trade_one_one' and state == 'active':
                console_object.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                ).update(run_console_trade_one=True)
            elif action == 'trade_one_one' and state == 'deactive':
                console_object.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                ).update(run_console_trade_one=False)
            elif action == 'squad_one' and state == 'active':
                console_object.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                ).update(run_squad_battle=True)
            elif action == 'squad_one' and state == 'deactive':
                console_object.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                ).update(run_squad_battle=False)
            elif action == 'discharge_one' and state == 'active':
                console_object.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                ).update(run_discharge=True)
            elif action == 'discharge_one' and state == 'deactive':
                console_object.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                ).update(run_discharge=False)
            elif action == 'sbc_one' and state == 'active':
                console_object.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                ).update(run_sbc=True)
            elif action == 'sbc_one' and state == 'deactive':
                console_object.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                ).update(run_sbc=False)
            elif action == 'active_one' and state == 'deactive':
                console_object.is_active = False
                console_object.save()
            elif action == 'active_one' and state == 'active':
                console_object.is_active = True
                console_object.save()
            messages.success(request, f'action success : {console_object} {state} {action} ')
        elif action and state:
            user_consoles = self.get_queryset()
            if range_number_min and range_number_max and range_number_min < range_number_max:
                user_consoles = user_consoles.filter(name__in=list(range(range_number_min, range_number_max)))
            if action == 'trade_one_all' and state == 'deactive':
                FifaAccount.objects.exclude(console=None).filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    console__is_active=True, console__in=user_consoles
                ).update(run_console_trade_one=False)
            elif action == 'squad_all' and state == 'active':
                FifaAccount.objects.exclude(console=None).filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    console__is_active=True, console__in=user_consoles
                ).update(run_squad_battle=True)
            elif action == 'squad_all' and state == 'deactive':
                FifaAccount.objects.exclude(console=None).filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    console__is_active=True, console__in=user_consoles
                ).update(run_squad_battle=False)
            elif action == 'discharge_all' and state == 'active':
                FifaAccount.objects.exclude(console=None).filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    console__is_active=True, console__in=user_consoles
                ).update(run_discharge=True)
            elif action == 'discharge_all' and state == 'deactive':
                FifaAccount.objects.exclude(console=None).filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    console__is_active=True, console__in=user_consoles
                ).update(run_discharge=False)
            elif action == 'sbc_all' and state == 'active':
                FifaAccount.objects.exclude(console=None).filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    console__is_active=True, console__in=user_consoles
                ).update(run_sbc=True)
            elif action == 'sbc_all' and state == 'deactive':
                FifaAccount.objects.exclude(console=None).filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    console__is_active=True, console__in=user_consoles
                ).update(run_sbc=False)
            elif action == 'active_all' and state == 'deactive':
                user_consoles.update(is_active=False)
            elif action == 'active_all' and state == 'active':
                user_consoles.update(is_active=True)
        else:
            messages.error(request, message='somthing is wrong')
        # return redirect('console-list')
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

    def get_context_data(self, **kwargs):
        return {'message': 'Change Status Success', 'back_url': reverse_lazy("console-list")}

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


class StockMapView(TemplateView):
    template_name = 'account/stock_map.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['sign'] = self.request.GET.get('sign', 'ارز بازی')
        return context


class StockMapStocksHandler(View):
    def get(self, request, *args, **kwargs):
        sectors_code = []
        for investor_data in FifaAccount.objects.exclude(console=None).distinct('console__investor').values_list(
                'console__investor__id', 'console__investor__username'):
            sectors_code.append({"SectorCode": investor_data[0], "SectorName": investor_data[1]})
        return JsonResponse(sectors_code, safe=False)
        # return JsonResponse([{"SectorCode": "33", "SectorName": "ابزارپزشکی، اپتیکی و اندازه‌گیری"},
        #                      {"SectorCode": "10", "SectorName": "استخراج زغال سنگ"},
        #                      {"SectorCode": "14", "SectorName": "استخراج سایر معادن"},
        #                      {"SectorCode": "11", "SectorName": "استخراج نفت گاز و خدمات جنبی جز اکتشاف"},
        #                      {"SectorCode": "13", "SectorName": "استخراج کانه های فلزی"},
        #                      {"SectorCode": "73", "SectorName": "اطلاعات و ارتباطات"},
        #                      {"SectorCode": "52", "SectorName": "انبارداری و حمایت از فعالیتهای حمل و نقل"},
        #                      {"SectorCode": "70", "SectorName": "انبوه سازی، املاک و مستغلات"},
        #                      {"SectorCode": "22", "SectorName": "انتشار، چاپ و تکثیر"},
        #                      {"SectorCode": "76", "SectorName": "اوراق بهادار مبتنی بر دارایی فکری"},
        #                      {"SectorCode": "69", "SectorName": "اوراق تامین مالی"},
        #                      {"SectorCode": "59", "SectorName": "اوراق حق تقدم استفاده از تسهیلات مسکن"},
        #                      {"SectorCode": "57", "SectorName": "بانکها و موسسات اعتباری"},
        #                      {"SectorCode": "66", "SectorName": "بیمه وصندوق بازنشستگی به جزتامین اجتماعی"},
        #                      {"SectorCode": "45", "SectorName": "پیمانکاری صنعتی"},
        #                      {"SectorCode": "46", "SectorName": "تجارت عمده فروشی به جز وسایل نقلیه موتور"},
        #                      {"SectorCode": "50", "SectorName": "تجارت عمده وخرده فروشی وسائط نقلیه موتور"},
        #                      {"SectorCode": "26", "SectorName": "تولید محصولات کامپیوتری الکترونیکی ونوری"},
        #                      {"SectorCode": "41", "SectorName": "جمع آوری، تصفیه و توزیع آب"},
        #                      {"SectorCode": "02", "SectorName": "جنگلداری و ماهیگیری"},
        #                      {"SectorCode": "15", "SectorName": "حذف شده- فرآورده‌های غذایی و آشامیدنی"},
        #                      {"SectorCode": "24", "SectorName": "حذف شده-مواد و محصولات شیمیایی"},
        #                      {"SectorCode": "61", "SectorName": "حمل و نقل آبی"},
        #                      {"SectorCode": "51", "SectorName": "حمل و نقل هوایی"},
        #                      {"SectorCode": "60", "SectorName": "حمل ونقل، انبارداری و ارتباطات"},
        #                      {"SectorCode": "74", "SectorName": "خدمات فنی و مهندسی"},
        #                      {"SectorCode": "47", "SectorName": "خرده فروشی،باستثنای وسایل نقلیه موتوری"},
        #                      {"SectorCode": "34", "SectorName": "خودرو و ساخت قطعات"},
        #                      {"SectorCode": "19", "SectorName": "دباغی، پرداخت چرم و ساخت انواع پاپوش"},
        #                      {"SectorCode": "72", "SectorName": "رایانه و فعالیت‌های وابسته به آن"},
        #                      {"SectorCode": "01", "SectorName": "زراعت و خدمات وابسته"},
        #                      {"SectorCode": "32", "SectorName": "ساخت دستگاه‌ها و وسایل ارتباطی"},
        #                      {"SectorCode": "28", "SectorName": "ساخت محصولات فلزی"},
        #                      {"SectorCode": "35", "SectorName": "سایر تجهیزات حمل و نقل"},
        #                      {"SectorCode": "54", "SectorName": "سایر محصولات کانی غیرفلزی"},
        #                      {"SectorCode": "58", "SectorName": "سایر واسطه گریهای مالی"},
        #                      {"SectorCode": "56", "SectorName": "سرمایه گذاریها"},
        #                      {"SectorCode": "53", "SectorName": "سیمان، آهک و گچ"},
        #                      {"SectorCode": "X1", "SectorName": "شاخص"},
        #                      {"SectorCode": "39", "SectorName": "شرکتهای چند رشته ای صنعتی"},
        #                      {"SectorCode": "68", "SectorName": "صندوق سرمایه گذاری قابل معامله"},
        #                      {"SectorCode": "40", "SectorName": "عرضه برق، گاز، بخاروآب گرم"},
        #                      {"SectorCode": "23", "SectorName": "فراورده های نفتی، کک و سوخت هسته ای"},
        #                      {"SectorCode": "77", "SectorName": "فعالبت های اجاره و لیزینگ"},
        #                      {"SectorCode": "82", "SectorName": "فعالیت پشتیبانی اجرائی اداری وحمایت کسب"},
        #                      {"SectorCode": "71", "SectorName": "فعالیت مهندسی، تجزیه، تحلیل و آزمایش فنی"},
        #                      {"SectorCode": "63", "SectorName": "فعالیت های پشتیبانی و کمکی حمل و نقل"},
        #                      {"SectorCode": "90", "SectorName": "فعالیت های هنری، سرگرمی و خلاقانه"},
        #                      {"SectorCode": "93", "SectorName": "فعالیتهای فرهنگی و ورزشی"},
        #                      {"SectorCode": "67", "SectorName": "فعالیتهای کمکی به نهادهای مالی واسط"},
        #                      {"SectorCode": "27", "SectorName": "فلزات اساسی"},
        #                      {"SectorCode": "38", "SectorName": "قند و شکر"},
        #                      {"SectorCode": "98", "SectorName": "گروه اوراق غیرفعال"},
        #                      {"SectorCode": "25", "SectorName": "لاستیک و پلاستیک"},
        #                      {"SectorCode": "29", "SectorName": "ماشین آلات و تجهیزات"},
        #                      {"SectorCode": "31", "SectorName": "ماشین آلات و دستگاه‌های برقی"},
        #                      {"SectorCode": "36", "SectorName": "مبلمان و مصنوعات دیگر"},
        #                      {"SectorCode": "20", "SectorName": "محصولات چوبی"},
        #                      {"SectorCode": "44", "SectorName": "محصولات شیمیایی"},
        #                      {"SectorCode": "42", "SectorName": "محصولات غذایی و آشامیدنی به جز قند و شکر"},
        #                      {"SectorCode": "21", "SectorName": "محصولات کاغذی"},
        #                      {"SectorCode": "64", "SectorName": "مخابرات"},
        #                      {"SectorCode": "17", "SectorName": "منسوجات"},
        #                      {"SectorCode": "43", "SectorName": "مواد و محصولات دارویی"},
        #                      {"SectorCode": "55", "SectorName": "هتل و رستوران"},
        #                      {"SectorCode": "65", "SectorName": "واسطه‌گری‌های مالی و پولی"},
        #                      {"SectorCode": "49", "SectorName": "کاشی و سرامیک"}], safe=False)


class StockMapAlmasDataHandler(View):
    def get(self, request, *args, **kwargs):
        from accounts.console_bot_settings import allowed_discharge_time
        result_list = []
        lowest_run_hour = ConsoleBotSetting.objects.get(name='lowest_account_run_in_console_hour').int_value
        discharge_start_coin_greater = ConsoleBotSetting.objects.get(name='discharge_start_coin_greater').int_value
        discharge_start_coin_lower = ConsoleBotSetting.objects.get(name='discharge_start_coin_lower').int_value
        allowed_discharge_time_var = allowed_discharge_time()
        local_now = timezone.localtime()
        query = Console.objects.filter(is_active=True).annotate(
                inv_id=F('investor__id'),
                all_account_count=Coalesce(Subquery(FifaAccount.objects.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    console__id=OuterRef('pk'),
                ).values('console').annotate(
                    account_count=Count('id')
                ).values('account_count'), output_field=IntegerField()), Value(0)),
                pr=Coalesce(Subquery(FifaAccount.objects.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    account_played_games__gte=F('allowed_play_game'),
                    console__id=OuterRef('pk'),
                ).values('console').annotate(
                    account_count=Count('id')
                ).values('account_count'), output_field=IntegerField()), Value(0)),
                last_accounts_worker_id=Subquery(SBCWorker.objects.filter(
                    fifa_account__console__id=OuterRef('pk'),
                ).order_by('status_change_time').values('id').reverse()[:1]),
                last_active_account_worker_id=Subquery(SBCWorker.objects.filter(
                    Q(fifa_account__delete_console_reason=None) | Q(fifa_account__delete_console_reason=''),
                    id__gte=OuterRef('last_accounts_worker_id'),
                    fifa_account__console__id=OuterRef('pk'),
                    is_done=False, has_error=False, running_platform__in=['console', 'console_web_pc'],
                ).order_by('status_change_time').values('id').reverse()[:1]),
        ).order_by('name')
        related_quieries = list(SBCWorker.objects.filter(
            id__in=query.values_list('last_active_account_worker_id', flat=True)
        ).annotate(
            fifa_acc_id=F('fifa_account__id'),
            fifa_acc_user_name=F('fifa_account__user_name'),
            fifa_acc_name_in_console=F('fifa_account__name_in_console'),
            fifa_acc_platform=F('fifa_account__platform'),
            fifa_acc_any_desk=F('fifa_account__pc__any_desk_code'),
        ))
        for item in query:
            # last_worker = SBCWorker.objects.filter(
            #     is_done=False, has_error=False, running_platform='console',
            #     fifa_account__console=item,
            # ).annotate(
            #     fifa_acc_id=F('fifa_account__id'),
            #     fifa_acc_user_name=F('fifa_account__user_name'),
            #     fifa_acc_name_in_console=F('fifa_account__name_in_console'),
            #     fifa_acc_platform=F('fifa_account__platform'),
            #     fifa_acc_any_desk=F('fifa_account__pc__any_desk_code'),
            # ).order_by('status_change_time').last()
            status_color = 1
            last_active_id = item.last_active_account_worker_id
            if last_active_id:
                for item_3 in related_quieries:
                    if item_3.id == item.last_active_account_worker_id:
                        last_worker = item_3
                        break
                last_status = last_worker.status
                if (last_status.startswith('Trade bidding') and
                    local_now - timezone.timedelta(minutes=200) > last_worker.status_change_time
                ) or (last_status.startswith('bid waiting') and
                      local_now - timezone.timedelta(minutes=70) > last_worker.status_change_time
                ) or (last_status.startswith('sbc id') and
                        local_now - timezone.timedelta(minutes=60) > last_worker.status_change_time
                ) or (local_now - timezone.timedelta(minutes=40) > last_worker.status_change_time):
                    status_color = -5
                elif last_status in RED_STATUS:
                    status_color = -2
            else:
                last_worker = SBCWorker.objects.filter(
                    running_platform='console', fifa_account__console=item
                ).annotate(
                    fifa_acc_id=F('fifa_account__id'),
                    fifa_acc_user_name=F('fifa_account__user_name'),
                    fifa_acc_name_in_console=F('fifa_account__name_in_console'),
                    fifa_acc_platform=F('fifa_account__platform'),
                    fifa_acc_any_desk=F('fifa_account__pc__any_desk_code'),
                ).order_by('status_change_time').last()
                if last_worker:
                    need_work_2 = FifaAccount.objects.filter(
                        console=item,
                    ).annotate(
                        account_24_played_games=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
                            fifa_account__id=OuterRef('pk'),
                            create_time__gt=local_now - timezone.timedelta(hours=24)
                        ).values('fifa_account').annotate(
                            played_count=Count('id', output_field=IntegerField())
                        ).values('played_count'), output_field=IntegerField()), Value(0)),
                        account_all_played_games=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
                            fifa_account__id=OuterRef('pk'),
                            # create_time__gt=now_local_time - timezone.timedelta(hours=24)
                        ).values('fifa_account').annotate(
                            played_count_all=Count('id', output_field=IntegerField())
                        ).values('played_count_all'), output_field=IntegerField()), Value(0)),
                        uncompleted_sbc=Value(SBCType.objects.filter(console_can_use=True, must_done=1).exclude(
                            id__in=SBCProcess.objects.filter(
                                worker_id=last_worker.id, is_done=True
                            ).distinct('sbc_type').values_list('sbc_type__id', flat=True)
                        ).count()),

                        can_play_squad=ExpressionWrapper(Q((Q(account_played_games__lt=F('allowed_play_game')) | Q(squad_special_game_one=False) |
                           Q(squad_special_game_two=False)) & Q(run_squad_battle=True) &
                          Q(allowed_play_game_day__gt=F('account_24_played_games')) &
                          # Q(account_played_games__lt=F('allowed_play_game')) &
                          # Q(account_31_day_played_games__lt=Value(88))
                          (Q(account_all_played_games__lt=Value(12)) | Q(account_all_played_games__gt=Value(400)) |
                           Q(console__name__in=list(range(9000, 9500))))
                          ), output_field=BooleanField()),
                        can_discharge=ExpressionWrapper(Q(
                            Q(run_discharge=True) & Q(credit__gt=discharge_start_coin_greater) &
                         Q(credit__lt=discharge_start_coin_lower) & Value(allowed_discharge_time_var)
                        ), output_field=BooleanField()),
                        can_sbc=ExpressionWrapper(
                            Q(Q(run_sbc=True) & Q(credit__gt=8000) & Q(uncompleted_sbc__gt=0)), output_field=BooleanField()),
                        can_console_trade=ExpressionWrapper(
                            Q(trade_access__in=['0', '1', '3']) & (Q(run_console_trade_one=True) & Q(credit__gt=10000) &
                           Q(is_running_console_trade_one=False)) | Q(is_running_console_trade_one=True),
                            output_field=BooleanField()),

                    ).filter(
                            Q(stop_for_update_game=False) & Q(
                                last_run_time__lt=local_now - timezone.timedelta(hours=lowest_run_hour)) &
                            (Q(can_play_squad=True) | Q(can_discharge=True) | Q(can_sbc=True) | Q(can_console_trade=True))
                        # (((Q(account_played_games__lt=F('allowed_play_game')) | Q(squad_special_game_one=False) |
                        #    Q(squad_special_game_two=False)) & Q(run_squad_battle=True)) |
                        #  (Q(run_discharge=True) &
                        #   Q(credit__gt=ConsoleBotSetting.objects.get(name='discharge_start_coin_greater').int_value)) |
                        #  (Q(run_sbc=True) & Q(credit__gt=16000) & Q(uncompleted_sbc__gt=0)))
                    ).exclude(
                        name_in_console='key'
                    ).order_by('last_run_time').first()
                    if need_work_2:
                        if local_now - timezone.timedelta(minutes=220) < last_worker.status_change_time:
                            status_color = 0
                        else:
                            status_color = -1
                        last_status = 'resting ...'
                    else:
                        status_color = 5
                        last_status = 'all account is done'
                else:
                    continue
                    # last_worker = SBCWorker.objects.last()
                    # last_status = 'Fake Status'
            result_list.append(
                {"n": f"{last_worker.fifa_acc_id}",
                 "s": f"{item.name}",
                 "c": f"{last_worker.fifa_acc_name_in_console}",
                 "sc": f"{item.inv_id}",
                 "pr": item.pr,
                 "cr": status_color, "v": item.all_account_count})

        return JsonResponse(result_list, safe=False)


class CommandView(RequiredPermissionViewMixin, LoginRequiredMixin, TemplateView):
    required_permission__all = 'command_menu'

    template_name = 'account/command_page.html'

    def get(self, request, *args, **kwargs):
        return super().get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        command_name = request.POST.get('command_name', None)
        if command_name == 'reset_first_week':
            FifaAccount.objects.all().update(squad_special_game_two=True, squad_special_game_one=False,
                                             account_played_games=0)
            messages.success(request, 'Reset games success')
        elif command_name == 'special_two':
            FifaAccount.objects.all().update(squad_special_game_two=False)
            messages.success(request, 'Active special two success')
        elif command_name == 'force_discharge':
            FifaAccount.objects.all().update(run_force_discharge=True)
            messages.success(request, 'Active Force Discharge')
        elif command_name == 'stop_for_update_game__xboxs':
            query_count = FifaAccount.objects.filter(
                Q(delete_console_reason=None) | Q(delete_console_reason=''),
                platform='xboxs', ).update(stop_for_update_game=True)
            messages.success(request, f'{query_count} account deactivated until update')
        elif command_name == 'continue_after_update_game__xboxs':
            query_count = FifaAccount.objects.filter(
                Q(delete_console_reason=None) | Q(delete_console_reason=''),
                platform='xboxs', ).update(stop_for_update_game=False)
            messages.success(request, f'{query_count} account deactivated until update')
        elif command_name == 'stop_for_update_game__xbox360':
            query_count = FifaAccount.objects.filter(
                Q(delete_console_reason=None) | Q(delete_console_reason=''),
                platform='xbox360', ).update(stop_for_update_game=True)
            messages.success(request, f'{query_count} account deactivated until update')
        elif command_name == 'continue_after_update_game__xbox360':
            query_count = FifaAccount.objects.filter(
                Q(delete_console_reason=None) | Q(delete_console_reason=''),
                platform='xbox360', ).update(stop_for_update_game=False)
            messages.success(request, f'{query_count} account deactivated until update')
        elif command_name == 'delete_last_active_sbc_processes':
            last_active_sbc_type = SBCType.objects.filter(must_done=1).first()
            if last_active_sbc_type:
                counter = SBCProcess.objects.filter(sbc_type=last_active_sbc_type).delete()
                messages.success(
                    request,
                    f'sbc number {last_active_sbc_type.sbc_number} processes has been deleted , count : {counter[0]}')
            else:
                messages.success(request, f'no active sbc found')
        elif command_name == 'fix_sbc_solution':
            accounts = FifaAccountLog.objects.filter(description__icontains='need to check sbc solution',
                                                     log_time__gt=timezone.localtime() - timezone.timedelta(
                                                         hours=24)).distinct('fifa_account')
            sbc_processes = SBCProcess.objects.filter(
                worker__fifa_account__id__in=accounts.values_list('fifa_account__id', flat=True)
            ).delete()
            messages.success(request, f'{sbc_processes[0]} sbc processes removed')
        elif command_name == 'set_week_allowed_play_game':
            command_count = request.POST.get('command_count', None)
            if command_count is not None:
                FifaAccount.objects.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason=''),
                    console__name__in=list(range(0, 9000))
                ).update(allowed_play_game=int(command_count))
                messages.success(request, f'allowed play game week changed to {command_count}')
            else:
                messages.warning(request, f'This Command Need Set Number')
        elif command_name == 'consoles_dont_sleep_after_work':
            command_file = request.FILES.get('command_file')
            consoles_name = []
            if command_file:
                wb_obj = openpyxl.load_workbook(command_file)
                sheet_obj = wb_obj.active
                max_row = sheet_obj.max_row
                for i in range(2, max_row + 1):
                    console_name = sheet_obj.cell(row=i, column=1).value
                    consoles_name.append(console_name)
            consoles_ = Console.objects.filter(is_active=True)
            if consoles_name:
                consoles_ = consoles_.filter(name__in=consoles_name)
            command_items = consoles_.update(turn_off_after_work=False)
            messages.success(request, f'{command_items} consoles will not sleep after work')
        elif command_name == 'consoles_sleep_after_work':
            command_file = request.FILES.get('command_file')
            consoles_name = []
            if command_file:
                wb_obj = openpyxl.load_workbook(command_file)
                sheet_obj = wb_obj.active
                max_row = sheet_obj.max_row
                for i in range(2, max_row + 1):
                    console_name = sheet_obj.cell(row=i, column=1).value
                    if console_name:
                        consoles_name.append(console_name)
            consoles_ = Console.objects.filter(is_active=True)
            if consoles_name:
                consoles_ = consoles_.filter(name__in=consoles_name)
            command_items = consoles_.update(turn_off_after_work=True)
            messages.success(request, f'{command_items} consoles will sleep after work')
        elif command_name == 'remove_new_disables_information':
            new_disabled_accounts = FifaAccount.objects.filter(
                delete_console_reason='account_disable',
                last_run_time__lt=timezone.localtime() - timezone.timedelta(days=1),
                last_run_time__gt=timezone.localtime() - timezone.timedelta(days=31),
                credit__gt=1
            )
            new_disabled_count = new_disabled_accounts.count()
            delete_process = SBCProcess.objects.filter(worker__fifa_account__in=new_disabled_accounts).delete()
            new_disabled_accounts.update(credit=0)
            messages.success(request, f'{new_disabled_count} disabled accounts information removed , {delete_process}')
        else:
            messages.warning(request, f'Command not found : {command_name}')

        return HttpResponseRedirect(reverse('commands-view'))


class PackItemListView(GenericListView):
    model = ItemPack
    table_class = PackItemTable

    def get_extra_buttons(self):
        buttons = []
        if has_permission_exactly(self.request.user, 'daily_credit_generate__read__all'):
            buttons.append({
                'url': f'{reverse_lazy("pack-item-list")}?untradeable=true',
                'text': f'Untradeable',
                'color': 'btn-danger'

            })
        return buttons

    def get_table_data(self):
        query = self.get_queryset()
        if not self.request.GET.get('untradeable'):
            query = query.exclude(pack_value=0)
        packs_id = query.values('pack_id').order_by('pack_id').annotate(
            count_pack_id=Count('pack_value'),
            sum_pack_id=Sum('pack_value'),
            avg_pack_id=F('sum_pack_id') / F('count_pack_id')
        )
        this_year_packs = query.filter(
            create_time__gt=timezone.localtime().replace(year=2023, month=9, day=20)
        ).values('pack_id').order_by('pack_id').annotate(
            count_pack_id=Count('pack_value'),
            sum_pack_id=Sum('pack_value'),
            avg_pack_id=F('sum_pack_id') / F('count_pack_id')
        )
        packs_7_days = query.values('pack_id').order_by('pack_id').filter(
            create_time__gt=timezone.localtime() - timezone.timedelta(days=7)
        ).annotate(
            count_pack_id=Count('pack_value'),
            sum_pack_id=Sum('pack_value'),
            avg_pack_id=F('sum_pack_id') / F('count_pack_id')
        )
        if timezone.localtime() > timezone.localtime().replace(hour=21, minute=30):
            sbc_daily_reset_time = timezone.localtime().replace(hour=21, minute=30)
        else:
            sbc_daily_reset_time = timezone.localtime().replace(hour=21, minute=30) - timezone.timedelta(days=1)
        packs_last_sbc_day = query.values('pack_id').order_by('pack_id').filter(
            create_time__gt=sbc_daily_reset_time
        ).annotate(
            count_pack_id=Count('pack_value'),
            sum_pack_id=Sum('pack_value'),
            avg_pack_id=F('sum_pack_id') / F('count_pack_id')
        )

        packs_item_data = []
        with open(os.path.join(BASE_DIR, 'accounts/packs_data.xhtml'), encoding='utf-8') as packs_data_file:
            packs_data_file_text = packs_data_file.read()
            for pack_item_data in packs_id:
                pack_id = pack_item_data.get("pack_id")
                group_name = re.search(
                    f'PACK_{pack_id}_NAME"><source>([^<]+)</source>',
                    packs_data_file_text.replace('\n', '').replace('\t', '')
                )
                if group_name:
                    pack_name = group_name.group(1)
                else:
                    pack_name = 'Not Found'
                count_pack_id_7_days = 0
                sum_pack_id_7_days = 0
                avg_pack_id_7_days = 0
                for pack_item_data_2 in packs_7_days:
                    if pack_item_data_2.get('pack_id') == pack_item_data.get('pack_id'):
                        count_pack_id_7_days = pack_item_data_2.get('count_pack_id')
                        sum_pack_id_7_days = pack_item_data_2.get('sum_pack_id')
                        avg_pack_id_7_days = pack_item_data_2.get('avg_pack_id')
                        break
                this_year_pack_count = 0
                this_year_pack_sum = 0
                this_year_pack_avg = 0
                for pack_item_data_3 in this_year_packs:
                    if pack_item_data_3.get('pack_id') == pack_item_data.get('pack_id'):
                        this_year_pack_count = pack_item_data_3.get('count_pack_id')
                        this_year_pack_sum = pack_item_data_3.get('sum_pack_id')
                        this_year_pack_avg = pack_item_data_3.get('avg_pack_id')
                        break
                count_pack_id_last_sbc_day = 0
                for pack_item_data_3 in packs_last_sbc_day:
                    if pack_item_data_3.get('pack_id') == pack_item_data.get('pack_id'):
                        count_pack_id_last_sbc_day = pack_item_data_3.get('count_pack_id')
                        break
                packs_item_data.append({
                    'pack_name': pack_name,
                    'pack_id': pack_item_data.get('pack_id'),
                    # 'count_pack_id': pack_item_data.get('count_pack_id'),
                    # 'sum_pack_id': number_convertor_to_milion(pack_item_data.get('sum_pack_id')),
                    'count_pack_id': '{:,}'.format(this_year_pack_count),
                    'sum_pack_id': number_convertor_to_milion(this_year_pack_sum),
                    'avg_pack_id': str('{:,}'.format(this_year_pack_avg)) + '-' + str('{:,}'.format(pack_item_data.get('avg_pack_id'))),
                    'count_pack_id_7_days': '{:,}'.format(count_pack_id_7_days),
                    'sum_pack_id_7_days': number_convertor_to_milion(sum_pack_id_7_days),
                    'avg_pack_id_7_days': '{:,}'.format(avg_pack_id_7_days),
                    'count_pack_id_last_sbc_day': '{:,}'.format(count_pack_id_last_sbc_day),
                    'fut_mind_link': f"https://futmind.com/pack/{pack_item_data.get('pack_id')}/"
                })
            pass
        return packs_item_data


class ItemPackChartReportView(LoginRequiredMixin, RequiredPermissionViewMixin, FilterView):
    template_name = 'generic_views/filter_list_view.html'
    required_permission__all = 'manager_commands'
    model = ItemPack
    filterset_class = ItemPackChartReportFilterSet
    dashboard_layout = DashboardLayout(
        DashboardRow(
            ItemPackChartReportChartDashboardCard,
            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_local_timezone(request):
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        request_ip = x_forwarded_for.split(',')[0]
    else:
        request_ip = request.META.get('REMOTE_ADDR')
    return JsonResponse({'local_timezone': timezone.localtime().isoformat(), 'request_ip': request_ip})


def get_last_version(request):
    last_version = ProgramVersion.objects.order_by('-id').values()[0]
    return JsonResponse(last_version)


def get_chrome_last_version(request, version):
    return HttpResponse(version)

# don't need storage if get_chrome_last_version always return that version u request :)
# def get_chrome_storage(request):
#     with open(str(BASE_DIR)+'/accounts/chrome_storage.xml', 'r') as chrome_storage_file:
#         chrome_storage_data = chrome_storage_file.read()
#     return HttpResponse(chrome_storage_data, content_type='text/xml')


def get_chrome_version(request, version_number, file_name):
    try:
        file_code = open(str(BASE_DIR)+f'/accounts/chrome_version/{version_number}/{file_name}', 'rb')
        return FileResponse(file_code)
    except Exception as error:
        return HttpResponse(f'error happend : {str(error)}')


# todo : this url created for test how many download happend. can remove after work done. also remove usage of url.
def get_chrome_version_2(request, version_number, file_name, account_name):
    try:
        FIFA_REPORT_TOKEN = '1980303938:AAH9LtY6_pxOHJ226xtZmJUghAOmmnSOmAE'
        url = f'https://api.telegram.org/bot{FIFA_REPORT_TOKEN}/sendMessage'
        text = f'getting web driver. account {account_name} version {version_number}'
        params = {
            'chat_id': ARZBAZI_REPORT_GROUP_ID,
            'text': text,
            'message_thread_id': ARZBAZI_REPORT_TOPIC_LOGS_THREAD_MESSAGE_ID,
        }
        requests.get(url, params=params)
        # bot = telepot.Bot(FIFA_REPORT_TOKEN)
        # bot.sendMessage('-1001711538724',
        #                 f'getting web driver. account {account_name} version {version_number}')
        file_code = open(str(BASE_DIR)+f'/accounts/chrome_version/{version_number}/{file_name}', 'rb')
        return FileResponse(file_code)
    except Exception as error:
        return HttpResponse(f'error happend : {str(error)}')


class DailyCreditGeneratedReportView(LoginRequiredMixin, RequiredPermissionViewMixin, FilterView):
    template_name = 'generic_views/filter_list_view.html'
    required_permission__all = 'daily_credit_generate__read__all'
    page_header = _('Daily Credit Generated')
    model = FifaAccount
    filterset_class = DailyCreditGeneratedReportFilterSet

    dashboard_layout = DashboardLayout(
        DashboardRow(
            # DailyCreditGeneratedChartDashboardCard,
            InvestTradeSalaryChartDashboardCard,
            InvestTradeSalaryGenerateChartDashboardCard,
            ConsoleInvestTradeItemsCountLogChartDashboardCard,
            ConsoleInvestTradeWinItemsCountLogChartDashboardCard,
            ConsoleInvestTradeSoldItemsCountLogChartDashboardCard,
            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_card_data(self):
        cards_data = []
        queryset = FifaAccountCreditLog.objects.filter(
            Q(fifa_account__delete_console_reason=None) | Q(fifa_account__delete_console_reason='')
        ).exclude(
            Q(fifa_account__console=None) | Q(fifa_account__console__investor=None)
        ).exclude(
            fifa_account__console__investor__id=18
        ).annotate(
            create_time_epoch=Extract('create_time', 'epoch')
        ).filter(create_time__gt=timezone.datetime(year=2023, month=6, day=1, hour=16))
        # queryset = self.filterset_class(data=self.request.GET, queryset=queryset).qs
        last_salary = queryset.last()
        if last_salary:
            a = queryset.values('create_time').order_by('create_time').annotate(
                formatted_create_time=ToCharTZ('create_time', TIME_ZONE, 'dd.MM.yyyy HH24'),
                sum_today_console_trade_salary=Sum('today_console_trade_salary'),
            ).last().get('sum_today_console_trade_salary', 0)
            cards_data.append({'name': 'Salary',
                               'info': f'{number_convertor_to_milion(a)}',
                               'box_css_class': 'fw-bold'})
        generate_24_hour = queryset.filter(
            # create_time__gte=timezone.localtime() - timezone.timedelta(hours=24)
            create_time_epoch__gte=(timezone.localtime() - timezone.timedelta(hours=24)).timestamp()
        ).aggregate(
            sum_invest_trade_generation=Sum('invest_trade_generation'),
        ).get('sum_invest_trade_generation') or 0
        cards_data.append({'name': 'Generate 24 H',
                           'info': f'{number_convertor_to_milion(generate_24_hour)}',
                           'box_css_class': 'fw-bold'})
        generate_7_days = queryset.filter(
            create_time_epoch__gte=(timezone.localtime() - timezone.timedelta(days=7)).timestamp()
        ).values('create_time').order_by('create_time').aggregate(
            sum_invest_trade_generation=Sum('invest_trade_generation'),
        ).get('sum_invest_trade_generation', 0)
        cards_data.append({'name': 'Generate 7 Days',
                           'info': f'{number_convertor_to_milion(generate_7_days)}',
                           'box_css_class': 'fw-bold'})
        generate_30_days = queryset.filter(
            create_time_epoch__gte=(timezone.localtime() - timezone.timedelta(days=30)).timestamp()
        ).values('create_time').order_by('create_time').aggregate(
            sum_invest_trade_generation=Sum('invest_trade_generation'),
        ).get('sum_invest_trade_generation', 0)
        cards_data.append({'name': 'Generate 30 Days',
                           'info': f'{number_convertor_to_milion(generate_30_days)}',
                           'box_css_class': 'fw-bold'})

        queryset3 = ConsoleInvestTradeItemsCountLog.objects.filter(
            Q(fifa_account__delete_console_reason=None) | Q(fifa_account__delete_console_reason='')
        ).exclude(
            Q(fifa_account__console=None) | Q(fifa_account__console__investor=None)
        ).exclude(
            fifa_account__console__investor__id=18
        ).annotate(
            create_time_epoch=Extract('create_time', 'epoch')
        ).filter(create_time_epoch__gte=(timezone.localtime() - timezone.timedelta(hours=24)).timestamp())
        win_items_24_hour = queryset3.aggregate(
            sum_added_win_items=Sum('added_win_items')).get('sum_added_win_items', None) or 0
        cards_data.append({'name': 'Win 24 H',
                           'info': f'{number_convertor_to_milion(win_items_24_hour)}',
                           'box_css_class': 'fw-bold'})
        queryset2 = ConsoleInvestTradeItemsCountLog.objects.filter(
            Q(fifa_account__delete_console_reason=None) | Q(fifa_account__delete_console_reason='')
        ).exclude(
            Q(fifa_account__console=None) | Q(fifa_account__console__investor=None)
        ).exclude(
            fifa_account__console__investor__id=18
        ).annotate(
            create_time_epoch=Extract('create_time', 'epoch')
        ).filter(create_time_epoch__gte=(timezone.localtime() - timezone.timedelta(hours=24)).timestamp())
        # queryset2 = self.filterset_class(data=self.request.GET, queryset=queryset2).qs
        sold_items_24 = queryset2.aggregate(
            sum_added_sold_items=Sum('added_sold_items')).get('sum_added_sold_items', 0) or 0
        cards_data.append({'name': 'Sold 24 Hour',
                           'info': f'{number_convertor_to_milion(sold_items_24)}',
                           'box_css_class': 'fw-bold'})

        #####
        fifa_accounts = FifaAccount.objects.filter(
            Q(delete_console_reason=None) | Q(delete_console_reason='')
        ).exclude(
            Q(console=None) | Q(console__investor=None)
        ).exclude(
            console__investor__id=18
        )
        # console_trade_histories = ConsoleTradeOneHistory.objects.filter(
        #     Q(bought_items_managed=True) | Q(list_try_count__gte=1),
        #     fifa_account__id__in=queryset.values_list('fifa_account__id', flat=True),
        # ).exclude(
        #     fifa_account__console__investor__id=18
        # ).order_by('fifa_account', '-create_time').distinct('fifa_account').values_list('id', flat=True)
        # console_trade_histories = ConsoleTradeOneHistory.objects.filter(id__in=console_trade_histories).annotate(
        #     bronze_1_items=F('club_bronze1_items') + Case(When(quality_name='bronze1',
        #                                                        then=F('transfer_list_items_count')), default=0),
        #     silver_1_items=F('club_silver1_items') + Case(When(quality_name='silver1',
        #                                                        then=F('transfer_list_items_count')), default=0),
        #     gold_0_items=F('club_gold0_items') + Case(When(quality_name='gold0',
        #                                                    then=F('transfer_list_items_count')), default=0),
        #     gold_1_items=F('club_gold1_items') + Case(When(quality_name='gold1',
        #                                                    then=F('transfer_list_items_count')), default=0),
        #     position_modifier_items=F('club_position_modifier_items') + Case(
        #         When(quality_name='position_modifier', then=F('transfer_list_items_count')), default=0),
        #     stock=Case(
        #         When(quality_name='bronze1', then=F('transfer_list_items_count') + F('club_bronze1_items')),
        #         When(quality_name='silver1', then=F('transfer_list_items_count') + F('club_silver1_items')),
        #         When(quality_name='gold0', then=F('transfer_list_items_count') + F('club_gold0_items')),
        #         When(quality_name='gold1', then=F('transfer_list_items_count') + F('club_gold1_items')),
        #         When(quality_name='position_modifier',
        #              then=F('transfer_list_items_count') + F('club_position_modifier_items')),
        #         default=0),
        # )
        # club_bronze1_items = '{:,}'.format(
        #     console_trade_histories.aggregate(Sum('bronze_1_items')).get('bronze_1_items__sum') or 0)
        # club_silver1_items = '{:,}'.format(
        #     console_trade_histories.aggregate(Sum('silver_1_items')).get('silver_1_items__sum') or 0)
        # club_gold0_items = '{:,}'.format(
        #     console_trade_histories.aggregate(Sum('gold_0_items')).get('gold_0_items__sum') or 0)
        # club_gold1_items = '{:,}'.format(
        #     console_trade_histories.aggregate(Sum('gold_1_items')).get('gold_1_items__sum') or 0)
        # club_position_modifier_items = '{:,}'.format(
        #     console_trade_histories.aggregate(Sum('position_modifier_items')).get('position_modifier_items__sum') or 0)
        sane_fifa_account_current_items = FifaAccountCurrentItems.objects.filter(
            Q(fifa_account__delete_console_reason=None) | Q(fifa_account__delete_console_reason=''),
            fifa_account__last_run_time__gt=timezone.localtime().replace(year=2024, month=10, day=1)
        )
        club_bronze1_items = sane_fifa_account_current_items.filter(update_time__gt=timezone.localtime().replace(year=2023, month=9, day=18)).aggregate(sum_items=Sum('club_bronze1_tradable_items')).get('sum_items')
        club_silver0_items = sane_fifa_account_current_items.filter(update_time__gt=timezone.localtime().replace(year=2023, month=9, day=18)).aggregate(sum_items=Sum('club_silver0_tradable_items')).get('sum_items')
        club_silver1_items = sane_fifa_account_current_items.filter(update_time__gt=timezone.localtime().replace(year=2023, month=9, day=18)).aggregate(sum_items=Sum('club_silver1_tradable_items')).get('sum_items')
        club_gold0_items = sane_fifa_account_current_items.filter(update_time__gt=timezone.localtime().replace(year=2023, month=9, day=18)).aggregate(sum_items=Sum('club_gold0_tradable_items')).get('sum_items')
        club_gold1_items = sane_fifa_account_current_items.filter(update_time__gt=timezone.localtime().replace(year=2023, month=9, day=18)).aggregate(sum_items=Sum('club_gold1_tradable_items')).get('sum_items')
        bronze1_data = f"{fifa_accounts.filter(console_trade_one_quality='bronze1').count()} - {club_bronze1_items}"
        silver0_data = f"{fifa_accounts.filter(console_trade_one_quality='silver0').count()} - {club_silver0_items}"
        silver1_data = f"{fifa_accounts.filter(console_trade_one_quality='silver1').count()} - {club_silver1_items}"
        gold0_data = f"{fifa_accounts.filter(console_trade_one_quality='gold0').count()} - {club_gold0_items}"
        gold1_data = f"{fifa_accounts.filter(console_trade_one_quality='gold1').count()} - {club_gold1_items}"
        # position_modifier_data = f"{fifa_accounts.filter(console_trade_one_quality='position_modifier').count()} - {club_position_modifier_items}"
        cards_data.append({'name': 'Gold Rare',
                           'info': gold1_data,
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'Gold Common',
                           'info': gold0_data,
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'Silver Rare',
                           'info': silver1_data,
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'Silver Common',
                           'info': silver0_data,
                           'box_css_class': 'fw-bold'})
        cards_data.append({'name': 'Bronze Rare',
                           'info': bronze1_data,
                           'box_css_class': 'fw-bold'})
        # cards_data.append({'name': 'Position Modifier',
        #                    'info': position_modifier_data,
        #                    'box_css_class': 'fw-bold'})

        intact_accounts = FifaAccount.objects.exclude(console__name=None).filter(
            Q(delete_console_reason=None) | Q(delete_console_reason='')).count()
        cards_data.append({'name': 'All Accounts',
                           'info': f'{intact_accounts}',
                           'box_css_class': 'fw-bold'})

        sbc_process = SBCProcess.objects.filter(
            sbc_number__in=SBCType.objects.exclude(
                Q(sbc_number=1) | Q(sbc_number=2) | Q(sbc_number=3) | Q(sbc_number=4)
            ).filter(
                console_can_use=True, must_done=1
            ).values_list('sbc_number', flat=True),
            is_done=True
        ).distinct('worker__fifa_account', 'sbc_type')
        completed_account = sbc_process.distinct('worker__fifa_account').count()
        completed_process = sbc_process.count()
        cards_data.append({'name': 'SBC Completed',
                           'info': f'{completed_account} - {completed_process}',
                           'box_css_class': 'fw-bold'})
        invest_trade_24_hour = ConsoleInvestTradeItemsCountLog.objects.filter(
            create_time__gt=timezone.localtime() - timezone.timedelta(hours=24)
        )
        invest_trade_24_hour_account = invest_trade_24_hour.distinct('fifa_account').count()
        invest_trade_24_hour_round = invest_trade_24_hour.aggregate(
            sum_complete_trade_count_new=Sum('complete_trade_count_new')
        ).get('sum_complete_trade_count_new') or 0
        cards_data.append({'name': 'Trade Round',
                           'info': f'{invest_trade_24_hour_account} - {invest_trade_24_hour_round}',
                           'box_css_class': 'fw-bold'})


        return cards_data

    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


class FifaAccountWorkErrorListView(GenericFilterListView):
    model = FifaAccountWorkError
    table_class = FifaAccountWorkErrorListTable
    filterset_class = FifaAccountWorkErrorListFilterSet
    page_header = _('Fifa Accounts Work Error')

    def get_queryset(self):
        query = super().get_queryset()
        query = query.exclude(fifa_account__console=None).distinct('id', 'fifa_account')
        return query


class FifaAccountDetailWorkerErrorListView(GenericFilterListView):
    model = FifaAccountWorkError
    table_class = FifaAccountDetailWorkErrorListTable
    filterset_class = FifaAccountDetailWorkerErrorListFilterSet
    back_url = reverse_lazy('fifa-account-worker-error-list')

    def page_header(self):
        fifa_account_id = self.kwargs.get('pk')
        return f'{FifaAccount.objects.get(id=fifa_account_id)} Errors'

    def get_queryset(self):
        fifa_account_id = self.kwargs.get('pk')
        query = super().get_queryset()
        if fifa_account_id:
            query = query.filter(fifa_account__id=fifa_account_id)
        return query


@login_required()
def solve_fifa_account_error(request, pk):
    error_item = FifaAccountWorkError.objects.get(id=pk)
    error_item.solve_status = 'solved'
    error_item.solve_user = request.user
    error_item.solve_time = timezone.localtime()
    error_item.save()
    messages.success(request, f'{pk} solved')
    return redirect(reverse_lazy('fifa-account-worker-error-detail', kwargs={'pk': error_item.fifa_account.id}))


class ConsoleUpdateView(RequiredPermissionViewMixin, GenericUpdateView):
    required_permission__ = 'console__update'
    model = Console
    form_class = ConsoleUpdateForm
    success_url = reverse_lazy('console-list')
    back_url = reverse_lazy('console-list')

    @property
    def page_header(self):
        return 'Update %s' % self.object.name

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


class WorkerGeneration(LoginRequiredMixin, RequiredPermissionViewMixin, FilterView):
    template_name = 'generic_views/filter_list_view.html'
    required_permission__all = 'manager_commands'
    page_header = _('Daily Credit Generated Part 1')
    model = FifaAccount
    filterset_class = DailyCreditGeneratedReportFilterSet

    dashboard_layout = DashboardLayout(
        DashboardRow(
            SBCSquadSalaryChartDashboardCard,
            SBCSquadTradeSalaryChartDashboardCard,
            # SBCSquadTradeSalary2ChartDashboardCard,
            # SBCSquadTradeSalary3ChartDashboardCard,
            # SBCSquadTradeSalary4ChartDashboardCard,
            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_card_data(self):
        cards_data = []
        return cards_data

    def get_context_data(self, **kwargs):
        kwargs = self.update_kwargs(self.kwargs)
        if 'dashboard_layout' not in kwargs:
            kwargs['dashboard_layout'] = self.dashboard_layout.construct(self.request, **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 update_kwargs(self, kwargs):
        week_times = self.get_weeks(datetime.datetime(2024, 2, 4), datetime.datetime.now())
        kwargs.update({'week_times': week_times})
        queryset = self.model.objects.filter(
            Q(delete_console_reason=None) | Q(delete_console_reason='')
        ).exclude(
            Q(console=None) | Q(console__investor=None)
        ).exclude(
            console__investor__id=18
        )
        queryset_list = list(queryset.values_list('id', flat=True))
        kwargs.update({'queryset_list': queryset_list})
        packs = list(ItemPack.objects.filter(
            fifa_account__id__in=queryset_list,
            create_time__gte=datetime.datetime(2024, 2, 4)
        ).annotate(
            create_week=Case(
                *[When(Q(create_time__gte=week_time.get('start')) & Q(create_time__lte=week_time.get('end')),
                       then=Value(week_time.get('start').timestamp())) for week_time in week_times],
                default=Value(None), output_field=IntegerField()),
        ).values('create_week').annotate(sum_packs=Sum('pack_value')).values_list('create_week', 'sum_packs'))
        kwargs.update({'packs': packs})
        return kwargs

    def get_weeks(self, start_date, end_date):
        weeks = []
        delta = datetime.timedelta(days=7)
        current_date = start_date
        while current_date <= end_date:
            week = {
                'start': current_date,
                'end': (current_date + datetime.timedelta(days=6)).replace(hour=23, minute=59)
            }
            weeks.append(week)
            current_date += delta
        return weeks


class WorkerGeneration2(WorkerGeneration):
    page_header = _('Daily Credit Generated Part 2')

    dashboard_layout = DashboardLayout(
        DashboardRow(
            # SBCSquadSalaryChartDashboardCard,
            # SBCSquadTradeSalaryChartDashboardCard,
            SBCSquadTradeSalary2ChartDashboardCard,
            SBCSquadTradeSalary3ChartDashboardCard,
            SBCSquadTradeSalary4ChartDashboardCard,
            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',
        ),
    )


class OutlookCreateWorkerView(GenericListView):
    template_name = 'sbc/sbs_workers_report_list.html'
    page_header = _('Outlook Creation Status')
    model = OutlookCreateWorker
    table_class = OutlookCreateWorkerTable

    def get_table_data(self):
        query = self.get_queryset().filter(is_done=False, has_error=False)
        query = query.annotate(
            str_console_name=Cast('outlook_account__console__name', output_field=CharField()),
            any_desk=Coalesce(Subquery(
                PC.objects.filter(
                    name=OuterRef('str_console_name')
                ).values('any_desk_code')[:1]
            ), Value('--')),
            pc_name=Coalesce(Subquery(
                PC.objects.filter(
                    name=OuterRef('str_console_name')
                ).values('name')[:1]
            ), Value('--')),
            log_worker_name=Concat(Value('create_outlook_'), 'outlook_account__id', output_field=CharField())
        )
        return query


class OutlookCreateHasError(LoginRequiredMixin, TemplateView):
    template_name = 'public/success.html'

    def get_context_data(self, **kwargs):
        return {'message': 'Has Error Success', 'back_url': reverse_lazy("create-outlook-workers")}

    def get(self, request, *args, **kwargs):
        outlook_account = NewOutlookAccount.objects.get(id=kwargs.get('pk'))
        outlook_account.signup_status = 'failed'
        outlook_account.signup_error = 'operator stopped'
        outlook_account.save()
        last_worker = outlook_account.outlookcreateworker_set.filter(is_done=False, has_error=False).last()
        if last_worker:
            last_worker.has_error = True
            last_worker.error_description = 'operator stopped'
            last_worker.save()
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)


class OutlookCreateReport(RequiredPermissionViewMixin, LoginRequiredMixin, TemplateView):
    required_permission__all = 'manager_commands'
    model = NewOutlookAccount

    def get(self, request, *args, **kwargs):
        response = HttpResponse(content_type='application/vnd.ms-excel')
        response['Content-Disposition'] = f'attachment; filename="outlook_created.xlsx"'
        wb = Workbook()
        ws = wb.active
        created_accounts = self.get_queryset().select_related('proxy', 'console')
        ws.append(
            ['create_time', 'user_name', 'password', 'birth_date', 'support_email',
             'console_name', 'start_signup_time', 'signup_status', 'gamer_tag', 'create_ip', 'browser',
             'origin_app_code', 'signup_error'
             ]
        )
        for item in created_accounts:

            ws.append([
                item.create_time.date() if item.create_time else None,
                item.user_name,
                item.password,
                # item.first_name,
                # item.last_name,
                item.birth_date,
                # item.proxy.ip_address if item.proxy else None,
                item.support_email,
                # item.support_password,
                # item.support_imap_host,
                item.console.name if item.console else None,
                item.start_signup_time.date() if item.start_signup_time else None,
                item.signup_status,
                item.gamer_tag,
                item.create_ip.strip() if item.create_ip else None,
                item.browser,
                item.origin_app_code,
                # item.need_proxy,
                item.start_signup_time.time() if item.start_signup_time else None,
                item.region,
                item.signup_error,
            ])
        wb.save(response)
        return response


class ConsolesPowerCommandListView(RequiredPermissionViewMixin, GenericFilterListView):
    required_permission__ = 'consoles_command__create'
    model = ConsolePowerCommand
    table_class = ConsolesCommandPowerTable
    page_header = 'Consoles Power'
    # filterset_class = ConsoleListFilter

    def get(self, request, *args, **kwargs):
        need_update = request.GET.get('update')
        if need_update:
            current_consoles_list = FifaAccount.objects.exclude(
                Q(console=None) | Q(pc=None)
            ).filter(
                Q(delete_console_reason=None) | Q(delete_console_reason='')
            ).distinct('console').values_list('console__id', flat=True)
            current_power_commands = ConsolePowerCommand.objects.all().values_list('console_id', flat=True)
            news = []
            for console_id in current_consoles_list:
                if console_id not in current_power_commands:
                    news.append(ConsolePowerCommand(console_id=console_id))
            ConsolePowerCommand.objects.bulk_create(news)
        return super().get(request, *args, **kwargs)

    def get_extra_buttons(self):
        buttons = []
        range_count = self.get_queryset().count()
        range_number_min = int(self.request.GET.get('range_number_min', 0))
        range_number_max = int(self.request.GET.get('range_number_max', 0))
        range_number = ''
        if range_number_max and range_number_max and range_number_min < range_number_max:
            range_number = f'&range_number_min={range_number_min}&range_number_max={range_number_max}'
        if has_permission_exactly(self.request.user, 'manager_commands'):
            buttons.append({
                'url': f'{reverse_lazy("console-power-command-action")}?command=turn_on_all' + range_number,
                'text': f'Turn On ({range_count})',
                'color': 'btn-danger'

            })
            buttons.append({
                'url': f'{reverse_lazy("console-power-command-action")}?command=shutdown_all' + range_number,
                'text': f'ShutDown ({range_count})',
                'color': 'btn-danger'

            })
            buttons.append({
                'url': f'{reverse_lazy("console-power-command-list")}?update=True',
                'text': f'Update',
                'color': 'btn-info'
            })
        return buttons

    def get_queryset(self) -> QuerySet:
        query_set = super().get_queryset()
        query_set1 = query_set.order_by('console__name')
        return query_set1

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


class ConsolesPowerCommandActionView(RequiredPermissionViewMixin, LoginRequiredMixin, TemplateView):
    template_name = 'public/success.html'
    required_permission__ = 'consoles_command__create'
    model = ConsolePowerCommand

    def get(self, request, *args, **kwargs):
        data = self.request.GET
        console_id = data.get('console_id')
        action = data.get('command')
        range_number_min = int(data.get('range_number_min', 0))
        range_number_max = int(data.get('range_number_max', 0))
        if console_id and action:
            console_object = Console.objects.get(id=console_id)
            if action == 'turn_on_one':
                ConsolePowerCommand.objects.filter(
                    console=console_object,
                ).update(
                    last_command='turn_on',
                    command_status=None,
                    update_time=timezone.localtime(),
                )
            elif action == 'shutdown_one':
                ConsolePowerCommand.objects.filter(
                    console=console_object,
                ).update(
                    last_command='shutdown',
                    command_status=None,
                    update_time=timezone.localtime(),
                )
            messages.success(request, f'action success : {console_object} {action} ')
        elif action:
            consoles_list = self.get_queryset()
            if range_number_min and range_number_max and range_number_min < range_number_max:
                consoles_list = consoles_list.filter(console__name__in=list(range(range_number_min, range_number_max)))
            if action == 'turn_on_all':
                ConsolePowerCommand.objects.filter(console__in=consoles_list).update(
                    last_command='turn_on',
                    command_status=None,
                    update_time=timezone.localtime(),
                )
            elif action == 'shutdown_all':
                ConsolePowerCommand.objects.filter(console__in=consoles_list).update(
                    last_command='shutdown',
                    command_status=None,
                    update_time=timezone.localtime(),
                )
        else:
            messages.error(request, message='somthing is wrong')
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

    def get_context_data(self, **kwargs):
        return {'message': 'Change Status Success', 'back_url': reverse_lazy("console-power-command-list")}

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


class PCPowerCommandListView(RequiredPermissionViewMixin, GenericFilterListView):
    required_permission__all = 'pcs__read'
    model = PCPowerCommand
    table_class = PCsCommandPowerTable
    page_header = 'PCs Power'
    filterset_class = PCListFilter

    def get(self, request, *args, **kwargs):
        need_update = request.GET.get('update')
        clear_all = request.GET.get('clear_all')
        if need_update:
            current_pcs_list = FifaAccount.objects.exclude(
                Q(console=None) | Q(pc=None)
            ).filter(
                Q(delete_console_reason=None) | Q(delete_console_reason='')
            ).distinct('pc').values_list('pc__id', flat=True)
            current_power_commands = PCPowerCommand.objects.all().values_list('pc__id', flat=True)
            for pc_id in current_pcs_list:
                if pc_id not in current_power_commands:
                    PCPowerCommand.objects.create(pc_id=pc_id)
        elif clear_all:
            current_power_commands = PCPowerCommand.objects.exclude(
                Q(last_command=None) | Q(command_status='done')).update(last_command=None)
            messages.success(request, f'action done for {current_power_commands}')
        return super().get(request, *args, **kwargs)

    def get_extra_buttons(self):
        buttons = []
        range_count = self.get_queryset().count()
        range_number_min = int(self.request.GET.get('range_number_min', 0))
        range_number_max = int(self.request.GET.get('range_number_max', 0))
        range_number = ''
        if range_number_max and range_number_max and range_number_min < range_number_max:
            range_number = f'&range_number_min={range_number_min}&range_number_max={range_number_max}'
        need_clears = PCPowerCommand.objects.exclude(Q(last_command=None) | Q(command_status='done')).count()
        if has_permission_exactly(self.request.user, 'manager_commands'):
            buttons.append({
                'url': f'{reverse_lazy("pc-power-command-action")}?command=sleep_all' + range_number,
                'text': f'Sleep ({range_count})',
                'color': 'btn-danger'

            })
            buttons.append({
                'url': f'{reverse_lazy("pc-power-command-action")}?command=shutdown_all' + range_number,
                'text': f'Shutdown ({range_count})',
                'color': 'btn-danger'

            })
            buttons.append({
                'url': f'{reverse_lazy("pc-power-command-list")}?update=True',
                'text': f'Update',
                'color': 'btn-info'
            })
            buttons.append({
                'url': f'{reverse_lazy("pc-power-command-list")}?clear_all=True',
                'text': f'Clear All ({need_clears})',
                'color': 'btn-warning'
            })
        return buttons

    def get_queryset(self) -> QuerySet:
        query_set = super().get_queryset()
        query_set1 = query_set.annotate(
            pc_name_int=Cast('pc__name', output_field=IntegerField())
        ).select_related('pc').order_by('pc_name_int')
        return query_set1

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


class PCsPowerCommandActionView(RequiredPermissionViewMixin, LoginRequiredMixin, TemplateView):
    template_name = 'public/success.html'
    required_permission__all = 'pcs__read'
    model = PC

    def get(self, request, *args, **kwargs):
        data = self.request.GET
        pc_id = data.get('pc_id')
        action = data.get('command')
        range_number_min = int(data.get('range_number_min', 0))
        range_number_max = int(data.get('range_number_max', 0))
        if pc_id and action:
            pc_object = PCPowerCommand.objects.get(id=pc_id)

            if action == 'sleep_one':
                pc_object.last_command = 'sleep'
                pc_object.update_time = timezone.localtime()
                pc_object.command_status = None
                pc_object.save()
            elif action == 'shutdown_one':
                pc_object.last_command = 'shutdown'
                pc_object.update_time = timezone.localtime()
                pc_object.command_status = None
                pc_object.save()
            messages.success(request, f'action success : {pc_object.pc.name} {action} ')
        elif action:
            pcs = self.get_queryset()
            if range_number_min and range_number_max and range_number_min < range_number_max:
                pcs = pcs.filter(name__in=list(range(range_number_min, range_number_max)))
            if action == 'sleep_all':
                PCPowerCommand.objects.filter(pc__in=pcs).update(
                    last_command='sleep',
                    update_time=timezone.localtime(),
                    command_status=None
                )
            elif action == 'shutdown_all':
                PCPowerCommand.objects.filter(pc__in=pcs).update(
                    last_command='shutdown',
                    update_time=timezone.localtime(),
                    command_status=None
                )
        else:
            messages.error(request, message='somthing is wrong')
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

    def get_context_data(self, **kwargs):
        return {'message': 'Change Status Success', 'back_url': reverse_lazy("pc-power-command-list")}

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)


class SendTelegramMessageView(View):
    def post(self, request, *args, **kwargs):
        request_data = request.POST
        bot_token = request_data.get('bot_token')
        group_id = request_data.get('group_id')
        message_text = request_data.get('message_text')
        message_thread_id = request_data.get('message_thread_id')
        url = f'https://api.telegram.org/bot{bot_token}/sendMessage'
        params = {
            'chat_id': group_id,
            'text': message_text,
        }
        if message_thread_id:
            params.update({'message_thread_id': message_thread_id})
        result = requests.get(url, params=params)
        return JsonResponse({'result': result.text}, status=200)

    def get(self, request, *args, **kwargs):
        return JsonResponse({'result': 'only post handled'}, status=200)


class ConsoleAccountsActionListView(GenericFormTableView):
    required_permission__ = 'consoles_command__create'
    model = Console
    table_class = ConsoleAccountsActionTable
    page_header = _('Console Accounts Action')
    form_class = ConsoleFileFilterForm
    success_url = reverse_lazy('console-accounts-actions')

    def get_extra_buttons(self):
        buttons = []
        range_count = self.get_queryset().filter(is_active=True).count()
        range_number_min = int(self.request.GET.get('range_number_min', 0) or 0)
        range_number_max = int(self.request.GET.get('range_number_max', 0) or 0)
        range_number = ''
        if range_number_max and range_number_max and range_number_min < range_number_max:
            range_number = f'&range_number_min={range_number_min}&range_number_max={range_number_max}'
        if has_permission_exactly(self.request.user, 'manager_commands'):
            buttons.append({
                'url': f'{reverse_lazy("console-accounts-actions")}?action=add_accounts_all&state=active' + range_number,
                'text': f'Active Add({range_count})',
                'color': 'btn-success'
            })
            buttons.append({
                'url': f'{reverse_lazy("console-accounts-actions")}?action=add_accounts_all&state=deactive' + range_number,
                'text': f'DeActive Add({range_count})',
                'color': 'btn-info'
            })
            buttons.append({
                'url': f'{reverse_lazy("console-accounts-actions")}?action=remove_accounts_all&state=active' + range_number,
                'text': f'Active Remove({range_count})',
                'color': 'btn-success'
            })
            buttons.append({
                'url': f'{reverse_lazy("console-accounts-actions")}?action=remove_accounts_all&state=deactive' + range_number,
                'text': f'DeActive Remove({range_count})',
                'color': 'btn-info'
            })
            buttons.append({
                'url': f'{reverse_lazy("console-accounts-actions")}?action=stop_after_all&state=active' + range_number,
                'text': f'Active Stop({range_count})',
                'color': 'btn-success'
            })
            buttons.append({
                'url': f'{reverse_lazy("console-accounts-actions")}?action=stop_after_all&state=deactive' + range_number,
                'text': f'DeActive Stop({range_count})',
                'color': 'btn-info'
            })
            buttons.append({
                'url': f'{reverse_lazy("console-accounts-actions")}?get_report=true' + range_number,
                'text': f'Report add-remove',
                'color': 'btn-warning'
            })
            buttons.append({
                'url': f'{reverse_lazy("console-accounts-actions")}?get_report_2=true' + range_number,
                'text': f'Report check',
                'color': 'btn-info'
            })
        return buttons

    def get(self, request, *args, **kwargs):
        data = self.request.GET
        if data.get('action'):
            console_id = data.get('console_id')
            action = data.get('action')
            state = data.get('state')
            range_number_min = int(data.get('range_number_min', 0))
            range_number_max = int(data.get('range_number_max', 0))
            if console_id and action and state:
                console_object = Console.objects.get(id=console_id)
                if action == 'add_accounts_one' and state == 'active':
                    console_object.add_accounts = True
                    console_object.save(update_fields=['add_accounts'])
                elif action == 'add_accounts_one' and state == 'deactive':
                    console_object.add_accounts = False
                    console_object.save(update_fields=['add_accounts'])
                elif action == 'remove_accounts_one' and state == 'active':
                    console_object.remove_accounts = True
                    console_object.save(update_fields=['remove_accounts'])
                elif action == 'remove_accounts_one' and state == 'deactive':
                    console_object.remove_accounts = False
                    console_object.save(update_fields=['remove_accounts'])
                elif action == 'stop_after_one' and state == 'active':
                    console_object.stop_after_add_remove_accounts = True
                    console_object.save(update_fields=['stop_after_add_remove_accounts'])
                elif action == 'stop_after_one' and state == 'deactive':
                    console_object.stop_after_add_remove_accounts = False
                    console_object.save(update_fields=['stop_after_add_remove_accounts'])
                elif action == 'check_accounts_one' and state == 'active':
                    console_object.check_accounts = True
                    console_object.save(update_fields=['check_accounts'])
                elif action == 'check_accounts_one' and state == 'deactive':
                    console_object.check_accounts = False
                    console_object.save(update_fields=['check_accounts'])
                messages.success(request, f'action success : {console_object} {state} {action} ')
            elif action and state:
                user_consoles = self.get_queryset()
                if range_number_min and range_number_max and range_number_min < range_number_max:
                    user_consoles = user_consoles.filter(name__in=list(range(range_number_min, range_number_max)))
                if action == 'add_accounts_all' and state == 'active':
                    user_consoles.filter(
                        is_active=True
                    ).update(add_accounts=True)
                elif action == 'add_accounts_all' and state == 'deactive':
                    user_consoles.filter(
                        is_active=True
                    ).update(add_accounts=False)
                elif action == 'remove_accounts_all' and state == 'active':
                    user_consoles.filter(
                        is_active=True
                    ).update(remove_accounts=True)
                elif action == 'remove_accounts_all' and state == 'deactive':
                    user_consoles.filter(
                        is_active=True
                    ).update(remove_accounts=False)
                elif action == 'stop_after_all' and state == 'active':
                    user_consoles.filter(
                        is_active=True
                    ).update(stop_after_add_remove_accounts=True)
                elif action == 'stop_after_all' and state == 'deactive':
                    user_consoles.filter(
                        is_active=True
                    ).update(stop_after_add_remove_accounts=False)
            else:
                messages.error(request, message='somthing is wrong')
            return redirect('console-accounts-actions')
        elif data.get('get_report'):
            response = HttpResponse(content_type='application/vnd.ms-excel')
            response['Content-Disposition'] = f'attachment; filename="add_accounts_report.xlsx"'
            wb = Workbook()
            ws = wb.active
            query_set_1 = self.get_queryset()
            range_number_min = int(data.get('range_number_min', 0))
            range_number_max = int(data.get('range_number_max', 0))
            ws.append(
                ['id', 'console', 'user name', 'status', 'start time', 'create time', 'error']
            )
            data_consoles = query_set_1
            if range_number_min and range_number_max and range_number_min < range_number_max:
                data_consoles = query_set_1.filter(name__in=list(range(range_number_min, range_number_max)))
            data_add_accounts = NewConsoleAccount.objects.filter(
                Q(add_start_time=None) | Q(add_start_time__gt=timezone.localtime() - timezone.timedelta(days=15)),
                console__in=data_consoles,
            ).select_related('console')
            for item_1 in data_add_accounts:
                ws.append([
                    str(item_1.id),
                    str(item_1.console.name),
                    str(item_1.user_name),
                    str(item_1.add_status),
                    str(item_1.add_start_time),
                    str(item_1.create_time),
                    str(item_1.add_error),
                ])
            wb.save(response)
            return response
        elif data.get('get_report_2'):
            response = HttpResponse(content_type='application/vnd.ms-excel')
            response['Content-Disposition'] = f'attachment; filename="check_accounts_report.xlsx"'
            wb = Workbook()
            ws = wb.active
            query_set_1 = self.get_queryset()
            range_number_min = int(data.get('range_number_min', 0))
            range_number_max = int(data.get('range_number_max', 0))
            ws.append(
                ['create_time', 'console', 'status code', 'description']
            )
            data_consoles = query_set_1
            if range_number_min and range_number_max and range_number_min < range_number_max:
                data_consoles = query_set_1.filter(name__in=list(range(range_number_min, range_number_max)))
            data_add_accounts = ConsoleReadingAccounts.objects.filter(
                console__in=data_consoles,
            ).select_related('console')
            for item_1 in data_add_accounts:
                ws.append([
                    str(item_1.create_time),
                    str(item_1.console.name),
                    str(item_1.status_code),
                    str(item_1.description),
                ])
            wb.save(response)
            return response
        else:
            return super().get(request, *args, **kwargs)

    def form_valid(self, form):
        upload_file = form.cleaned_data.get('upload_file')
        if upload_file:
            wb_obj = openpyxl.load_workbook(upload_file)
            sheet_obj = wb_obj.active
            max_row = sheet_obj.max_row
            for nn in range(2, max_row + 1):
                console_name = sheet_obj.cell(row=nn, column=1).value
                active_add = sheet_obj.cell(row=nn, column=2).value
                active_remove = sheet_obj.cell(row=nn, column=3).value
                active_stop = sheet_obj.cell(row=nn, column=4).value
                console_obj = Console.objects.filter(name=console_name).last()
                if not console_obj:
                    messages.add_message(self.request, messages.ERROR, f'Console name not exists {console_name}')

                if active_add == 'a':
                    console_obj.add_accounts = True
                elif active_add == 'd':
                    console_obj.add_accounts = False

                if active_remove == 'a':
                    console_obj.remove_accounts = True
                elif active_remove == 'd':
                    console_obj.remove_accounts = False

                if active_stop == 'a':
                    console_obj.stop_after_add_remove_accounts = True
                elif active_stop == 'd':
                    console_obj.stop_after_add_remove_accounts = False

                console_obj.save(update_fields=['add_accounts', 'remove_accounts', 'stop_after_add_remove_accounts'])



        query_params = {k: v for k, v in form.cleaned_data.items() if v not in [None, '', [], {}]}
        return HttpResponseRedirect(f"{self.success_url}?{urlencode(query_params)}")

    def get_queryset(self) -> QuerySet:
        # query_set = super().get_queryset()
        query_set = Console.objects.all()
        form = ConsoleFileFilterForm(self.request.GET, self.request.FILES)

        if form.is_valid():
            number_min = form.cleaned_data.get('range_number_min')
            number_max = form.cleaned_data.get('range_number_max')

            if number_min:
                query_set = query_set.filter(name__gte=number_min)
            if number_max:
                query_set = query_set.filter(name__lte=number_max)


        query_set1 = query_set.distinct().order_by('name').annotate(
            add_accounts_state=Case(
                When(Q(add_accounts=True),
                     then=Value('deactive')),
                When(Q(add_accounts=False),
                     then=Value('active')),
                # default=Value('active'),
                output_field=CharField()
            ),
            add_accounts_text=Case(
                When(Q(add_accounts=True),
                     then=Value('Deactive Add')),
                When(Q(add_accounts=False),
                     then=Value('Active Add')),
                # default=Value('Active Trade'),
                output_field=CharField()
            ),

            remove_accounts_state=Case(
                When(Q(remove_accounts=True),
                     then=Value('deactive')),
                When(Q(remove_accounts=False),
                     then=Value('active')),
                # default=Value('active'),
                output_field=CharField()
            ),
            remove_accounts_text=Case(
                When(Q(remove_accounts=True),
                     then=Value('Deactive Remove')),
                When(Q(remove_accounts=False),
                     then=Value('Active Remove')),
                # default=Value('Active Discharge'),
                output_field=CharField()
            ),

            stop_after_state=Case(
                When(Q(stop_after_add_remove_accounts=True),
                     then=Value('deactive')),
                When(Q(stop_after_add_remove_accounts=False),
                     then=Value('active')),
                # default=Value('active'),
                output_field=CharField()
            ),
            stop_after_text=Case(
                When(Q(stop_after_add_remove_accounts=True),
                     then=Value('Deactive Stop')),
                When(Q(stop_after_add_remove_accounts=False),
                     then=Value('Active Stop')),
                # default=Value('Active Squad'),
                output_field=CharField()
            ),
            check_accounts_state=Case(
                When(Q(check_accounts=True),
                     then=Value('deactive')),
                When(Q(check_accounts=False),
                     then=Value('active')),
                # default=Value('active'),
                output_field=CharField()
            ),
            check_accounts_text=Case(
                When(Q(check_accounts=True),
                     then=Value('Deactive Check')),
                When(Q(check_accounts=False),
                     then=Value('Active Check')),
                # default=Value('Active Discharge'),
                output_field=CharField()
            ),
        ).exclude(
            Q(add_accounts_state=None) | Q(remove_accounts_state=None) | Q(stop_after_state=None) | Q(check_accounts_state=None)
        )
        return query_set1

    def is_rel(self):
        return has_permission_exactly(self.request.user, self.required_permission__rel)

    def get_table_data(self):
        return self.get_queryset()


class GetPlayerMainImage(View):
    def get(self, request, *args, **kwargs):
        player_futbin_id = request.GET.get('player_futbin_id')
        suggested_player_file_name = request.GET.get('player_file_name')
        if not player_futbin_id:
            return JsonResponse({'status': 'error', 'msg': 'need futbin id'}, status=400, safe=False)
        futbin_id = player_futbin_id
        if suggested_player_file_name:
            player_file_name = f'{suggested_player_file_name}.png'
        else:
            player_file_name = f'player_{futbin_id}.png'
        scraper = cloudscraper.create_scraper(browser={
            'browser': 'firefox',
            'platform': 'linux',
            'mobile': False
        })

        player_page = scraper.get(f'https://www.futbin.com/25/player/{futbin_id}/a')
        file_name = 'player_page.html'
        with open(os.path.join(MEDIA_ROOT, f"temp/{file_name}"), 'w', encoding='utf-8') as player_file:
            player_page_text = player_page.text
            player_page_text = player_page_text.replace('href="/', 'href="https://www.futbin.com/')
            player_page_text = player_page_text.replace('src="/', 'src="https://www.futbin.com/')
            player_page_text = re.sub(
                r'saveAs\(blob, &quot;(.+)\.png&quot;\)\)',
                f'saveAs(blob, &quot;{player_file_name}&quot;))', player_page_text)
            player_file.write(player_page_text)
        from selenium import webdriver
        from selenium.webdriver.common.by import By


        screenshot_path = os.path.join(MEDIA_ROOT, "temp") # create this directory .data/media/temp
        options = webdriver.ChromeOptions()
        prefs = {
            "download.default_directory": screenshot_path,
            "download.prompt_for_download": False,
            "directory_upgrade": True,
        }
        options.add_experimental_option("prefs", prefs)
        options.add_argument("--headless")
        options.add_argument("--no-sandbox")
        options.add_argument('--window-size=1200x600')
        options.add_argument(f"user-agent={user_agent}")
        # options.add_argument("--disable-gpu")
        # options.add_argument("--disable-dev-shm-usage")
        # options.add_argument("--remote-debugging-port=9222")

        driver = webdriver.Chrome(options=options)
        file_path = f"file://{os.path.join(MEDIA_ROOT, f'temp/{file_name}')}"
        driver.get(file_path)
        time.sleep(1)
        # element = driver.find_element(By.XPATH, '//*[contains(@class,"playercard-option-wrapper")]/a/div')
        # element = driver.find_element(By.XPATH, '//*[contains(@class,"playercard-option")]/template')
        try:
            element = driver.find_element(By.XPATH, '//*[contains(@class,"player-card-wrapper")]')
        except:
            return JsonResponse({'status': 'error', 'msg': 'page not found'}, status=400, safe=False)

        # get screenshot from element
        # element.screenshot(f'{screenshot_path}/{player_file_name}')
        # time.sleep(1)

        # # todo : bellow to slow , fix it
        # download element by click on download icon
        driver.find_element(by=By.XPATH, value='//*[contains(@class,"playercard-option-button")]').click()
        time.sleep(1)
        driver.find_element(by=By.XPATH, value='//*[contains(text(), "Download card image")]').click()
        time.sleep(5)

        for iien in range(20):
            # downloaded_file = max([f"{screenshot_path}/{file}" for file in files], key=os.path.getctime)
            # os.rename(downloaded_file, f'{screenshot_path}/player_{futbin_id}.png')
            files_names = [f"{BASE_DIR}/{file}" for file in os.listdir(BASE_DIR) if file == player_file_name]
            if files_names:
                os.rename(files_names[0], f'{screenshot_path}/{player_file_name}')
            files_names = [f"{screenshot_path}/{file}" for file in os.listdir(screenshot_path) if file == player_file_name]
            if files_names:
                break
            time.sleep(1)
        if not files_names:
            return JsonResponse({'status': 'error', 'msg': 'no file found'}, status=400, safe=False)
        downloaded_file = max(files_names, key=os.path.getctime)
        os.rename(downloaded_file, f'{screenshot_path}/{player_file_name}')
        driver.quit()
        return JsonResponse({'status': 'success',
                             'link': f'http://142.132.177.244:8000/media/temp/{player_file_name}'},
                            status=200,
                            safe=False)


def gc_discharge_player_max_price(request):
    credit_list = list(FifaAccount.objects.exclude(console=None).filter(
        Q(delete_console_reason=None) | Q(delete_console_reason=''),
        # last_run_time__lte=timezone.localtime() - timezone.timedelta(hours=5),
        credit__gt=ConsoleBotSetting.objects.get(
            name='discharge_with_mode2_lowest_target_buy_now_price'
        ).int_value
    ).values_list('credit', flat=True))
    discharge_with_mode3_lowest_target_price = ConsoleBotSetting.objects.get(
        name='discharge_with_mode3_lowest_target_price').int_value
    credit_list = sorted(credit_list, reverse=True)
    n = len(credit_list)
    idx_10_top = n * 5 // 100  # Index for removing the first 5%
    idx_40_next = n - (n * 55 // 100)  # Index for removing the last 40%
    idx_30_next = n - (n * 65 // 100)  # Index for removing the last 30%
    idx_20_next = n - (n * 75 // 100)  # Index for removing the last 20%

    idx_2_top = n * 2 // 100  # Index for removing the first 2%
    idx_10_next = n - (n * 88 // 100)  # Index for removing the last 10%
    idx_5_next = n - (n * 93 // 100)  # Index for removing the last 5%
    idx_7_next = n - (n * 91 // 100)  # Index for removing the last 7%

    # Remove the first 10% and the last 40%
    filtered_10_40 = credit_list[idx_10_top:idx_40_next]

    # Remove the first 10% and the last 30%
    filtered_10_30 = credit_list[idx_10_top:idx_30_next]

    # Remove the first 10% and the last 20%
    filtered_10_20 = credit_list[idx_10_top:idx_20_next]

    filtered_10_10 = credit_list[idx_10_top:idx_10_next]
    filtered_2_10 = credit_list[idx_2_top:idx_10_next]
    filtered_2_5 = credit_list[idx_2_top:idx_5_next]
    filtered_2_7 = credit_list[idx_2_top:idx_7_next]

    # Compute the averages
    avg_10_40 = int(sum(filtered_10_40) / len(filtered_10_40) if filtered_10_40 else 0)
    avg_10_30 = int(sum(filtered_10_30) / len(filtered_10_30) if filtered_10_30 else 0)
    avg_10_20 = int(sum(filtered_10_20) / len(filtered_10_20) if filtered_10_20 else 0)
    avg_10_10 = int(sum(filtered_10_10) / len(filtered_10_10) if filtered_10_10 else 0)
    avg_2_10 = int(sum(filtered_2_10) / len(filtered_2_10) if filtered_2_10 else 0)
    avg_2_5 = int(sum(filtered_2_5) / len(filtered_2_5) if filtered_2_5 else 0)
    avg_2_7 = int(sum(filtered_2_7) / len(filtered_2_7) if filtered_2_7 else 0)
    avg_credit = avg_10_10
    if avg_credit >= discharge_with_mode3_lowest_target_price:
        avg_credit = discharge_with_mode3_lowest_target_price
    return JsonResponse({
        'avg_credit': avg_credit,
        'max_player_price': int(avg_credit * .7),
        'avg_5_40': avg_10_40,
        'avg_5_30': avg_10_30,
        'avg_5_20': avg_10_20,
        'avg_10_10': avg_10_10,
        'avg_2_10': avg_2_10,
        'avg_2_5': avg_2_5,
        'avg_2_7': avg_2_7,
        'account_count': len(credit_list)
    }, safe=False, status=200)


def pcs_sleeps(request):
    aa = ConsoleLastStatus.objects.filter(console__is_active=True).annotate(
        loc_code=Coalesce(Subquery(FifaAccount.objects.filter(
            console__id=OuterRef('console__pk'),
        ).order_by().values('pc__location_code')[:1], output_field=IntegerField()), Value(None)),
    ).order_by(
        'console__name'
    ).values_list('console__name', 'status', 'loc_code', 'status_change_time')
    return JsonResponse(list(aa), safe=False, status=200)


class FifaAccountsChangeHosts(RequiredPermissionViewMixin, GenericFormView):
    required_permission__all = 'fifa_account__create'
    form_class = SimpleFileUploadForm
    success_url = reverse_lazy('fifa-accounts-change-hosts')

    def page_header(self):
        return 'Change Hosts'

    def form_valid(self, form):
        upload_file = form.files.get('upload_file')
        wb_obj = openpyxl.load_workbook(upload_file)
        sheet_obj = wb_obj.active
        max_row = sheet_obj.max_row
        data_list = []

        for i in range(2, max_row + 1):
            field_1 = sheet_obj.cell(row=i, column=1).value
            field_2 = sheet_obj.cell(row=i, column=2).value
            field_3 = sheet_obj.cell(row=i, column=3).value
            field_4 = sheet_obj.cell(row=i, column=4).value
            field_5 = sheet_obj.cell(row=i, column=5).value
            data_list.append([str(field_1), str(field_2), str(field_3), str(field_4), str(field_5)])

        output_data = self.process_data(data_list)

        response = HttpResponse(content_type='application/vnd.ms-excel')
        response['Content-Disposition'] = f'attachment; filename="output_change_hosts.xlsx"'
        output_wb = Workbook()
        output_ws = output_wb.active
        output_ws.append(
            ['console', 'guests', 'hosts', 'guests count', 'hosts count', 'moved']

        )
        for key_1, item_1 in output_data.get('base_dict').items():
            output_ws.append([
                str(key_1),
                ','.join(item_1.get('guests')),
                ','.join(item_1.get('hosts')),
                item_1.get('gusts_count'),
                item_1.get('hosts_count'),
                ','.join(item_1.get('moves')),
            ])
        output_ws_2 = output_wb.create_sheet('moved_list')
        output_ws_2.append([
            'email', 'console', 'gamer tag'
        ])
        for ii in output_data.get('moved_list'):
            output_ws_2.append([
                ii[0],
                str(ii[1]),
                ii[2]
            ])
        output_wb.save(response)
        return response

    def process_data(self, list_data):
        base_dict = {}
        moved_list = []
        for ii in list_data:
            if not ii:
                continue
            console_name = ii[0]
            if base_dict.get(console_name, None) is None:
                base_dict.update(
                    {console_name: {'guests': [], 'hosts': [], 'gusts_count': 0, 'hosts_count': 0, 'moves': []}})
            if ii[1] == '1':
                console_data = base_dict.get(console_name)
                console_data['guests'].append(ii[2] + '_' + ii[3])
                console_data['gusts_count'] += 1
            else:
                console_data = base_dict.get(console_name)
                console_data['hosts'].append(ii[2] + '_' + ii[3])
                console_data['hosts_count'] += 1

        for ii_2 in list_data:
            if not ii_2:
                continue
            console_name_2 = ii_2[0]
            if ii_2[1] == '1':
                continue
            console_data_2 = base_dict.get(console_name_2)
            for key_3, value_3 in base_dict.items():
                if key_3 == console_name_2:
                    continue

                if value_3['gusts_count'] >= 12:
                    continue
                if ii_2[2] + '_' + ii_2[3] in value_3['guests'] + value_3['hosts']:
                    continue
                current_platform_count = [nn.split('_')[1] for nn in value_3['guests']]
                current_platform_count = [nn2 for nn2 in current_platform_count if nn2 == ii_2[3]]
                if len(current_platform_count) >= 6:
                    continue
                console_data_3 = base_dict.get(key_3)
                console_data_3['guests'].append(ii_2[2] + '_' + ii_2[3])
                console_data_3['gusts_count'] += 1
                console_data_3['moves'].append(ii_2[4])
                console_data_2['hosts_count'] -= 1
                moved_list.append([ii_2[4], key_3, ii_2[2] + '_' + ii_2[3]])
                break
        return {'base_dict': base_dict, 'moved_list': moved_list}


class RedisMonitoring(GenericListView):
    table_class = SummaryTable
    model = Console
    page_header = 'Redis Monitor'

    def get_table_data(self):
        rows = []
        r = get_redis_connection("print_log")
        info = r.info()
        config = r.config_get()
        redis_dir = config.get("dir", "/var/lib/redis")
        rdb_file = config.get("dbfilename", "dump.rdb")
        aof_file = config.get("appendfilename", "appendonly.aof")

        rdb_path = os.path.join(redis_dir, rdb_file)
        aof_path = os.path.join(redis_dir, aof_file)

        rdb_size = os.path.getsize(rdb_path) if os.path.exists(rdb_path) else 0
        aof_size = os.path.getsize(aof_path) if os.path.exists(aof_path) else 0
        data_keys = {
            "total_keys": r.dbsize(),
            "used_memory": info.get("used_memory_human", "N/A"),
            "uptime_days": info.get("uptime_in_days", "N/A"),
            "connected_clients": info.get("connected_clients", "N/A"),
            "ops_per_sec": info.get("instantaneous_ops_per_sec", "N/A"),
            "keyspace_hits": info.get("keyspace_hits", "N/A"),
            "keyspace_misses": info.get("keyspace_misses", "N/A"),
            "expired_keys": info.get("expired_keys", "N/A"),
            "evicted_keys": info.get("evicted_keys", "N/A"),
            "rdb_size": round(rdb_size / 1024 / 1024, 2),  # MB
            "aof_size": round(aof_size / 1024 / 1024, 2),  # MB
        }
        for ii, val_ii in data_keys.items():

            rows.append({'title': ii, 'sum': str(val_ii)})


        rows.append({'title': 'Keys example', 'sum': '....'})
        keys = r.scan_iter(count=20)
        for ii in list(keys):
            rows.append({"title": ii.decode(), "sum": ''})
        return rows


class ConsoleAccountManagementView(GenericFormView):
    form_class = ConsoleAccountManagementForm
    success_url = reverse_lazy('console-account-management')
    page_header = "Console Accounts Management"

    def form_valid(self, form):
        upload_file = form.cleaned_data.get('upload_file')
        action = form.cleaned_data.get('action')

        wb = openpyxl.load_workbook(upload_file)
        sheet = wb.active
        max_row = sheet.max_row

        processed_data = []
        for row in range(2, max_row + 1):
            account_data = {
                'console_name': sheet.cell(row=row, column=1).value,
                'gamer_tag': sheet.cell(row=row, column=2).value,
                'user_name': sheet.cell(row=row, column=3).value,
                'password': sheet.cell(row=row, column=4).value,
                'support_email': sheet.cell(row=row, column=5).value,
                'support_password': sheet.cell(row=row, column=6).value,
                'support_imap_host': sheet.cell(row=row, column=7).value,
            }
            processed_data.append(account_data)

        if action == '1':  # Add Data
            self.add_data(processed_data)
        elif action == '2':  # Remove Data
            self.remove_data(processed_data)

        messages.success(self.request, "Operation completed successfully.")
        return redirect(self.success_url)

    def add_data(self, data):
        new_accounts = []
        consoles = {c.name: c for c in Console.objects.filter(name__in=[item['console_name'] for item in data])}
        error_messages = []

        for item in data:
            console_name = item.get('console_name')
            user_name = item.get('user_name')

            console = consoles.get(console_name)
            if not console:
                error_messages.append(f"Console '{console_name}' not found! Skipping account: {user_name}.")
                continue

            if NewConsoleAccount.objects.filter(user_name=user_name, console=console).exists():
                error_messages.append(f"Account already exists: {user_name}")
                continue

            new_accounts.append(
                NewConsoleAccount(
                    user_name=user_name,
                    password=item.get('password'),
                    support_email=item.get('support_email'),
                    support_password=item.get('support_password'),
                    support_imap_host=item.get('support_imap_host'),
                    gamer_tag=item.get('gamer_tag'),
                    console=console,
                )
            )

        if new_accounts:
            NewConsoleAccount.objects.bulk_create(new_accounts)
            messages.success(self.request, f"{len(new_accounts)} accounts added successfully.")

        if error_messages:
            messages.error(self.request, " | ".join(error_messages))

    def remove_data(self, data):
        delete_queries = []

        for item in data:
            user_name = item.get('user_name')
            console_name = item.get('console_name')

            query = NewConsoleAccount.objects.filter(user_name=user_name)
            if console_name:
                query = query.filter(console__name=console_name)

            delete_queries.append(query)

        if delete_queries:
            combined_query = Q()
            for query in delete_queries:
                combined_query |= Q(id__in=query.values_list('id', flat=True))

            deleted_count, _ = NewConsoleAccount.objects.filter(combined_query).delete()
            messages.success(self.request, f"{deleted_count} accounts removed successfully.")


def relay_status(request):
    board_name = request.GET.get('arduino', '')
    if not board_name:
        return JsonResponse([], safe=False, status=400)
    ports_name = request.GET.get('names', '')
    if not ports_name:
        return JsonResponse([], safe=False, status=400)
    names_list = ports_name.split(',')
    arduino_ports = ArduinoPort.objects.filter(
        board_name=board_name,
        port_name__in=names_list
    ).order_by('id')
    result = [{'n': item.port_name, 's': item.get_current_state_display()} for item in arduino_ports]
    return JsonResponse(result, safe=False)


def relay_names(request):
    board_name = request.GET.get('arduino', '')
    arduino_pins = request.GET.get('pins', '')
    if not board_name:
        return JsonResponse({'names': [], 'status': 'bad data. arduino required'}, status=400)
    arduino_ports = ArduinoPort.objects.filter(board_name=board_name).order_by('id')
    if not arduino_ports:
        new_ports = []
        pins_name = arduino_pins.split(',')
        for ii in range(1, len(pins_name) + 1):
            new_ports.append(ArduinoPort(board_name=board_name, port_name=f'R{ii}', pin_name=pins_name[ii-1]))
        ArduinoPort.objects.bulk_create(new_ports)
        arduino_ports = ArduinoPort.objects.filter(board_name=board_name).order_by('id')
    data = [f'{relay.port_name}' for relay in arduino_ports.iterator()]

    return JsonResponse({"names": data})
