import time

from django.core.cache import cache
from django.db.models import Subquery, OuterRef, Sum, IntegerField, Value, Q, F, Count
from django.db.models.functions import Coalesce
from django.utils import timezone

from accounts.models import Console, ConsoleBotSetting, FifaAccount, ConsoleLastStatus
from squad_battle.models import FifaAccountSquadGame
from sbc.models import SBCWorker, SBCType, SBCProcess
from sniper import allowed_discharge_time


def get_console_worker_logs(force_update=False, return_result=False):
    cache_name = 'console_worker_logs'
    old_logs = cache.get(cache_name)

    if old_logs and old_logs.get('update_time') > time.time() - 240 and not force_update:
        if return_result:
            return old_logs
    else:
        now_local_time = timezone.localtime()
        hours_24_ago = now_local_time - timezone.timedelta(hours=24)
        result_data = []
        query1 = Console.objects.filter(is_active=True)
        allowed_discharge_time_var = allowed_discharge_time()
        lowest_account_run_in_console_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
        query = query1.annotate(
            # console_last_24_hour_played=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
            #     fifa_account__console__id=OuterRef('pk'),
            #     create_time__gt=now_local_time - timezone.timedelta(hours=24)
            # ).values('fifa_account__console').annotate(
            #     played_count=Count('id', output_field=IntegerField())
            # ).values('played_count'), output_field=IntegerField()), Value(0)),
            console_credit=Coalesce(Subquery(FifaAccount.objects.filter(
                console__id=OuterRef('pk'),
            ).values('console').annotate(
                sum_accounts_credit=Sum('credit', output_field=IntegerField())
            ).values('sum_accounts_credit'), output_field=IntegerField()), Value(0)),
            last_accounts_worker_id=Subquery(SBCWorker.objects.exclude(
                running_platform__in=['console_web_pc', ],
                status__in=['', None]
            ).filter(
                fifa_account__console__id=OuterRef('pk'),
            ).order_by('status_change_time').values('id').reverse()[:1]),
            last_console_worker_id=Subquery(SBCWorker.objects.exclude(
                running_platform__in=['console_web_pc', ],
                status__in=['', None]
            ).filter(
                # Q(fifa_account__delete_console_reason=None) | Q(fifa_account__delete_console_reason=''),
                fifa_account__console__id=OuterRef('pk'),
                running_platform__in=['console', 'console_web_pc'],
            ).order_by('status_change_time').values('id').reverse()[:1]),
            last_active_account_worker_id=Subquery(SBCWorker.objects.exclude(
                running_platform__in=['console_web_pc', ],
                status__in=['', None]
            ).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]),
        )
        query_list = list(query)
        # query_values_list = list(query.values_list('last_active_account_worker_id', 'last_console_worker_id'))
        query_values_list = list((ii.last_active_account_worker_id, ii.last_console_worker_id) for ii in query_list)
        last_1 = []
        last_2 = []
        for item in query_values_list:
            last_1.append(item[0])
            last_2.append(item[1])
        related_quieries = list(SBCWorker.objects.filter(
            id__in=last_1
        ).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'),
            fifa_acc_any_desk_2=F('fifa_account__pc__any_desk_code_2'),
        ))
        related_quieries_2 = list(SBCWorker.objects.filter(
            id__in=last_2
        ).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'),
            fifa_acc_any_desk_2=F('fifa_account__pc__any_desk_code_2'),
        ))
        must_done_sbc_numbers = list(SBCType.objects.filter(
            console_can_use=True, must_done=1
        ).values_list('sbc_number', flat=True))
        # all_fifa_account_worked_in_24_hour = list(SBCWorker.objects.filter(
        #     Q(fifa_account__delete_console_reason=None) | Q(fifa_account__delete_console_reason='')
        # ).exclude(
        #     fifa_account__name_in_console='key'
        # ).filter(
        #     status_change_time__gt=now_local_time - timezone.timedelta(hours=24)
        # ).distinct('fifa_account__id').values_list('fifa_account__console__id', 'fifa_account__id'))
        for item in query_list:
            last_worker = None
            status_color = ''
            if item.pc_is_on is False:
                # last_worker = SBCWorker.objects.filter(
                #     fifa_account__console=item
                # ).order_by('status_change_time').last()
                # last_worker = SBCWorker.objects.select_related('fifa_account', 'fifa_account__pc').get(id=item.last_accounts_worker_id)
                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
                else:
                    for item_3 in related_quieries_2:
                        if item_3.id == item.last_console_worker_id:
                            last_worker = item_3
                            break
                status_color = 'light-green2'
                last_status = 'PC Off'
                # if item.console_last_24_hour_played >= item.allowed_play_game_day:
                #     first_play_game = FifaAccountSquadGame.objects.filter(
                #         fifa_account__console=item,
                #         create_time__gt=now_local_time - 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()
                #     hours, remainder = divmod(need_rest_time.seconds, 3600)
                #     minutes, seconds = divmod(remainder, 60)
                #     last_status += '- need rest {} H : {} M'.format(int(hours), int(minutes))
                #     # last_status += f" - need rest {':'.join(str(need_rest_time).split(':')[:2])}"
                #     status_color = 'light-green'
            elif item.last_active_account_worker_id:
                for item_2 in related_quieries:
                    if item_2.id == item.last_active_account_worker_id:
                        last_worker = item_2
                        last_status = last_worker.status
                        break
            else:
                # fifa_account_worked_in_24_hour = []
                # for nnntt in all_fifa_account_worked_in_24_hour:
                #     if nnntt[0] == item.id:
                #         fifa_account_worked_in_24_hour.append(nnntt[1])
                last_worker = SBCWorker.objects.exclude(
                    running_platform__in=['console_web_pc', ],
                    status__in=['', None]
                ).filter(
                    running_platform__in=['console', 'console_web_pc'],
                    fifa_account__console=item,
                    status_change_time__gt=hours_24_ago,
                    # fifa_account__id__in=fifa_account_worked_in_24_hour
                ).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'),
                    fifa_acc_any_desk_2=F('fifa_account__pc__any_desk_code_2'),
                ).order_by('status_change_time').last()
                if last_worker:
                    need_work_2 = FifaAccount.objects.filter(
                        console=item,
                        last_run_time__gt=hours_24_ago,
                        # id__in=fifa_account_worked_in_24_hour
                    ).annotate(
                        # can_play=Value(item.console_last_24_hour_played < item.allowed_play_game_day),
                        # last_sbc_worker_id=Coalesce(Subquery(SBCWorker.objects.filter(
                        #     running_platform='console',
                        #     fifa_account__id=OuterRef('pk')
                        # ).order_by('status_change_time').last().values('id'))),
                        # console_last_24_hour_played__lt=Value(item.allowed_play_game_day),
                        uncompleted_sbc=Value(SBCType.objects.filter(console_can_use=True, must_done=1).exclude(
                            id__in=SBCProcess.objects.filter(
                                sbc_number__in=must_done_sbc_numbers,
                                worker__fifa_account__console=item,
                                worker__status_change_time__gt=hours_24_ago,
                                is_done=True
                            ).distinct('sbc_type').values_list('sbc_type__id', flat=True)
                        ).count()),
                        account_24_played_games=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
                            fifa_account__id=OuterRef('pk'),
                            create_time__gt=hours_24_ago
                        ).values('fifa_account').annotate(
                            played_count=Count('id', output_field=IntegerField())
                        ).values('played_count'), output_field=IntegerField()), Value(0)),
                        account_31_day_played_games=Coalesce(Subquery(FifaAccountSquadGame.objects.filter(
                            fifa_account__id=OuterRef('pk'),
                            create_time__gt=now_local_time - 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)),
                    ).filter(
                        Q(last_run_time__lt=now_local_time -
                                            timezone.timedelta(hours=lowest_account_run_in_console_hour)) &
                        (((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))))
                          ) |
                         (Q(run_discharge=True) & Q(credit__gt=discharge_start_coin_greater) &
                          Q(credit__lt=discharge_start_coin_lower) & Value(allowed_discharge_time_var)) |
                         (Q(run_sbc=True) & Q(credit__gt=8000) & Q(uncompleted_sbc__gt=0)) |
                         (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))
                         )
                    ).exclude(
                        name_in_console='key'
                    ).order_by('last_run_time')
                    if need_work_2:
                        if last_worker.status_change_time < now_local_time - timezone.timedelta(minutes=5):
                            status_color = 'red'
                        else:
                            status_color = 'gray'
                        last_status = 'resting ...'
                    else:
                        # if 0 < item.allowed_play_game_day <= item.console_last_24_hour_played:
                        #     status_color = 'gray'
                        #     last_status = 'resting 3 ...'
                        # else:
                        #     status_color = 'dark-gray'
                        #     last_status = 'all account is done'
                        status_color = 'dark-gray'
                        last_status = 'all account is done'
                else:
                    last_worker = SBCWorker.objects.exclude(
                        running_platform__in=['console_web_pc', ],
                        status__in=['', None]
                    ).filter(
                        Q(fifa_account__delete_console_reason=None) | Q(fifa_account__delete_console_reason='')
                    ).exclude(
                        fifa_account__name_in_console='key'
                    ).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'),
                        fifa_acc_any_desk_2=F('fifa_account__pc__any_desk_code_2'),
                    ).filter(
                        fifa_account__console=item,
                        running_platform__in=['console', 'console_web_pc'],
                    ).order_by('status_change_time').last()
                    # last_worker = SBCWorker.objects.get(id=item.last_console_worker_id)
                    if last_worker:
                        status_color = 'dark-gray'
                        last_status = 'resting 2 ...'
                    else:
                        continue
                    # last_worker = SBCWorker.objects.last()
                    # last_status = 'Fake Status'
            if last_worker:
                a = {
                    'id': last_worker.id,
                    'console_id': item.id,
                    'status': last_status,
                    'status_change_time': last_worker.status_change_time,
                    'status_color': status_color,
                    # 'fifa_account': last_worker.fifa_account,
                    'fifa_account_id': last_worker.fifa_acc_id,
                    'fifa_account_user_name': last_worker.fifa_acc_user_name,
                    'name_in_console': f'{last_worker.fifa_acc_name_in_console} - {last_worker.fifa_acc_platform}',
                    'console_name': item.name,
                    'any_desk': last_worker.fifa_acc_any_desk,
                    'any_desk_2': last_worker.fifa_acc_any_desk_2,
                    'description': last_worker.description,
                    'console_credit': item.console_credit,
                }
            else:
                continue

            result_data.append(a)
        new_status = list(ConsoleLastStatus.objects.filter(console__in=query1).select_related(
            'fifa_account', 'fifa_account__pc', 'console', 'sbc_worker'
        ))
        for worker_status in result_data:
            for ittt in new_status:
                if ittt.console.id == worker_status.get('console_id'):
                    if ittt.status_change_time > worker_status.get('status_change_time'):
                        # todo : remove this if
                        if not ittt.sbc_worker:
                            break
                        worker_update_dict = {
                            'id': ittt.sbc_worker.id,
                            'console_id': ittt.console.id,
                            'name_in_console': f'{ittt.fifa_account.name_in_console} - {ittt.fifa_account.platform}',
                            'console_name': ittt.console.name,
                            'any_desk': ittt.fifa_account.pc.any_desk_code,
                            'any_desk_2': ittt.fifa_account.pc.any_desk_code_2,
                            'status_change_time': ittt.status_change_time,
                            'fifa_account_id': ittt.fifa_account.id,
                            'fifa_account_user_name': ittt.fifa_account.user_name,
                            'status': ittt.status,
                        }
                        if ittt.status == 'PC Turned off':
                            worker_update_dict.update({
                                'status_color': 'light-green2',
                            })
                        worker_status.update(worker_update_dict)
                    break
        save_data = {'update_time': time.time(), 'data': result_data}
        cache.set(cache_name, save_data, timeout=600)
        if return_result:
            return save_data