import json
import os
import random
import subprocess
import threading
import time
import traceback

import django
import keyboard
import mouse
import pytesseract
from django.core.exceptions import ImproperlyConfigured
from django.db import close_old_connections
from django.db.models import Q, Value, F, Sum, Subquery, OuterRef, IntegerField, Count, ExpressionWrapper, BooleanField, \
    When, Case
from django.db.models.functions import Coalesce
from django.utils import timezone

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'futplus.settings')
django.setup()

from sbc import FIFA_REPORT_TOKEN, ARZBAZI_REPORT_TOPIC_PC_DIFFERENT_TIME_THREAD_MESSAGE_ID, ARZBAZI_REPORT_GROUP_ID, \
    ARZBAZI_REPORT_TOPIC_TESSERACT_ERROR_THREAD_MESSAGE_ID
from utils.realy_public_methods import get_db_time, telegram_send_message_fifa_account
from squad_battle import calculate_need_game2, ACCOUNT_ALLOWED_PLAYED_ALL, \
    ACCOUNT_TOO_MANY_UNLISTED_ITEMS2
from accounts.console_bot_settings import allowed_discharge_time
from accounts.public import console_need_force_sleep
from utils.public_moves import PublicMoves
from sbc.models import SBCWorker, SBCType, SBCProcess
from trade.models import ConsoleTradeOneHistory, ConsoleTradeOneQuality
from sbc.public_methods import new_print, set_main_log, set_sub_log, focus_on_ps, has_image, get_screen_shot, \
    get_image_position, process_exists, set_sbc_status, set_console_status, ThreadWithReturnValue, console_worker_cache, \
    check_bot_version, set_console_list_status
from accounts.models import Console, FifaAccount, ConsoleBotSetting, AccountSalablePlayerCard, FifaAccountCurrentItems, \
    PCPowerCommand, ConsolePowerCommand, ConsoleLastStatus
from squad_battle.models import FifaAccountSquadGame
from futplus.settings import CONSOLE_NAME, BASE_DIR, TIME_ZONE, CONSOLE_NAME_LIST
from squad_battle.squad_battle_bot import SquadBattleRunner
from trade.console_trade_bot import ConsoleTradeRunner
from sbc.pc_bots import start_pc_bots, start_get_backup_code, start_add_and_remove_accounts
from accounts.create_outlook_email import CreateOutlookMail
import pygetwindow as gw

# delete bellow uninstall_package
# def uninstall_package(package_name):
#     import importlib.util
#     import sys
#     if importlib.util.find_spec(package_name) is not None:
#         print(f"uninstalling {package_name} ... ")
#         subprocess.check_call([sys.executable, "-m", "pip", "uninstall", package_name, "-y"])
#         print(f"uninstall {package_name} done.")
#     else:
#         pass
# for bad_package in ['seleniumbase', 'chardet']:
#     uninstall_package(bad_package)

# todo : remove me
try:
    tesseract_version = pytesseract.get_tesseract_version()
    version_float = float(str(pytesseract.get_tesseract_version())[:3])
    if version_float < 5.5:
        telegram_send_message_fifa_account(
            fifa_account=FifaAccount.objects.filter(console__name=CONSOLE_NAME).first(),
            bot_token=FIFA_REPORT_TOKEN,
            text=f'tesseract version is low {tesseract_version} console : {CONSOLE_NAME}',
            chat_id=ARZBAZI_REPORT_GROUP_ID,
            message_thread_id=ARZBAZI_REPORT_TOPIC_TESSERACT_ERROR_THREAD_MESSAGE_ID,
        )
        time.sleep(120)
except:
    time.sleep(120)
    print('error on read pytesseract : ', traceback.format_exc())

def key_can_use(fifa_account: FifaAccount, sbc_worker: SBCWorker):
    using_current_fifa_key = FifaAccount.objects.exclude(
        Q(id=fifa_account.id) | Q(console=fifa_account.console)
    ).filter(
        active=True,
        console__key_fifa_account=fifa_account.console.key_fifa_account,
        console__is_active=True,
        console__fifa_key_is_home=False,
    )

    if using_current_fifa_key.count() >= 1 and fifa_account.console.fifa_key_is_home is False:
        # todo : fix active = False , add some conditions . not all time
        undone_worker_count = SBCWorker.objects.filter(
            fifa_account=fifa_account,
            is_done=False, has_error=False, must_done=False,
        ).exclude(running_platform='console').count()
        if undone_worker_count < 1:
            new_print(fifa_account, 'no other active worker . make account deactive.')
            fifa_account.active = False
            fifa_account.save(update_fields=['active'])

        text = f'accounts {using_current_fifa_key} using current key , wait until he`s work done'
        print(text)
        new_print(fifa_account, text)
        threading.Thread(target=focus_on_ps, kwargs={'fifa_account': fifa_account}).start()
        time.sleep(5)
        public_moves = PublicMoves(None, fifa_account.sbcworker_set.last(), None, {}, None)
        print('pressing left and right for keep console alive')
        public_moves.ps4_buttons.left()
        time.sleep(1)
        public_moves.ps4_buttons.right()
        time.sleep(10)
        set_sbc_status(sbc_worker, f'key in use : {list(using_current_fifa_key.values_list("user_name", flat=True))}')
        time.sleep(random.randint(150, 200))
        return False
    return True


# def is_within_work_hours(local_time, work_time_list):
#     current_time = local_time.time()
#     result_list = []
#     for work_time in work_time_list:
#         if work_time.get('start_time') < work_time.get('end_time'):
#             result_list.append(current_time <= work_time.get('start_time') or current_time >= work_time.get('end_time'))
#         else:
#             result_list.append(work_time.get('start_time') >= current_time >= work_time.get('end_time'))
#     if False in result_list:
#         return True
#     return False
#
#
# def need_force_sleep():
#     console = Console.objects.filter(name=CONSOLE_NAME).last()
#     if not console:
#         return False
#     console_work_list = ConsoleWorkTime.objects.filter(
#         console__name=CONSOLE_NAME
#     ).values('start_time', 'end_time')
#     sane_console_fifa_accounts = FifaAccount.objects.filter(
#         console=console,
#     ).filter(
#         Q(delete_console_reason=None) | Q(delete_console_reason=''),
#     ).exclude(name_in_console='key').order_by('last_run_time')
#     try:
#         local_time = get_db_time(timezone_=TIME_ZONE)
#     except:
#         print('cant get local_time from server , ', traceback.format_exc())
#         local_time = timezone.localtime()
#     if (console.turn_off_after_work and console_work_list and
#             (not is_within_work_hours(local_time, console_work_list))):
#         first_account = sane_console_fifa_accounts.first()
#         sleep_text = f'work time out of range 2 , current time : {local_time} , start time : {console.work_start_time} , end time : {console.work_end_time} , logs in {first_account}'
#         print(sleep_text)
#         if first_account:
#             new_print(first_account, sleep_text)
#         set_console_status(console=console, status='PC is asleep')
#         time.sleep(1)
#         sleep_command = '''Start-Sleep -Seconds 5
#                                         Add-Type -AssemblyName System.Windows.Forms
#                                         [System.Windows.Forms.Application]::SetSuspendState("Suspend", $false, $false)'''
#         subprocess.Popen(['powershell.exe', sleep_command])
#         return True


def run_worker(worker_id):
    print('run worker started with worker :', worker_id)
    uncompleted_worker = SBCWorker.objects.filter(id=worker_id).first()
    fifa_account = uncompleted_worker.fifa_account
    fifa_account.refresh_from_db()
    need_works = check_need_work_fifa_account(
        fifa_account,
        console_last_24_hour_played=get_console_last_24_hour_played(fifa_account.console),
        console=fifa_account.console,
        allowed_discharge_time_var=allowed_discharge_time()
    )
    if fifa_account.console.key_fifa_account and not key_can_use(fifa_account=fifa_account, sbc_worker=uncompleted_worker):
        return
    set_main_log(uncompleted_worker, 'preparing for work...')
    set_sub_log(uncompleted_worker, 'preparing for work with existed sbc worker...')
    account_works = need_works.first()
    uncompleted_worker.last_run_time = timezone.localtime()
    uncompleted_worker.must_done = False
    uncompleted_worker.save()
    fifa_account.last_run_time = timezone.localtime()
    fifa_account.need_captcha = 0
    fifa_account.active = True
    fifa_account.can_kill_by_mother = False
    fifa_account.save()

    # check again that no one using key except this user
    time.sleep(random.randint(10, 30))
    if fifa_account.console.key_fifa_account and not key_can_use(fifa_account=fifa_account, sbc_worker=uncompleted_worker):
        return

    # if not fifa_account.active:
    # print('start fifa account working : ', fifa_account)

    # new_print(fifa_account, 'run worker but can not start squad manager or trade manager')
    # worker_runner = FifaAccount
    # core = fifa_account.refresh_from_db
    lowest_run_hour = ConsoleBotSetting.objects.get(name='lowest_account_run_in_console_hour').int_value

    # default worker runner
    worker_runner = None

    core_list = []
    if not fifa_account.is_running_console_trade_one and (
            account_works.can_play_squad is True or
            account_works.can_discharge is True or
            account_works.can_sbc is True or
            account_works.too_many_unlist_item is True or
            # todo : bellow is for start of fifa and accounts want job to go in console. remove after start
            account_works.zero_credit is True
    ):
        worker_runner = SquadBattleRunner(
            uncompleted_worker.id, fifa_account.id, fifa_account.user_name, fifa_account.password,
            fifa_account.platform, uncompleted_worker.manual_loyal)
        set_sub_log(uncompleted_worker, 'going for squad battle bot ...')
        new_print(fifa_account, 'going for squad battle bot ...')
        core_list.append(worker_runner.squad_battle_core)
    elif fifa_account.is_running_console_trade_one is True:
        last_trade_history = ConsoleTradeOneHistory.objects.filter(fifa_account=fifa_account).last()
        console_trade_quality = ConsoleTradeOneQuality.objects.filter(
            name=fifa_account.console_trade_one_quality).last()
        if (
                last_trade_history and
                ((0 <= last_trade_history.transfer_list_items_count <= 95 and
                  account_works.can_discharge is True and
                  last_trade_history.unassigned_item_count <= 0
                 ) or (((console_trade_quality and
                         not console_trade_quality.sell_items and not console_trade_quality.bid_items)
                        or (last_trade_history.transfer_list_items_count <= 95 and
                             last_trade_history.unassigned_item_count <= 0)) and
                       (account_works.can_discharge is True or
                        account_works.can_play_squad is True or
                        account_works.can_sbc is True or
                        account_works.too_many_unlist_item is True)
                 ))):
            worker_runner = SquadBattleRunner(
                uncompleted_worker.id, fifa_account.id, fifa_account.user_name, fifa_account.password,
                fifa_account.platform, uncompleted_worker.manual_loyal)
            set_sub_log(uncompleted_worker, 'going for squad battle bot 2 ...')
            new_print(fifa_account, 'going for squad battle bot 2 ...')
            core_list.append(worker_runner.squad_battle_core)
    if False and (
            (fifa_account.run_console_trade_one is True and
             # ConsoleTradeOneCard.objects.filter(
             #     fifa_account__id=fifa_account.id,
             #     create_time__gt=timezone.localtime() - timezone.timedelta(hours=lowest_run_hour)
             # ).count() < 1 and
             ConsoleTradeOneHistory.objects.filter(
                 fifa_account__id=fifa_account.id,
                 create_time__gt=timezone.localtime() - timezone.timedelta(hours=lowest_run_hour)).count() < 1 and
             # fifa_account.credit > 10000 and
             fifa_account.is_running_console_trade_one is False) or
            ((
            # ConsoleTradeOneCard.objects.filter(
            #     fifa_account__id=fifa_account.id,
            #     deleted=False,
            #     create_time__lt=timezone.localtime() - timezone.timedelta(hours=1)
            # ).count() > 0 or
              fifa_account.is_running_console_trade_one is True) and
             ConsoleTradeOneHistory.objects.exclude(update_time=None).filter(
                 fifa_account__id=fifa_account.id,
                 update_time__gt=timezone.localtime() - timezone.timedelta(hours=lowest_run_hour)).count() < 1)
    ):
        worker_runner = ConsoleTradeRunner(
            uncompleted_worker.id, fifa_account.id, fifa_account.user_name, fifa_account.password,
            fifa_account.platform, uncompleted_worker.manual_loyal)
        new_print(fifa_account, 'going for trade mode one...')
        core_list.append(worker_runner.console_trade_bot_core)
    # try:
    #     worker_runner = SquadBattleRunner(
    #         uncompleted_worker.id, fifa_account.id, fifa_account.user_name, fifa_account.password,
    #         fifa_account.platform, uncompleted_worker.manual_loyal)
    # except AssertionError as e:
    #     if str(e) == "The virtual device could not connect to ViGEmBus.":
    #         new_print(fifa_account, e)
    #         uncompleted_worker.refresh_from_db()
    #         uncompleted_worker.status = 'gamepad error'
    #         uncompleted_worker.status_change_time = timezone.localtime()
    #         uncompleted_worker.save()
    #         time.sleep(1000)
    #     return ''
    try:
        # print('core list : ', core_list)
        # print('runner created ', worker_runner.__class__.__name__)
        # try:
        #     # todo : uncomment bellow
        #     # logout_login(worker_runner, uncompleted_worker, fifa_account)
        #     pass
        # except Exception as e:
        #     new_print(fifa_account, 'login in celery task error : ', traceback.format_exc())
        #     # handle_end_bot()

        # fifa_account.refresh_from_db()
        # if fifa_account.active:
        try:
            for core in core_list:
                fifa_account.refresh_from_db()
                fifa_account.active = True
                fifa_account.save(update_fields=['active'])
                new_print(fifa_account, f'before worker {core.__name__} core manager')
                core()
                new_print(fifa_account, f'after worker {core.__name__} core manager')
                fifa_account.refresh_from_db()
                fifa_account.last_run_time = timezone.localtime()
                fifa_account.active = False
                fifa_account.save(update_fields=['last_run_time', 'active'])
            uncompleted_worker.refresh_from_db()
            uncompleted_worker.is_done = True
            uncompleted_worker.save(update_fields=['is_done'])
        except Exception as error:
            print('error 94 : ', error)
            traceback.print_exc()
            uncompleted_worker.has_error = True
            uncompleted_worker.error_description = str(error)
            uncompleted_worker.save(update_fields=['has_error', 'error_description'])
            print('saving error complete')
        # else:
        #     print('fifa account is not active')
        #     uncompleted_worker.has_error = True
        #     uncompleted_worker.error_description = 'error in login'
        #     uncompleted_worker.save()

        print('account work done and want delete game pad')
        # todo : fix bellow code. for change user no need to put on rest mode
        if fifa_account.platform == 'ps' and worker_runner:
            print('need to put on rest mode')
            worker_runner.public_moves.console_login_utils.put_on_rest_mode()
            print('sleep 60 sec before start next user')
            time.sleep(30)
    except:
        print('error 95: :', traceback.format_exc())

    if worker_runner:
        worker_runner.public_moves.ps4_buttons.__del__()
        print('game pad was successfully deleted')
    set_main_log(uncompleted_worker, 'all works done.')


def check_need_work_fifa_account(fifa_account: FifaAccount, **kwargs):
    # last_sbc_worker = kwargs.get('last_sbc_worker')
    console_last_24_hour_played = kwargs.get('console_last_24_hour_played')
    console = kwargs.get('console')
    allowed_discharge_time_var = kwargs.get('allowed_discharge_time_var')
    lowest_run_hour = ConsoleBotSetting.objects.get(name='lowest_account_run_in_console_hour').int_value
    need_some_work = FifaAccount.objects.filter(
        id=fifa_account.id
    ).annotate(
        uncompleted_sbc=Value(SBCType.objects.filter(console_can_use=True, must_done=1).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__id=fifa_account.id, is_done=True
            ).distinct('sbc_type').values_list('sbc_type__id', flat=True)
        ).count()),
        uncompleted_sbc_price=Coalesce(SBCType.objects.filter(console_can_use=True, must_done=1).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__id=fifa_account.id, is_done=True
            ).distinct('sbc_type').values_list('sbc_type__id', flat=True)
        ).aggregate(Sum('sbc_actual_price')).get('sbc_actual_price__sum'), Value(0)),
        completed_sbc=Value(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_account.id, is_done=True
            ).distinct('sbc_type').values_list('sbc_type__id', flat=True)
        ).count()),
        # can_play_1=Value(console_last_24_hour_played.count() < console.allowed_play_game_day),
        can_play_2=Value(calculate_need_game2(
            account_played=fifa_account.account_played_games,
            account_limit_play=fifa_account.allowed_play_game,
            # console_last_24_hour_played.count(),
            # console_limit=fifa_account.console.allowed_play_game_day,
            account_play_day=fifa_account.fifaaccountsquadgame_set.filter(
                create_time__gt=timezone.localtime() - timezone.timedelta(hours=24)
            ).count(),
            account_limit_day=fifa_account.allowed_play_game_day
        ) > 0),
        account_24_played_games=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
            fifa_account__id=OuterRef('pk'),
            create_time__gt=timezone.localtime() - timezone.timedelta(hours=24)
        ).values('fifa_account').annotate(
            played_count=Count('id', output_field=IntegerField())
        ).values('played_count'), output_field=IntegerField()), Value(0)),
        account_play_31_days=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
            fifa_account__id=OuterRef('pk'),
            create_time__gt=timezone.localtime() - timezone.timedelta(days=31)
        ).values('fifa_account').annotate(
            played_count_31_day=Count('id', output_field=IntegerField())
        ).values('played_count_31_day'), 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)),
        pro_and_semi_pro_played_count=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
            fifa_account__id=OuterRef('pk'),
            difficulty__in=['semi_pro', 'professional'],
        ).values('fifa_account').annotate(
            difficulty_played_count_all=Count('id', output_field=IntegerField())
        ).values('difficulty_played_count_all'), output_field=IntegerField()), Value(0)),
        # trade_one_2_hour=Coalesce(Subquery(ConsoleTradeOneCard.objects.filter(
        #     fifa_account__id=OuterRef('pk'),
        #     create_time__gt=timezone.localtime() - timezone.timedelta(hours=lowest_run_hour)
        # ).values('fifa_account').annotate(
        #     trade_one_6_count=Count('id', output_field=IntegerField())
        # ).values('trade_one_6_count'), output_field=IntegerField()), Value(0)),
        # trade_one_unsoled_items=Coalesce(Subquery(ConsoleTradeOneCard.objects.filter(
        #     fifa_account__id=OuterRef('pk'),
        #     deleted=False,
        # ).values('fifa_account').annotate(
        #     unsoled_items=Count('id', output_field=IntegerField())
        # ).values('unsoled_items'), output_field=IntegerField()), Value(0)),
        # trade_one_1_hour_history=Coalesce(Subquery(ConsoleTradeOneHistory.objects.filter(
        #     fifa_account__id=OuterRef('pk'),
        #     create_time__gt=timezone.localtime() - timezone.timedelta(hours=lowest_run_hour)
        # ).values('fifa_account').annotate(
        #     trade_one_history=Count('id', output_field=IntegerField())
        # ).values('trade_one_history'), output_field=IntegerField()), Value(0)),
        # trade_one_1_hour_history_update=Coalesce(Subquery(ConsoleTradeOneHistory.objects.filter(
        #     fifa_account__id=OuterRef('pk'),
        #     update_time__gt=timezone.localtime() - timezone.timedelta(hours=lowest_run_hour)
        # ).values('fifa_account').annotate(
        #     trade_one_history_update=Count('id', output_field=IntegerField())
        # ).values('trade_one_history_update'), output_field=IntegerField()), Value(0)),
        account_unlisted_items=Coalesce(Subquery(AccountSalablePlayerCard.objects.filter(
            fifa_account__id=OuterRef('pk'),
        ).values('fifa_account').annotate(
            player_count_all=Count('id', output_field=IntegerField())
        ).values('player_count_all'), output_field=IntegerField()), Value(0)),
        account_unlisted_items2=Coalesce(Subquery(FifaAccountCurrentItems.objects.filter(
            fifa_account__id=OuterRef('pk'),
        ).values('transfer_list_items_count'), output_field=IntegerField()), Value(0)),
        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(can_play_1=True) &
            (Q(can_play_2=True) | Q(squad_special_game_one=False) |
             Q(squad_special_game_two=False)) &
            Q(allowed_play_game_day__gte=F('account_24_played_games')) &
            # Q(account_play_31_days__lt=Value(88))
            (Q(account_all_played_games__lt=Value(ACCOUNT_ALLOWED_PLAYED_ALL)) |
             Q(account_all_played_games__gt=Value(400)) |
             Q(console__name__in=list(range(90, 100)))
             # Q(console__name__in=[120, 2040, 2041, 2042, 2043, 2044, 2045])
             # Q(pro_and_semi_pro_played_count__gte=Value(70))
             )
            # Q(is_running_console_trade_one=False)
        ), output_field=BooleanField()),
        can_discharge=ExpressionWrapper(Q(
            Q(run_discharge=True) &
            Q(credit__gt=ConsoleBotSetting.objects.get(name='discharge_start_coin_greater').int_value) &
            Q(credit__lt=ConsoleBotSetting.objects.get(name='discharge_start_coin_lower').int_value)
            & Value(allowed_discharge_time_var)
            # Q(is_running_console_trade_one=False)
        ), output_field=BooleanField()),
        can_sbc=ExpressionWrapper(Q(
            Q(run_sbc=True) & Q(uncompleted_sbc__gt=0) &
            # todo : for now our sbc don't need coin , if need coin uncomment bellow
            # (Q(credit__gt=F('uncompleted_sbc_price')) | (Q(credit__gt=5000) & Q(completed_sbc__gt=0)))
            # Q(credit__gt=8000)
            Q(credit__gt=0)

            # Q(is_running_console_trade_one=False)
        ), output_field=BooleanField()),
        can_console_trade=ExpressionWrapper(Q(
            Q(trade_access__in=['0', '1', '3']) &  # trade access 2 not work for trade. use in mule
            (Q(run_console_trade_one=True) &
             # Q(trade_one_2_hour__lt=1) &
             # Q(trade_one_1_hour_history__lt=1) &
             Q(credit__gt=10000) &
             Q(is_running_console_trade_one=False)) |
            ((
                     # Q(trade_one_unsoled_items__gt=0) |
                     Q(is_running_console_trade_one=True))
             # & Q(trade_one_1_hour_history_update__lt=1)
             )), output_field=BooleanField()),
        # can_console_trade=Value(False),
        need_force_relist=ExpressionWrapper(Q(
            is_running_console_trade_one=True,
            run_console_invest_trade_one=False,
            last_run_time__lt=timezone.localtime() - timezone.timedelta(hours=1)), output_field=BooleanField()),
        too_many_unlist_item=ExpressionWrapper(
            # todo : increase unlisted items to 80. for start of fifa decreased.
            Q((Q(account_unlisted_items__gte=ACCOUNT_TOO_MANY_UNLISTED_ITEMS2) | Q(account_unlisted_items2__gte=ACCOUNT_TOO_MANY_UNLISTED_ITEMS2)) & Q(
                Q(run_squad_battle=True) | Q(run_discharge=True) | Q(run_sbc=True)
            )), output_field=BooleanField()),
        no_delete_console_reason=ExpressionWrapper(
            Q(Q(delete_console_reason=None) | Q(delete_console_reason='')),
            output_field=BooleanField()
        ),
        zero_credit=ExpressionWrapper(
            Q(Q(credit=0) & Q(Q(run_discharge=True) | Q(run_sbc=True))),
            output_field=BooleanField())
    ).filter(
        Q(stop_for_update_game=False) & Q(
            last_run_time__lt=timezone.localtime() - timezone.timedelta(hours=lowest_run_hour)
        ) & Q(no_delete_console_reason=True) &
        (Q(can_play_squad=True) | Q(can_discharge=True) | Q(can_sbc=True) | Q(can_console_trade=True) |
         Q(need_force_relist=True) | Q(too_many_unlist_item=True)
         # todo : bellow is for start of fifa and accounts want job to go in console. remove after start
         | Q(zero_credit=True))
    )

    return need_some_work


def get_console_last_24_hour_played(console):
    return FifaAccountSquadGame.objects.filter(
        fifa_account__in=console.fifaaccount_set.filter(
            Q(delete_console_reason=None) | Q(delete_console_reason='')
        ),
        create_time__gt=timezone.localtime() - timezone.timedelta(hours=24)
    )


# bellow for test query
# for fifa_account in FifaAccount.objects.filter(console__name=4):
# fifa_account = FifaAccount.objects.get(user_name='chemidonamchichi@outlook.com')
# need_works = check_need_work_fifa_account(
#         fifa_account,
#         console_last_24_hour_played=get_console_last_24_hour_played(fifa_account.console),
#         console=fifa_account.console,
#         allowed_discharge_time_var=allowed_discharge_time()
#     )
# print(need_works)
# exit(1)

def start_squad_manager(console_name):
    try:
        stopped_workers = SBCWorker.objects.filter(
            is_done=False, has_error=False, must_done=False, running_platform='console',
            status_change_time__lt=timezone.localtime() - timezone.timedelta(minutes=40),
            fifa_account__console__name=console_name
        ).update(has_error=True, error_description='worker stopped middle of work')
        print('workers stopped : ', stopped_workers)
    except:
        print('cant close old workers', traceback.format_exc())
    try:
        allowed_discharge_time_var = allowed_discharge_time()
        console = Console.objects.filter(name=console_name).first()
        console_last_24_hour_played = get_console_last_24_hour_played(console=console)
        fifa_account_worked_in_24_hour = SBCWorker.objects.filter(
            fifa_account__console=console,
            status_change_time__gt=timezone.localtime() - timezone.timedelta(hours=24)
        ).distinct('fifa_account__id').values_list('fifa_account__id', flat=True)[:console.allowed_account_work_day]
        if console:
            sane_console_fifa_accounts = FifaAccount.objects.filter(
                console=console,
                # todo : delete bellow line after captcha solver fixed
                # need_captcha=False,
            ).filter(
                Q(delete_console_reason=None) | Q(delete_console_reason=''),
            ).exclude(name_in_console='key').order_by('last_run_time')
            if console.is_active is False and sane_console_fifa_accounts.first():
                console_first_account = sane_console_fifa_accounts.first()
                print('console deactive , pressing left and right for keep console alive , first account : ',
                      console_first_account)
                console_first_account.sbcworker_set.last()
                threading.Thread(target=focus_on_ps,
                                 kwargs={'fifa_account': console_first_account}).start()
                # using thread because ps4 maybe has error on focus
                # focus_on_ps(console_first_account)
                time.sleep(5)
                public_moves = PublicMoves(None, console_first_account.sbcworker_set.last(), None, {},
                                           None)
                print('check for errors 2')
                current_state = public_moves.just_find_state()
                if not current_state:
                    new_print(console_first_account, 'can not find current state : ', current_state)
                    try:
                        public_moves.xboxs_go_to_app()
                    except:
                        new_print(console_first_account, 'exception in open xbox app : ', traceback.format_exc())
                else:
                    new_print(console_first_account, 'opening ultimate 2, current state : ', current_state)
                    threading.Thread(target=public_moves.console_login_utils.focus_on_ps).start()
                    time.sleep(10)
                new_print(console_first_account,
                          'console deactive , pressing left and right for keep console alive , ',
                          public_moves.just_find_state())
                public_moves.get_screen_shot()
                public_moves.errors()
                time.sleep(5)
                print('console deactive , pressing left and right for keep console alive 2')
                public_moves.ps4_buttons.left()
                time.sleep(1)
                public_moves.ps4_buttons.right()
                time.sleep(10)
                return
            try:
                local_time = get_db_time(timezone_=TIME_ZONE)
            except:
                print('cant get local_time from server , ', traceback.format_exc())
                local_time = timezone.localtime()
            if console.turn_off_after_work and console_need_force_sleep():
                current_console_work = console_worker_cache.get('current_console_work')
                print(f'this console {current_console_work} need sleep, set next console for work')
                set_next_console_work()
                time.sleep(10)
                return
                # first_account = sane_console_fifa_accounts.first()
                # sleep_text = f'work time out of range , current time : {local_time} , start time : {console.work_start_time} , end time : {console.work_end_time} , logs in {first_account}'
                # print(sleep_text)
                # if first_account:
                #     new_print(first_account, sleep_text)
                # set_console_status(console=console, status='PC is asleep')
                # time.sleep(1)
                # sleep_command = '''Start-Sleep -Seconds 5
                #                     Add-Type -AssemblyName System.Windows.Forms
                #                     [System.Windows.Forms.Application]::SetSuspendState("Suspend", $false, $false)'''
                # subprocess.Popen(['powershell.exe', sleep_command])
                # return
            # run force relist console trade one items
            force_relist_accounts = sane_console_fifa_accounts.filter(
                is_running_console_trade_one=True,
                run_console_invest_trade_one=False,
                last_run_time__lt=timezone.localtime() - timezone.timedelta(hours=1),
                stop_for_update_game=False,
            ).order_by('last_run_time')

            for relist_account in force_relist_accounts:
                need_work_3 = check_need_work_fifa_account(
                    relist_account, console_last_24_hour_played=console_last_24_hour_played,
                    console=console, allowed_discharge_time_var=allowed_discharge_time_var)
                need_work_3_account = need_work_3.first()
                if need_work_3_account and need_work_3_account.need_force_relist:
                    force_relist_sbc_worker = SBCWorker.objects.filter(
                        is_done=False, has_error=False,
                        running_platform='console',
                        fifa_account=relist_account,
                    ).last()
                    if force_relist_sbc_worker:
                        print('existed sbc worker found. worker id = ', force_relist_sbc_worker.id,
                              '\n account email = ', force_relist_sbc_worker.fifa_account.user_name,
                              '\n need work = force relist ')
                        new_print(force_relist_sbc_worker.fifa_account,
                                  'existed sbc worker found. worker id = ', force_relist_sbc_worker.id,
                                  '\n need work = force relist ')
                    else:
                        force_relist_sbc_worker = SBCWorker.objects.create(
                            is_done=False, has_error=False,
                            running_platform='console',
                            fifa_account=relist_account,
                        )
                        new_print(force_relist_sbc_worker.fifa_account,
                                  'new worker , worker id = ', force_relist_sbc_worker.id,
                                  '\n need work = force relist ', )
                    run_worker(worker_id=force_relist_sbc_worker.id)
                    return

            # if force_relist_accounts:
            #     force_relist_sbc_worker = SBCWorker.objects.filter(
            #         is_done=False, has_error=False,
            #         running_platform='console',
            #         fifa_account__in=force_relist_accounts,
            #     ).last()
            #     if not force_relist_sbc_worker:
            #         force_relist_sbc_worker, created = SBCWorker.objects.get_or_create(
            #             is_done=False, has_error=False,
            #             running_platform='console',
            #             fifa_account=force_relist_accounts.last(),
            #         )
            #     print('existed sbc worker found. worker id = ', force_relist_sbc_worker.id,
            #           '\n account email = ', force_relist_sbc_worker.fifa_account.user_name,
            #           '\n need work = force relist ')
            #     new_print(force_relist_sbc_worker.fifa_account,
            #               'existed sbc worker found. worker id = ', force_relist_sbc_worker.id,
            #               '\n need work = force relist ')
            #     run_worker(worker_id=force_relist_sbc_worker.id)
            #     return
            # run force discharge
            # force_discharge_fifa_accounts = FifaAccount.objects.filter(
            #     console=console
            # ).filter(
            #     Q(delete_console_reason=None) | Q(delete_console_reason=''),
            #     run_force_discharge=True
            # ).exclude(name_in_console='key').order_by('last_run_time')
            force_discharge_fifa_accounts = sane_console_fifa_accounts.filter(
                run_force_discharge=True,
                stop_for_update_game=False,
            ).order_by('last_run_time')
            if fifa_account_worked_in_24_hour.count() >= console.allowed_account_work_day:
                force_discharge_fifa_accounts = force_discharge_fifa_accounts.filter(
                    id__in=fifa_account_worked_in_24_hour
                )
            existed_force_discharge_worker = SBCWorker.objects.filter(
                is_done=False, has_error=False,
                running_platform='console',
                fifa_account__in=force_discharge_fifa_accounts,
            ).last()
            if existed_force_discharge_worker:
                print('existed sbc worker found. worker id = ', existed_force_discharge_worker.id,
                      '\n account email = ', existed_force_discharge_worker.fifa_account.user_name,
                      '\n need work = force discharge ')
                new_print(existed_force_discharge_worker.fifa_account,
                          'existed sbc worker found. worker id = ', existed_force_discharge_worker.id,
                          '\n need work = force discharge ')
                set_main_log(existed_force_discharge_worker, 'preparing for discharge...')
                set_sub_log(existed_force_discharge_worker, 'preparing for discharge with existed sbc worker...')
                run_worker(worker_id=existed_force_discharge_worker.id)
                return
            elif force_discharge_fifa_accounts:
                last_force_discharge_worker, created = SBCWorker.objects.get_or_create(
                    is_done=False, has_error=False,
                    running_platform='console',
                    fifa_account=force_discharge_fifa_accounts.last(),
                )
                print('new worker id = ', last_force_discharge_worker.id,
                      '\n account email = ', last_force_discharge_worker.fifa_account.user_name,
                      '\n need work = force discharge ')
                new_print(last_force_discharge_worker.fifa_account,
                          'new worker id = ', last_force_discharge_worker.id,
                          '\n need work = force discharge 2')
                set_main_log(last_force_discharge_worker, 'preparing for discharge ...')
                set_sub_log(last_force_discharge_worker, 'preparing for discharge with new sbc worker...')
                run_worker(worker_id=last_force_discharge_worker.id)
                return
            allowed_discharge_time_var = allowed_discharge_time()

            # run other works
            # fifa_accounts = FifaAccount.objects.filter(
            #     Q(delete_console_reason=None) | Q(delete_console_reason=''),
            #     console=console
            # ).exclude(name_in_console='key').order_by('last_run_time')
            fifa_accounts = sane_console_fifa_accounts.filter(
                stop_for_update_game=False,
            ).order_by('last_run_time')
            if fifa_account_worked_in_24_hour.count() >= console.allowed_account_work_day:
                fifa_accounts = fifa_accounts.filter(
                    id__in=fifa_account_worked_in_24_hour
                )

            for fifa_account_1 in fifa_accounts:
                existed_sbc_worker = SBCWorker.objects.filter(
                    is_done=False, has_error=False,
                    running_platform='console',
                    fifa_account=fifa_account_1,
                ).last()
                if existed_sbc_worker:
                    need_work = check_need_work_fifa_account(
                        fifa_account_1,
                        # last_sbc_worker=existed_sbc_worker,
                        console_last_24_hour_played=console_last_24_hour_played,
                        console=console,
                        allowed_discharge_time_var=allowed_discharge_time_var)

                    if need_work:
                        print('existed sbc worker found. worker id = ', existed_sbc_worker.id,
                              '\n account email = ', fifa_account_1.user_name,
                              '\n need work = ', need_work)
                        first_work = need_work.first().__dict__
                        new_print(fifa_account_1,
                                  'existed sbc worker found. worker id = ', existed_sbc_worker.id,
                                  '\n need work = ', {k: v for k, v in first_work.items()
                                                      if k not in ['_state', 'cookies', 'access_token']}
                                  )
                        # set_main_log(existed_sbc_worker, 'preparing for work...')
                        # set_sub_log(existed_sbc_worker, 'preparing for work with existed sbc worker...')
                        run_worker(worker_id=existed_sbc_worker.id)
                        return
            for fifa_account_2 in fifa_accounts.annotate(
                    account_unlisted_items=Coalesce(Subquery(AccountSalablePlayerCard.objects.filter(
                        fifa_account__id=OuterRef('pk'),
                    ).values('fifa_account').annotate(
                        player_count_all=Count('id', output_field=IntegerField())
                    ).values('player_count_all'), output_field=IntegerField()), Value(0)),
                    account_unlisted_items2=Coalesce(Subquery(FifaAccountCurrentItems.objects.filter(
                        fifa_account__id=OuterRef('pk'),
                    ).values('transfer_list_items_count'), output_field=IntegerField()), Value(0)),
                    need_relist_first=ExpressionWrapper(
                        Q(account_unlisted_items__gte=ACCOUNT_TOO_MANY_UNLISTED_ITEMS2) | Q(account_unlisted_items2__gte=ACCOUNT_TOO_MANY_UNLISTED_ITEMS2),
                        output_field=BooleanField()
                    ),
                    zero_credit_first=Case(
                        When(credit=0, then=0),
                        default=1,
                        output_field=IntegerField()
                    )
            ).order_by('zero_credit_first', '-need_relist_first', '-credit'):
            # ).order_by('zero_credit_first', '-credit'):
                last_sbc_worker = SBCWorker.objects.filter(
                    running_platform='console',
                    fifa_account=fifa_account_2,
                    last_run_time__gt=timezone.localtime() - timezone.timedelta(days=2)
                ).order_by('status_change_time').last()
                created = False
                # print(f'fifa account : {fifa_account_2} \n sbc worker in two days : {last_sbc_worker}')
                if not last_sbc_worker:
                    last_sbc_worker, created = SBCWorker.objects.get_or_create(
                        is_done=False, has_error=False,
                        running_platform='console',
                        fifa_account=fifa_account_2,
                    )
                need_work_2 = check_need_work_fifa_account(
                    fifa_account_2,
                    # last_sbc_worker=last_sbc_worker,
                    console_last_24_hour_played=console_last_24_hour_played,
                    console=console,
                    allowed_discharge_time_var=allowed_discharge_time_var)

                if need_work_2.first():
                    if created is False:
                        last_sbc_worker, created = SBCWorker.objects.get_or_create(
                            is_done=False, has_error=False,
                            running_platform='console',
                            fifa_account=fifa_account_2,
                        )
                    print('start squad battle account email = ', fifa_account_2.user_name)
                    first_work = need_work_2.first().__dict__
                    new_print(fifa_account_2, 'start squad battle , need work 2 ',
                              '\n need work = ',
                              {k: v for k, v in first_work.items()
                               if k not in ['_state', 'cookies', 'access_token']})

                    set_sbc_status(last_sbc_worker, status='Start Console Bots')
                    # sbc_worker, created = SBCWorker.objects.get_or_create(
                    #     is_done=False, has_error=False,
                    #     running_platform='console',
                    #     fifa_account=fifa_account_2,
                    # )
                    # set_main_log(last_sbc_worker, 'preparing for work...')
                    # set_sub_log(last_sbc_worker, 'preparing for work with new sbc worker...')
                    run_worker(worker_id=last_sbc_worker.id)
                    print('run worker done')
                    return

            set_next_console_work()
            print('all accounts is done')
            uncompeleted_workers = SBCWorker.objects.filter(
                is_done=False, has_error=False,
                running_platform='console',
                fifa_account__in=console.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason='')
                ),
            )
            is_active_accounts_id = list(uncompeleted_workers.values_list('fifa_account__id', flat=True))
            uncompeleted_workers.update(is_done=True)
            FifaAccount.objects.filter(
                id__in=is_active_accounts_id
            ).update(active=False)
            print('all workers make done')
            all_uncompleted_workers = SBCWorker.objects.filter(
                is_done=False, has_error=False, must_done=False,
                fifa_account__console=console,
            ).values_list('fifa_account_id', flat=True)
            FifaAccount.objects.filter(
                Q(delete_console_reason=None) | Q(delete_console_reason=''),
                console=console,
                active=True,
            ).exclude(
                id__in=all_uncompleted_workers
            ).update(active=False)
            print('make unused accounts deactive')
            console_first_account = console.fifaaccount_set.filter(
                Q(delete_console_reason=None) | Q(delete_console_reason=''),
            ).first()
            first_play_game = FifaAccountSquadGame.objects.filter(
                fifa_account__in=console.fifaaccount_set.filter(
                    Q(delete_console_reason=None) | Q(delete_console_reason='')
                ),
                create_time__gt=timezone.localtime() - timezone.timedelta(hours=24)
            ).first()
            if first_play_game:
                first_play_time = first_play_game.create_time
            else:
                first_play_time = timezone.localtime()
            need_rest_time = (first_play_time + timezone.timedelta(hours=24)) - timezone.localtime()
            console.refresh_from_db()
            if console_first_account:
                print('log will in account : ', console_first_account)
                new_print(console_first_account, 'no other worker found so log goes here')
                # todo uncomment bellows
                if (console.turn_off_after_work
                        # console_last_24_hour_played.count() >= console.allowed_play_game_day and
                        # need_rest_time.seconds > 60 * 60 * 3
                ):
                    if len(CONSOLE_NAME_LIST) > 1:
                        print('need sleep pc but more than 1 console exists in this pc')
                        time.sleep(20)
                        return
                    console_first_account.sbcworker_set.last()
                    print('i am complete all games and need turn off , log will in account : ', console_first_account)
                    threading.Thread(target=focus_on_ps, kwargs={'fifa_account': console_first_account}).start()
                    # using thread because ps4 maybe has error on focus
                    # focus_on_ps(console_first_account)
                    time.sleep(5)
                    public_moves = PublicMoves(None, console_first_account.sbcworker_set.last(), None, {}, None)
                    if not public_moves.just_find_state():
                        print('want to shut down but status not found')
                        new_print(console_first_account, 'want to shut down but status not found')
                        public_moves.ps4_buttons.ps()
                        time.sleep(5)
                        public_moves.ps4_buttons.cross()
                        time.sleep(10)
                    if public_moves.just_find_state():
                        print('check for errors 3')
                        new_print(console_first_account, 'i am complete all games and need turn off.'
                                                         ' automatically console sleep')
                        # new_print(console_first_account, 'i am complete all games and need turn off')
                        # public_moves.get_screen_shot()
                        # public_moves.errors()
                        # time.sleep(5)
                        # print('shutting done console')
                        # public_moves.ps4_buttons.ps(press_time=1)
                        # time.sleep(1)
                        # public_moves.ps4_buttons.up()
                        # time.sleep(1)
                        # public_moves.ps4_buttons.up()
                        # time.sleep(1)
                        # public_moves.ps4_buttons.cross()
                        # time.sleep(10)

                        # console.refresh_from_db()
                        # console.pc_is_on = False
                        # console.save()
                        # time.sleep(1)
                    else:
                        print('can not find state to restart console')
                        new_print(console_first_account, 'can not find state to restart console')
                    # turn of pc
                    # os.system("shutdown /s /t 1")
                    set_console_status(console=console, status='PC is asleep')
                    time.sleep(1)
                    sleep_command = '''Start-Sleep -Seconds 5
                                    Add-Type -AssemblyName System.Windows.Forms
                                    [System.Windows.Forms.Application]::SetSuspendState("Suspend", $false, $false)'''
                    subprocess.Popen(['powershell.exe', sleep_command])
                    return
                if console.restart_console_for_update:
                    threading.Thread(target=focus_on_ps, kwargs={'fifa_account': console_first_account}).start()
                    time.sleep(5)
                    public_moves = PublicMoves(None, console_first_account.sbcworker_set.last(), None, {}, None)
                    print('check for errors 4')
                    new_print(console_first_account, 'need to restart console for update')
                    public_moves.get_screen_shot()
                    public_moves.errors()
                    time.sleep(5)
                    if public_moves.just_find_state():
                        public_moves.console_login_utils.restart_console()
                        console.refresh_from_db()
                        console.restart_console_for_update = False
                        console.save()
                        return
                    else:
                        print('can not find state to restart console 2')
                        new_print(console_first_account, 'can not find state to restart console 2')
                if console.restart_pc_for_update:
                    console.restart_pc_for_update = False
                    console.save()
                    new_print(console_first_account, 'console restart_pc_for_update , will restart pc')
                    os.system("shutdown /r /t 1")
                    return
                first_account_worker = console_first_account.sbcworker_set.last()
                print('i am resting , log will in account : ', console_first_account,
                      ' rest seconds : ', need_rest_time.seconds)
                threading.Thread(target=focus_on_ps, kwargs={'fifa_account': console_first_account}).start()
                # using thread because ps4 maybe has error on focus
                # focus_on_ps(console_first_account)
                time.sleep(5)
                public_moves = PublicMoves(None, first_account_worker, None, {}, None)
                # print('check for errors 5')
                print(console_first_account, 'resting 3 , pressing left and right for keep console alive , ',
                          public_moves.just_find_state())
                public_moves.get_screen_shot()
                public_moves.errors(
                    excluded_images=['key_duplicate_error.png', 'key_duplicate_error2.png', 'windows_expire.png'],
                    add_log=False)
                time.sleep(5)
                print('pressing left and right for keep console alive')
                public_moves.ps4_buttons.left()
                time.sleep(1)
                public_moves.ps4_buttons.right()
                console_last_status = ConsoleLastStatus.objects.filter(console=console).last()
                # dont air plan consoles , all account is done
                if console_last_status and console_last_status.status == 'can not connect to console':
                    print('console has air plan error , so dont make it all account is done.')
                else:
                    set_console_status(
                        console=console_first_account.console, status='all account is done', update_time=False
                    )
                time.sleep(10)
                return
            else:
                print('no healthful account found. please check delete_console_reason of accounts. sleep 300 sec')
                time.sleep(300)
        else:
            print('console not found in database')
            return
            # except InterfaceError:
    #     print('exception happend 87')
    #     close_old_connections()
    #     print('connection error. retry and sleep 100 second')
    #     time.sleep(100)
    except:
        print('exception happened 88')
        traceback.print_exc()
    close_old_connections()
    return


def dynamic_allowed_play_game(console_name):
    try:
        console = Console.objects.filter(name=console_name).first()
        console_accounts = FifaAccount.objects.filter(console=console)
        if console_accounts.count() == 0:
            print('no account found , console : ', console)
            time.sleep(10)
            return
        if console_accounts.count() == 10:
            console_accounts.update(allowed_play_game=25)
        else:
            can_played = int(245 / console_accounts.count())
            print('console : ', console, 'account counts : ', console_accounts.count(), ' can played : ', can_played)
            if can_played > 40:
                console_accounts.update(allowed_play_game=40)
            else:
                console_accounts.update(allowed_play_game=can_played)

    except:
        print('exception happened 89')
        traceback.print_exc()
    close_old_connections()
    return


def dynamic_force_discharge(console_name):
    try:
        console = Console.objects.filter(name=console_name).first()
        console_accounts = FifaAccount.objects.filter(console=console)
        sum_credit = console_accounts.aggregate(sum_credit=Sum('credit')).get('sum_credit') or 0
        if sum_credit > 400 * 1000 and allowed_discharge_time() and console_accounts.first().run_discharge is True:
            print(f'sum credit {sum_credit} so run force discharge for console accounts')
            console_accounts.update(run_force_discharge=True)
        elif allowed_discharge_time() and console_accounts.first().run_discharge is True:
            for acc in console_accounts:
                if acc.credit > 100 * 1000:
                    print(f'account {acc} has {acc.credit} need force discharge')
                    acc.run_force_discharge = True
                    acc.save()
    except:
        print('exception happened 89')
        traceback.print_exc()
    close_old_connections()
    return


def check_update_console_games(console_name):
    try:
        console = Console.objects.get(name=console_name)
        last_account = console.fifaaccount_set.last()
        las_sbc_worker = SBCWorker.objects.filter(fifa_account=last_account).last()
        if console.need_games_update:
            print(f'need games update . log in account : {last_account.user_name}')
            console.need_games_update = False
            console.save()
            squad_battle_runner = SquadBattleRunner(
                las_sbc_worker.id, last_account.id,
                last_account.user_name, last_account.password,
                last_account.platform, False)
            squad_battle_runner.public_moves.console_login_utils.xbox_check_for_update()
    except:
        print('exception happened 90')
        traceback.print_exc()
    close_old_connections()
    return


def dynamic_console_allowed_play_day(console_name):
    try:
        close_old_connections()
        console = Console.objects.get(name=console_name)
        console.allowed_play_game_day = console.fifaaccount_set.filter(
            Q(delete_console_reason=None) | Q(delete_console_reason=''),
        ).annotate(
            account_play_31_days=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
                fifa_account__id=OuterRef('pk'),
                create_time__gt=timezone.localtime() - timezone.timedelta(days=31)
            ).values('fifa_account').annotate(
                played_count_31_day=Count('id', output_field=IntegerField())
            ).values('played_count_31_day'), 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)),
            pro_and_semi_pro_played_count=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
                fifa_account__id=OuterRef('pk'),
                difficulty__in=['semi_pro', 'professional'],
            ).values('fifa_account').annotate(
                difficulty_played_count_all=Count('id', output_field=IntegerField())
            ).values('difficulty_played_count_all'), output_field=IntegerField()), Value(0)),
        ).filter(
            # account_play_31_days__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(90, 100)))
             # Q(console__name__in=[120, 2040, 2041, 2042, 2043, 2044, 2045])
             # Q(pro_and_semi_pro_played_count__gte=Value(70))
             )
        ).aggregate(
            sum_account_day=Sum('allowed_play_game_day')).get('sum_account_day') or 0
        console.save()
    except:
        print('exception happened 91')
        traceback.print_exc()
    try:
        close_old_connections()
        console = Console.objects.get(name=console_name)
        console.pc_is_on = True
        console.save()
    except:
        print('exception happened 92')
        traceback.print_exc()
    close_old_connections()
    return


def check_xbox_turn_on():
    try:
        if Console.objects.get(name=CONSOLE_NAME).fifaaccount_set.first().platform == 'ps':
            print('this is ps')
            return
        if process_exists('XboxPcApp.exe'):
            print('xbox app already is open')
            return
        os.system('TASKKILL /F /IM xboxpcapp.exe /FI "USERNAME eq %username%"')
        keyboard.press_and_release('win')
        time.sleep(1)
        keyboard.write('Xbox Console Companion')
        time.sleep(10)
        keyboard.press_and_release('enter')
        time.sleep(60)
        get_screen_shot()
        if has_image(
                os.path.join(BASE_DIR, f'utils/xbox_companion/connecting_menu_icon.png'),
                'screen_shot_tmp.jpg'
        ):
            connection_icon_pos = get_image_position('utils/xbox_companion/connecting_menu_icon.png',
                                                     'screen_shot_tmp.jpg')
        elif has_image(
                os.path.join(BASE_DIR, f'utils/xbox_companion/connecting_menu_icon2.png'),
                'screen_shot_tmp.jpg'):
            connection_icon_pos = get_image_position('utils/xbox_companion/connecting_menu_icon2.png',
                                                     'screen_shot_tmp.jpg')
        else:
            raise Exception('Can not find connection icon')
        mouse.move(connection_icon_pos['top_left'][0], connection_icon_pos['top_left'][1])
        mouse.click('left')
        time.sleep(60)
        get_screen_shot()
        if has_image(
                os.path.join(BASE_DIR, f'utils/xbox_companion/turn_on.png'),
                'screen_shot_tmp.jpg'):
            turn_on_icon_pos = get_image_position('utils/xbox_companion/turn_on.png',
                                                  'screen_shot_tmp.jpg')
            mouse.move(turn_on_icon_pos['top_left'][0], turn_on_icon_pos['top_left'][1])
            mouse.click('left')
            print('ok i found turn on')
            time.sleep(90)
        else:
            raise Exception('Can not find turn on icon')
    except:
        print('exception happened 93')
        traceback.print_exc()
        os.system('TASKKILL /F /IM xboxpcapp.exe /FI "USERNAME eq %username%"')


def create_origin():
    CreateOutlookMail().core()


def console_power_command(console_obj: Console):
    if console_obj:
        try:
            close_old_connections()
            while works_done is False:
                consoles_power_command = list(ConsolePowerCommand.objects.filter(
                    arduino_pc__name=str(console_obj.name),
                ).exclude(
                    command_status='done',
                ).order_by('update_time'))
                if consoles_power_command:
                    import serial
                    import serial.tools.list_ports
                    SERIAL_PORT = 9600
                    BOUD_RATE = consoles_power_command[0].arduino_pc_usb
                    if not BOUD_RATE:
                        arduino_ports = [port.device for port in serial.tools.list_ports.comports()]
                        print('arduino pc usb not detected , pc usb names : ', arduino_ports)
                        for port_name in arduino_ports:
                            with serial.Serial(port_name, SERIAL_PORT, timeout=1) as ser:
                                time.sleep(5)  # times need to start serial. its time to void setup() work.
                                ser.flush()
                                time.sleep(1)
                                commands = json.dumps({'commands': []})
                                ser.write(commands.encode())
                                time.sleep(5)
                                response = ser.read(100)  # read 100 character
                                if response.decode().strip() == 'done':
                                    print('arduino pc usb name is : ', port_name)
                                    time.sleep(10)
                        return
                    with serial.Serial(BOUD_RATE, SERIAL_PORT, timeout=1) as ser:
                        for c_p_command in consoles_power_command:
                            if c_p_command.last_command == 'turn_on':
                                time.sleep(5)
                                ser.flush()
                                time.sleep(1)
                                commands = json.dumps({'commands': [
                                    # [angle, seconds, port]
                                    [45, 1, c_p_command.arduino_port - 1],
                                    [1, 1, c_p_command.arduino_port - 1],
                                ]})
                                ser.write(commands.encode())
                                time.sleep(6)
                                response = ser.read(100)
                                if response.decode().strip() == 'done':
                                    c_p_command.command_status = 'done'
                                    c_p_command.update_time = timezone.localtime()
                                    c_p_command.save(update_fields=['update_time', 'command_status'])
                                else:
                                    print('arduino response not fix : ', response.decode())
                            elif c_p_command.last_command == 'shutdown':
                                time.sleep(2)
                                ser.flush()
                                time.sleep(1)
                                commands = json.dumps({'commands': [
                                    # [angle, seconds, port]
                                    [45, 7, c_p_command.arduino_port - 1],
                                    [1, 1, c_p_command.arduino_port - 1],
                                ]})
                                ser.write(commands.encode())
                                time.sleep(15)
                                response = ser.read(100)
                                if response.decode().strip() == 'done':
                                    c_p_command.command_status = 'done'
                                    c_p_command.update_time = timezone.localtime()
                                    c_p_command.save(update_fields=['update_time', 'command_status'])
                                else:
                                    print('arduino response not fix 2 : ', response.decode())
                time.sleep(10)
        except:
            print('exception in console command : ', traceback.format_exc())
            time.sleep(10)
            close_old_connections()
    else:
        print('no console found 2')
        time.sleep(5)


def pc_power_command(console_obj: Console):
    if console_obj:
        pc_command_power = PCPowerCommand.objects.filter(
            pc__name=str(console_obj.name)
        ).exclude(
            command_status='done',
        ).last()
        if pc_command_power:
            if pc_command_power.last_command == 'sleep':
                pc_command_power.command_status = 'done'
                pc_command_power.update_time = timezone.localtime()
                pc_command_power.save(update_fields=['command_status', 'update_time'])
                # os.system('rundll32.exe powrprof.dll,SetSuspendState 0,1,0') # set pc on hibernate
                set_console_status(console=console_obj, status='PC is asleep')
                # os.system('Rundll32.exe Powrprof.dll,SetSuspendState Sleep') # set pc on sleep
                sleep_command = '''Start-Sleep -Seconds 5
                Add-Type -AssemblyName System.Windows.Forms
                [System.Windows.Forms.Application]::SetSuspendState("Suspend", $false, $false)'''
                subprocess.Popen(['powershell.exe', sleep_command])
            elif pc_command_power.last_command == 'shutdown':
                pc_command_power.command_status = 'done'
                pc_command_power.update_time = timezone.localtime()
                pc_command_power.save(update_fields=['command_status', 'update_time'])
                set_console_status(console=console_obj, status='PC Turned off')
                os.system("shutdown /s /t 1")
            else:
                print('command not found')
                time.sleep(5)
    else:
        print('no console found')
        time.sleep(5)


def check_time_difference(threshold_minutes=60, timezone_='UTC'):
    try:
        db_time = get_db_time(timezone_)

        if not isinstance(db_time, timezone.datetime):
            raise ImproperlyConfigured("Database time is not a datetime object")

        if not timezone.is_aware(db_time):
            db_time = timezone.make_aware(db_time, timezone.utc)

        system_time = timezone.datetime.now(timezone.utc)
        diff = abs((db_time - system_time).total_seconds()) / 60
        if diff > threshold_minutes:
            telegram_send_message_fifa_account(
                fifa_account=FifaAccount.objects.filter(console__name=CONSOLE_NAME).first(),
                bot_token=FIFA_REPORT_TOKEN,
                text=f'time has different {int(diff)} minutes\n console : {CONSOLE_NAME}',
                chat_id=ARZBAZI_REPORT_GROUP_ID,
                message_thread_id=ARZBAZI_REPORT_TOPIC_PC_DIFFERENT_TIME_THREAD_MESSAGE_ID,
            )
            return f"time different is {threshold_minutes}"
    except:
        print('cant check time : ', traceback.format_exc())

def set_next_console_work():
    current_console_name = console_worker_cache.get('current_console_work') or CONSOLE_NAME
    if current_console_name not in CONSOLE_NAME_LIST:
        current_console_name = str(CONSOLE_NAME)
        console_worker_cache.set('current_console_work', current_console_name)
    if len(CONSOLE_NAME_LIST) > 1:
        idx = CONSOLE_NAME_LIST.index(current_console_name)
        next_number = CONSOLE_NAME_LIST[(idx + 1) % len(CONSOLE_NAME_LIST)]
        console_worker_cache.set('next_console_work', str(next_number))
        print('next console will be , ', next_number)


def minimize_great_manager():
    window_title = "console_greate_manager"
    windows = gw.getWindowsWithTitle(window_title)
    if windows:
        win = windows[0]
        win.minimize()


minimize_great_manager()
# check_xbox_turn_on()
works_done = False
current_console_work = console_worker_cache.get('current_console_work')
next_console_work = console_worker_cache.get('next_console_work')
if next_console_work and current_console_work and next_console_work != current_console_work:
    print('change console working , current : ', current_console_work, ' next : ', next_console_work)
    current_console_work = next_console_work
    console_worker_cache.set('current_console_work', str(current_console_work))
    os.system('TASKKILL /F /IM XboxPcApp.exe /FI "USERNAME eq %username%"')
    time.sleep(5)
if len(CONSOLE_NAME_LIST) < 2 or not current_console_work:
    current_console_work = CONSOLE_NAME_LIST[0]
    console_worker_cache.set('current_console_work', str(current_console_work))
console_object = Console.objects.get(name=current_console_work)
# accounts_need_create = list(NewOutlookAccount.objects.filter(signup_status=None, console=console_object))
# create_origin_thread = None
# if console_object and accounts_need_create:
#     create_origin_thread = threading.Thread(target=create_origin)
#     create_origin_thread.start()
if console_object:
    console_power_command_thread = ThreadWithReturnValue(
        target=console_power_command,
        kwargs={'console_obj': console_object})
    console_power_command_thread.start()
dynamic_console_allowed_play_day(current_console_work)
start_get_backup_code()
if console_object and (console_object.remove_accounts or console_object.add_accounts or console_object.check_accounts):
    start_add_and_remove_accounts(console_object)
check_time_difference()
need_sbc_force_sleep = console_need_force_sleep(running_platform='console_web_pc')
if not need_sbc_force_sleep:
    start_pc_bots_result = start_pc_bots()
    os.system('TASKKILL /F /IM chrome.exe /FI "USERNAME eq %username%"')
else:
    print('now is not sbc file working time')
    time.sleep(20)

need_force_sleep = console_need_force_sleep()
console_name_list2 = CONSOLE_NAME_LIST.copy()
if not need_sbc_force_sleep:
    console_name_list2.remove(current_console_work) if current_console_work in console_name_list2 else None
if len(console_name_list2) > 1:
    set_console_list_status(console_name_list2, 'Console is asleep', update_time=False)
time.sleep(10)
# if need_force_sleep:
#     set_next_console_work()
if check_bot_version() == 'need update bot':
    print('need update bot version')
    time.sleep(20)
elif need_force_sleep:
    print(f'console work time is not now, console : {current_console_work}, sleep pc')
    set_next_console_work()
    time.sleep(20)
else:
    start_squad_manager(current_console_work)
    # dynamic_allowed_play_game(current_console_work)
    # dynamic_force_discharge(current_console_work)
    check_update_console_games(current_console_work)
    # if create_origin_thread:
    #     create_origin_thread.join()
if console_object:
    works_done = True
    pc_power_command(console_object)
    console_power_command_thread.join()

try:
    print('try to close active program')
    os.system('TASKKILL /F /IM chrome.exe /FI "USERNAME eq %username%"')
    os.system('TASKKILL /F /IM python.exe /FI "USERNAME eq %username%"')
    # time.sleep(1)
    os.system('TASKKILL /F /IM run_console_manager.exe /FI "USERNAME eq %username%"')
    os.system('TASKKILL /F /IM run_console_manager.exe /FI "USERNAME eq %username%"')
    os.system('TASKKILL /F /IM run_console_manager.exe /FI "USERNAME eq %username%"')
    os.system('TASKKILL /F /IM console_squad_manager.exe /FI "USERNAME eq %username%"')
    os.system('TASKKILL /F /IM console_squad_manager.exe /FI "USERNAME eq %username%"')
    os.system('TASKKILL /F /IM console_squad_manager.exe /FI "USERNAME eq %username%"')
except:
    print('no active python program found ...')
