import subprocess
import time
import traceback

from django.db.models import Q
from django.utils import timezone

from accounts import ELECTRIC_NODE_CYCLE_START_TIME
from accounts.models import Console, ConsoleWorkTime, FifaAccount, ConsoleWorkTimeLimitLog
from futplus.settings import CONSOLE_NAME, TIME_ZONE, CONSOLE_NAME_LIST
from sbc.models import SBCWorker, SBCFileWorkTime
from sbc.public_methods import set_console_status, console_worker_cache
from utils.realy_public_methods import get_db_time, new_print


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 is_node_active(start_hour, end_hour, now=None):
    work_hours_box = 48
    if now is None:
        now = timezone.localtime()
    elif timezone.is_naive(now):
        now = timezone.make_aware(now)

    delta = now - ELECTRIC_NODE_CYCLE_START_TIME
    seconds_in_cycle = work_hours_box * 3600
    position_in_cycle = (delta.total_seconds() % seconds_in_cycle) / 3600  # current hour in cycle

    start = start_hour % work_hours_box
    end = end_hour % work_hours_box

    if start < end:
        return start <= position_in_cycle < end
    else:
        return position_in_cycle >= start or position_in_cycle < end


def console_need_force_sleep(running_platform='console'):
    try:
        local_time = get_db_time(timezone_=TIME_ZONE)
    except:
        print('cant get local_time from server , ', traceback.format_exc())
        local_time = timezone.localtime()
    current_console_work_name = console_worker_cache.get('current_console_work')
    console = Console.objects.filter(name=current_console_work_name).last()
    if not console:
        return False
    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')

    first_account = sane_console_fifa_accounts.first()

    if running_platform == 'console_web_pc':
        console_work_list = SBCFileWorkTime.objects.filter(
            console__name__in=CONSOLE_NAME_LIST
        ).values('start_time', 'end_time')
        if (console.turn_off_after_work and console_work_list and
                (not is_within_work_hours(local_time, console_work_list))):
            sleep_text = (f'SBC file work time out of range 3 , current time : {local_time} ,'
                          f' logs in {first_account}')
            print(sleep_text)
            if first_account:
                new_print(first_account, sleep_text)
            return True
        return False
    else:
        console_work_list = ConsoleWorkTime.objects.filter(
            console__name=current_console_work_name
        ).values('start_time', 'end_time')

        # last_console_worker = SBCWorker.objects.filter(
        #     fifa_account__console=console, running_platform='console'
        # ).order_by('create_time').last()
        # if console.turn_off_after_work and running_platform == 'console_web_pc':
        #     if last_console_worker and last_console_worker.status_change_time > timezone.localtime() - timezone.timedelta(hours=2):
        #         sleep_text = (f'work time out of range 3 , current time : {local_time} ,'
        #                       f' logs in {first_account}')
        #         print(sleep_text)
        #         if first_account:
        #             new_print(first_account, sleep_text)
        #         return True
        #     return False
        if console.electric_node and not is_node_active(
                console.electric_node.start_hour, console.electric_node.end_hour, local_time):
            sleep_text = (f'same pc work not in work time , current time : {local_time} ,'
                          f' work list : {console.electric_node.start_hour} , {console.electric_node.end_hour} ,'
                          f' logs in {first_account}')
            print(sleep_text)
            if first_account:
                new_print(first_account, sleep_text)
            # ConsoleWorkTimeLimitLog.objects.create(console=console)
            # set_console_status(console=console, status='Console is asleep', update_time=False)
            time.sleep(1)
            return True
        if (console.turn_off_after_work and console_work_list and
                (not is_within_work_hours(local_time, console_work_list))):
            sleep_text = f'work time out of range 2 , current time : {local_time} , work list : {console_work_list} , logs in {first_account}'
            print(sleep_text)
            if first_account:
                new_print(first_account, sleep_text)
            ConsoleWorkTimeLimitLog.objects.create(console=console)
            set_console_status(console=console, status='PC is asleep')
            time.sleep(1)
            if len(CONSOLE_NAME_LIST) > 1:
                return True
            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])
            time.sleep(5)
            return True
