import os
import time
import traceback

import cv2
from django.db import close_old_connections

from futplus.settings import BASE_DIR, CONSOLE_NAME_LIST
from sbc.public_methods import new_print, set_sbc_status, has_image
from utils.graph_core import xbox360_graph, ps4_graph, Menu


class MenuUtils:
    def __init__(self, public_moves_instance):
        from utils.public_moves import PublicMoves
        self.public_moves: PublicMoves = public_moves_instance
        self.fifa_account = self.public_moves.fifa_account
        self.sbc_worker = self.public_moves.sbc_worker
        self.ps4_buttons = self.public_moves.ps4_buttons

    def get_all_menus(self, menu, menus=None):
        if menus is None:
            if self.fifa_account.platform in ['xbox360', 'xboxs']:
                menus = [xbox360_graph]
            else:
                menus = [ps4_graph]
        for item in menu.nodes:
            # new_print(self.fifa_account,item.name)
            if item not in menus:
                menus.append(item)
                self.get_all_menus(item, menus=menus)
        return menus

    def select_menu_items_by_name(self, item_name) -> Menu:
        for item in self.public_moves.menus:
            if item.name == item_name:
                return item

    def make_menu_dict(self, menu):
        list_1 = []
        for item in menu:
            if item.nodes:
                list_2 = []
                for node in item.nodes:
                    list_2.append(node.name)
                list_1.append({'name': item.name, 'nodes': list_2, 'specials': item.specials})
        return list_1

    def load_all_templates(self):
        """همه تصاویر مرجع را یک بار لود می‌کند و در حافظه نگه می‌دارد"""
        for menu in self.public_moves.menus:
            self._load_menu_images(menu)

    def _load_menu_images(self, menu):
        # مسیر تصویر اصلی منو
        img_path = os.path.join(BASE_DIR, f'utils/{self.fifa_account.platform}_controls/{menu.name}.png')
        if os.path.exists(img_path):
            self.public_moves.image_cache[menu.name] = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)

        # بارگذاری تصاویر multiple_images
        for image_item in menu.multiple_images:
            img_path = os.path.join(BASE_DIR, f'utils/{self.fifa_account.platform}_controls/{image_item.file_name}.png')
            if os.path.exists(img_path):
                self.public_moves.image_cache[image_item.file_name] = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)

        # بازگشتی برای زیرمنوها
        for sub_menu in menu.nodes:
            self._load_menu_images(sub_menu)

    # function to find path
    def find_path(self, graph, start, end, path=None, node_index=-1):
        if path is None:
            path = []
        if start not in path:
            path = path + [start]
        if node_index != -1:
            path += [node_index]
        if start == end:
            return path
        index = -1
        for child in graph:
            if child['name'] == start:
                index = graph.index(child)
        if index != -1:
            for node in graph[index]['nodes']:
                # new_print(self.fifa_account,'node = ',node)
                # new_print(self.fifa_account,'graph = ',graph[index])
                # if node not in path:
                node_index = graph[index]['nodes'].index(node)
                newpath = self.find_path(graph, node, end, path, node_index)
                if newpath:
                    return newpath
                # return None

    def get_path(self, graph, start, end):
        len_find_path = 0
        temp_start = start
        path = []
        while True:
            temp_path = self.find_path(graph, temp_start, end)
            try:
                if len(temp_path) == 1:
                    return path
            except:
                pass
            if temp_path:
                path.append([temp_start, temp_path[1], 'in', temp_path[2]])
                temp_start = temp_path[1]
            else:
                node_index = -1
                parent = ''
                parent_specials = None
                parent_nodes = []
                for menu in graph:
                    for node in menu['nodes']:
                        if node == temp_start:
                            parent_nodes = menu['nodes']
                            node_index = menu['nodes'].index(node)
                            parent = menu['name']
                            parent_specials = menu.get('specials')
                if node_index == -1:
                    new_print(self.fifa_account, 'path:', temp_start, end, ' -- no path found')
                    # new_print(self.fifa_account, 'no path found')
                    return ''
                if 'dont_need_enter' in parent_specials and start in parent_nodes and end in parent_nodes and start != end:
                    if parent_nodes.index(start) < parent_nodes.index(end):
                        moves_need = parent_nodes.index(end) - parent_nodes.index(start)
                        path.append([temp_start, end, 'right', moves_need])
                        temp_start = end
                    elif parent_nodes.index(start) > parent_nodes.index(end):
                        moves_need = parent_nodes.index(start) - parent_nodes.index(end)
                        path.append([temp_start, end, 'left', moves_need])
                        temp_start = end
                else:
                    path.append([temp_start, parent, 'out', node_index])
                    temp_start = parent


    def fix_path(self, the_path):
        return the_path
        count = 0
        new_path = []
        while count < len(the_path):
            if the_path[count]:
                must_insert = 1
                if the_path[count][2] == 'out':
                    if count + 1 < len(the_path):
                        if the_path[count + 1][2] == 'in':
                            if the_path[count][3] > the_path[count + 1][3]:
                                new_path.append([the_path[count][0], the_path[count + 1][1], 'left',
                                                 the_path[count][3] - the_path[count + 1][3]])
                            else:
                                new_path.append([the_path[count][0], the_path[count + 1][1], 'right',
                                                 the_path[count + 1][3] - the_path[count][3]])
                            must_insert = 0
                            count += 1
                if must_insert:
                    new_path.append(the_path[count])
            count += 1
        return new_path

    def map_path(self, graph, start, end):
        the_path = self.get_path(graph, start, end)
        # new_print(self.fifa_account, 'the path = ', the_path)
        fixed_path = self.fix_path(the_path)
        new_print(self.fifa_account, 'the path = ', the_path, ' -- fixed path = ', fixed_path,
                  ' start = ', start, ' end = ', end)
        return fixed_path

    def control_state(self, state):
        self.public_moves.screen_utils.get_screen_shot()
        if os.path.exists(os.path.join(BASE_DIR, f'utils/{self.fifa_account.platform}_controls/{state}.png')):
            if self.public_moves.has_image(
                    os.path.join(BASE_DIR, f'utils/{self.fifa_account.platform}_controls/{state}.png'),
                    'screen_shot_tmp.jpg', threshold=.9):
                return True

            new_print(self.fifa_account, 'state control failed')
            return False
        else:
            return True

    def just_find_state(self, get_new_screen_shot=True):
        """تشخیص صفحه فعلی با استفاده از MenuImage، ROI و threshold"""
        if get_new_screen_shot:
            self.public_moves.screen_utils.get_screen_shot()

        # خواندن تصویر اصلی و تبدیل به grayscale
        frame = cv2.imread('screen_shot_tmp.jpg')
        gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        # پیمایش تمام منوها
        for menu in self.public_moves.menus:
            if 'dont_need_enter' in menu.specials:
                continue

            # # بررسی عکس اصلی منو (اگه داخل کش هست)
            # if menu.name in self.public_moves.image_cache:
            #     menu_image = self.public_moves.image_cache[menu.name]
            #     roi = menu_image.roi if menu_image.roi else None
            #     ref_image = menu_image
            #     threshold = menu_image.threshold if menu_image.threshold else 0.9
            #
            #     # برش فریم در صورت داشتن ROI
            #     frame_to_check = gray_frame
            #     if roi:
            #         y1, y2, x1, x2 = roi
            #         frame_to_check = gray_frame[y1:y2, x1:x2]
            #
            #     if self.public_moves.screen_utils.has_image_2(ref_image,frame_to_check,threshold):
            #         return menu.name

            # بررسی multiple_images برای هر منو
            for image_item in menu.multiple_images:
                # image_item حالا یک آبجکت MenuImage است
                if image_item.file_name in self.public_moves.image_cache:
                    ref_image = self.public_moves.image_cache[image_item.file_name]
                    roi = image_item.roi if image_item.roi else None
                    threshold = image_item.threshold if image_item.threshold else 0.9

                    # برش فریم در صورت داشتن ROI
                    frame_to_check = gray_frame
                    if roi:
                        y1, y2, x1, x2 = roi
                        frame_to_check = gray_frame[y1:y2, x1:x2]

                    if self.public_moves.screen_utils.has_image_2(ref_image, frame_to_check, threshold):
                        return menu.name

        return False

    # def just_find_state(self, get_new_screen_shot=True):
    #     if get_new_screen_shot:
    #         self.public_moves.screen_utils.get_screen_shot()
    #     for menu in self.public_moves.menus:
    #         if os.path.exists(os.path.join(BASE_DIR, f'utils/{self.fifa_account.platform}_controls/{menu.name}.png')):
    #             # new_print(self.fifa_account,'menu.name = ',menu.name)
    #             # if (not 'use_r1_and_l1' in menu.specials) and self.public_moves.has_image(os.path.join(
    #             if (not 'dont_need_enter' in menu.specials) and self.public_moves.has_image(os.path.join(
    #                     BASE_DIR,
    #                     f'utils/{self.fifa_account.platform}_controls/{menu.name}.png'),
    #                     'screen_shot_tmp.jpg'):
    #                 return menu.name
    #         for image_item in menu.multiple_images:
    #             # if (not 'use_r1_and_l1' in menu.specials) and self.public_moves.has_image(os.path.join(
    #             if (not 'dont_need_enter' in menu.specials) and self.public_moves.has_image(os.path.join(
    #                     BASE_DIR,
    #                     f'utils/{self.fifa_account.platform}_controls/{image_item}.png'),
    #                     'screen_shot_tmp.jpg'):
    #                 return menu.name
    #     return False

    def find_menu_icon(self, need_right_left, specials, tag, multiple_images=None, use_r1_and_l1=False,
                       use_up_and_down=False):
        # this function created just for find_1 and find_2 specials . don't work for other specials
        if multiple_images is None:
            multiple_images = []
        new_print(self.fifa_account, 'find menu icon', specials, ' tag : ', tag,
                  ' multiple_images : ', multiple_images)
        for special in specials:
            # find_1 and find_2 controlls by bellow lin , just this one line.
            if special.find(tag) != -1:
                need_right_left = 0
                pic = special.split()[1]
                if len(special.split()) > 2:
                    threshold = float(special.split()[2])
                else:
                    threshold = 0.7
                    if self.fifa_account.platform in ['xboxs', 'xbox360']:
                        threshold = 0.85
                temp_count = 0
                time.sleep(1)
                use_up_and_down_arrow = 'down'
                while True:
                    continue_error = False
                    if pic == 'fifa_22':
                        self.public_moves.get_screen_shot()
                        self.public_moves.transfer_list_utils.get_transfer_list_cards_position()
                        time.sleep(2)
                        new_print(self.fifa_account, 'finding game info , press square')
                        self.ps4_buttons.square()
                        time.sleep(5)
                        self.ps4_buttons.square()  # Just to be sure work done
                        time.sleep(5)
                        self.public_moves.get_screen_shot()
                        if self.public_moves.has_image(
                                'transfer_list_cards_tmp.jpg', 'screen_shot_tmp.jpg', threshold=0.9
                        ) and temp_count > 0:
                            new_print(self.fifa_account, 'finding game info press square not work , press cross')
                            self.ps4_buttons.cross()
                            time.sleep(5)
                        # self.ps4_buttons.option()
                        # time.sleep(5)
                        # if self.public_moves.has_image(os.path.join(
                        #         BASE_DIR, f'utils/xbox_public/game_options_ea_sports.png'),
                        #         'screen_shot_tmp.jpg', threshold=threshold):
                        #     new_print(self.fifa_account, 'find game info , fifa_22_ea_sports found')
                        #     if self.public_moves.has_image(os.path.join(
                        #         BASE_DIR, f'utils/xbox_public/game_option_game_card.png'),
                        #             'screen_shot_tmp.jpg', threshold=threshold):
                        #         new_print(self.fifa_account, 'find game info , game_option_game_card found')
                        #         self.ps4_buttons.cross()
                        #         time.sleep(5)
                        #     else:
                        #         new_print(self.fifa_account, 'find game info , game_option_game_card not found')
                        #         self.ps4_buttons.circle()
                        #         time.sleep(5)
                        #         self.ps4_buttons.cross()
                        #         time.sleep(5)
                        # else:
                        #     self.ps4_buttons.circle()
                        #     time.sleep(5)
                        #     new_print(self.fifa_account, 'find game info , fifa_22_ea_sports not found')
                        #     self.ps4_buttons.square()
                        #     time.sleep(5)
                    self.public_moves.get_screen_shot()
                    # if pic == 'fifa_22' and (not self.public_moves.has_image(os.path.join(
                    #             BASE_DIR, f'utils/{self.fifa_account.platform}_controls/double_game_exists.png'),
                    #             'screen_shot_tmp.jpg', threshold=threshold) and not self.public_moves.has_image(os.path.join(
                    #     BASE_DIR, f'utils/{self.fifa_account.platform}_controls/double_game_exists_2.png'),
                    #             'screen_shot_tmp.jpg', threshold=threshold)):
                    #     continue_error = True
                    # new_print(self.fifa_account,'special pic address = ',os.path.join(BASE_DIR, f'utils/controls/{pic}.png'))
                    # print(pic,' use_r1_and_l1 : ', use_r1_and_l1, ' special : ', special)
                    if self.public_moves.has_image(
                            os.path.join(BASE_DIR, f'utils/{self.fifa_account.platform}_controls/{pic}.png'),
                            'screen_shot_tmp.jpg', threshold=threshold) and not continue_error:
                        if pic == 'fifa_22' and self.public_moves.has_image(
                            os.path.join(BASE_DIR, f'utils/{self.fifa_account.platform}_controls/view_in_queue.png'),
                            'screen_shot_tmp.jpg', threshold=threshold):
                            set_sbc_status(self.sbc_worker, 'game update need')
                            new_print(self.fifa_account, 'game update need')
                            self.ps4_buttons.cross()
                            time.sleep(2)
                            self.public_moves.get_screen_shot()
                            if self.public_moves.has_image(os.path.join(
                                    BASE_DIR, f'utils/{self.fifa_account.platform}_controls/resume_update_games_all.png'),
                                    'screen_shot_tmp.jpg', threshold=threshold):
                                new_print(self.fifa_account, 'resume update games found , press cross')
                                self.ps4_buttons.cross()
                                time.sleep(5)
                                # press two down to insure not going on other game
                                self.ps4_buttons.down()
                                time.sleep(1)
                                self.ps4_buttons.down()
                                time.sleep(1)
                            # press two down to insure not going on other game
                            self.ps4_buttons.down()
                            time.sleep(1)
                            self.ps4_buttons.down()
                            time.sleep(1)
                            self.ps4_buttons.ps()
                            time.sleep(1)
                            self.ps4_buttons.cross()
                            time.sleep(10)
                            if self.just_find_state() != 'ps4_main':
                                new_print(
                                    self.fifa_account,
                                    'bugs hapend , its must go to main menu but not goes , press two circle',
                                    ' state ', self.just_find_state()
                                )
                                self.ps4_buttons.circle()
                                time.sleep(1)
                                self.ps4_buttons.circle()
                                time.sleep(1)
                            # self.ps4_buttons.circle()
                            # time.sleep(2)
                            # self.ps4_buttons.option()
                            # time.sleep(1)
                            # for nnn in range(10):
                            #     self.ps4_buttons.down()
                            #     time.sleep(1)
                            #     self.public_moves.get_screen_shot()
                            #     if self.public_moves.has_image(os.path.join(
                            #             BASE_DIR, f'utils/{self.fifa_account.platform}_controls/resume_updating.png'),
                            #             'screen_shot_tmp.jpg', threshold=threshold):
                            #         self.ps4_buttons.cross()
                            #         break
                            new_print(self.fifa_account, 'waiting in main page for 600 sec to download done.')
                            for iiee in range(10):
                                time.sleep(60)
                                self.ps4_buttons.right()
                                time.sleep(5)
                                self.ps4_buttons.left()
                                time.sleep(5)
                            # self.ps4_buttons.circle()
                            # time.sleep(2)
                            # self.ps4_buttons.circle()
                            raise Exception('game update need')
                        break
                    # special check images for fifa open game
                    # find_multiple_image = False
                    # for image_item in multiple_images:
                    #     if self.public_moves.has_image(os.path.join(
                    #             BASE_DIR, f'utils/{self.fifa_account.platform}_controls/{image_item}.png'),
                    #             'screen_shot_tmp.jpg', threshold=threshold) and not continue_error:
                    #         find_multiple_image = True
                    #         # new_print(self.fifa_account, 'ok i find ', image_item)
                    #         break
                    # todo : uncomment bellow and check it for every menu
                    # if find_multiple_image:
                    # if find_multiple_image and pic == 'fifa_22':
                    #     break
                    elif pic == 'fifa_22' and (self.public_moves.has_image(os.path.join(
                            BASE_DIR, f'utils/{self.fifa_account.platform}_controls/fifa_22_ea_sports.png'),
                            'screen_shot_tmp.jpg', threshold=threshold) or self.public_moves.has_image(os.path.join(
                                BASE_DIR, f'utils/xbox_public/game_options_ea_sports.png'),
                                'screen_shot_tmp.jpg', threshold=threshold)):
                        self.ps4_buttons.circle()
                        time.sleep(1)
                    elif pic == 'fifa_22':
                        if temp_count % 5 == 0 and not self.just_find_state():
                            self.ps4_buttons.circle()
                            time.sleep(1)
                        elif temp_count > 20:
                            break
                    temp_count += 1
                    if temp_count % 15 == 0:
                        threshold -= 0.1
                        new_print(self.fifa_account, 'will reduce threshold. new threshold = ', threshold)
                        if use_up_and_down_arrow == 'up':
                            use_up_and_down_arrow = 'down'
                        else:
                            use_up_and_down_arrow = 'up'
                    if temp_count > 45:
                        break
                    if use_r1_and_l1:
                        self.ps4_buttons.r1()
                    elif use_up_and_down:
                        if use_up_and_down_arrow == 'down':
                            self.ps4_buttons.down()
                            time.sleep(2)
                        else:
                            self.ps4_buttons.up()
                            time.sleep(2)
                        if pic == 'ultimate_active':
                            self.ps4_buttons.right()
                            # todo : remove bellow sleep after birthday event
                            time.sleep(2)
                    else:
                        self.ps4_buttons.right()
                    time.sleep(1)
        return need_right_left

    def find_state(self, ):
        while True:
            self.public_moves.get_screen_shot()
            if self.public_moves.errors():
                pass
            else:
                break

        # if not found
        count = 0
        while True:
            state = self.just_find_state()
            if state:
                new_print(self.fifa_account, 'find_state , current : ', state)
                return state
            self.public_moves.errors()
            # self.public_moves.get_screen_shot(image_name='temp.jpg')
            new_print(self.fifa_account, 'need to press circle')
            self.ps4_buttons.circle()
            time.sleep(1)
            # self.public_moves.get_screen_shot()
            # if self.public_moves.has_image("temp.jpg", "screen_shot_tmp.jpg",threshold=0.8):
            if (count + 1) % 3 == 0:
                new_print(self.fifa_account, 'need to press cross')
                self.ps4_buttons.cross()
                time.sleep(1)
            count += 1
            new_print(self.fifa_account, 'find state count =', count)
            if count == 25 and self.fifa_account.credit == 0:
                new_print(self.fifa_account, 'in 25 try and 0 credit , press option , to check ')
                self.ps4_buttons.option()
                time.sleep(2)
            if count == 29:
                new_print(self.fifa_account, 'in 29 try , press ps and cross')
                self.ps4_buttons.ps()
                time.sleep(2)
                self.ps4_buttons.cross()
                time.sleep(5)
            if count == 40:
                new_print(self.fifa_account, 'trying in 40 try , close xbox friends window')
                try:
                    import pygetwindow as gw
                    wins = gw.getWindowsWithTitle('Xbox')
                    for win in wins:
                        if win.title == 'Friends ‎- Xbox':
                            new_print(self.fifa_account, 'closing xbox friends window')
                            win.close()
                            break
                except:
                    new_print(self.fifa_account, 'error on close xbox friends window : ', traceback.format_exc())
                self.ps4_buttons.circle()
                time.sleep(2)
                self.public_moves.get_screen_shot()
                if self.public_moves.has_image(
                    os.path.join(BASE_DIR, f'utils/xbox_public/remote_my_libarary.png'),
                    'screen_shot_tmp.jpg') and self.public_moves.has_image(
                    os.path.join(BASE_DIR, f'utils/xbox_public/cloud_gaming_icon.png'),
                    'screen_shot_tmp.jpg'):
                    new_print(self.fifa_account, 'seems account is out of remote play , try to open app')
                    open_xbox_app = self.public_moves.console_login_utils.xboxs_go_to_app()
                    if open_xbox_app and open_xbox_app.get('status_bool') is True:
                        new_print(self.fifa_account, 'xbox app opened so need to login to account')
                        if len(CONSOLE_NAME_LIST) > 1:
                            self.public_moves.console_login_utils.login_with_start()
                            time.sleep(5)
                        self.public_moves.console_login_utils.login_to_account()
            if count > 45:
                new_print(self.fifa_account,
                          'I cant find my way at all. I will put console on rest mode and reopen ps remote play')
                self.public_moves.console_login_utils.put_on_rest_mode()
                # self.console_open_ultimate(have_to=True)
                self.sbc_worker.refresh_from_db()
                self.sbc_worker.must_done = True
                self.sbc_worker.save()
                raise Exception('can not find way')