from datetime import datetime, timedelta

import cv2

from mower.data import agent_list
from mower.utils import config
from mower.utils import typealias as tp
from mower.utils.character_recognize import match_portrait
from mower.utils.graph import SceneGraphSolver
from mower.utils.image import cropimg, loadres, thres2
from mower.utils.log import logger
from mower.utils.recognize import Scene
from mower.utils.vector import ss, va

from .utils import generate_image, translate

agent = ["无需增调干员", "先锋", "近卫", "重装", "术士", "狙击", "医疗", "辅助", "特种"]


class SSSDROPSolver(SceneGraphSolver):
    def run(self, drops: list, blacklist: list = []) -> bool:
        self.drops = drops
        self.choose = False
        self.blacklist = set(blacklist)
        self.transelate_name()
        self.success = True
        self.start_time = datetime.now()
        super().run()
        return self.success

    def timeout(self) -> bool:
        return datetime.now() > self.start_time + timedelta(seconds=20)

    def transelate_name(self):
        for i in range(len(self.drops)):
            if self.drops[i] in translate:
                self.drops[i] = translate[self.drops[i]]

    def find_EC(self, drop: str, fs: int, scope: tp.Scope):
        img = cropimg(config.recog.gray, scope)
        res = generate_image(drop, fs)
        result = cv2.matchTemplate(img, res, cv2.TM_CCOEFF_NORMED)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
        h, w = res.shape
        logger.debug(f"drop:{drop},max_val:{max_val}")
        if max_val > 0.8:
            return va((max_loc[0], max_loc[1]), scope[0])

    def find_PR_in_fight(self, drop: str, scope: tp.Scope):
        img = cropimg(config.recog.img, scope)
        res = loadres(f"sss/drop/{drop}")
        res = cv2.resize(res, (61, 61), interpolation=cv2.INTER_LINEAR)
        result = cv2.matchTemplate(img, res, cv2.TM_CCOEFF_NORMED)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
        h, w, _ = res.shape
        logger.debug(f"drop:{drop},max_val:{max_val}")
        if max_val > 0.8:
            return va((max_loc[0], max_loc[1]), scope[0])

    def match_operators(self):
        img = cropimg(config.recog.gray, ((50, 231), (1900, 850)))
        img = thres2(img, 38)
        contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        rect = filter(
            lambda x: x[2] > 200, map(lambda c: cv2.boundingRect(c), contours)
        )
        segment = []
        for x, y, w, h in rect:
            top_left = va((x, y), (50, 350))
            bottom_right = va((x + w + 50, y + h + 231), (0, -230))
            segment.append(ss(2 / 3, 2 / 3, (top_left, bottom_right)))
        match_opers = dict(
            match_portrait(
                cv2.resize(config.recog.gray, (int(1920 / 1.5), int(1080 / 1.5))),
                segment=segment,
            )
        )
        logger.info(match_opers.keys())
        res = {}
        for name, scope in match_opers.items():
            if name and name not in self.blacklist:
                res[translate[agent_list[name]["profession"]]] = self.get_pos(
                    ss(1.5, 1.5, scope)
                )
        logger.info(f"不在黑名单的干员:{res}")
        return res

    def transition(self):
        if (scene := self.scene()) == Scene.SSS_DROP_AGENT_BEFORE_FIGHT:
            if self.timeout():
                self.success = False
                return True
            if self.choose and (
                self.find("sss/drop_check") or self.find("sss/no_drop_check")
            ):
                self.tap((1794, 900))
                self.choose = False
                self.sleep(2)
                return
            else:
                opers = self.match_operators()
                if pos := self.find("sss/drop/无需增调干员"):
                    opers["无需增调干员"] = pos

                for drop in self.drops:
                    if drop in opers:
                        self.tap(opers[drop])
                        self.sleep(0.5)
                        self.choose = True
                        return
                if len(opers):
                    self.tap(opers.popitem()[1])
                    self.sleep(0.5)
                    self.choose = True
                    return

        elif scene == Scene.SSS_DROP_IN_FIGHT:
            for drop in self.drops:
                if drop not in agent:
                    if pos := self.find_EC(drop, 29, ((510, 700), (1480, 770))):
                        self.tap(pos)
                        self.sleep(0.5)
                        self.tap((1750, 550))
                        return
                else:
                    if pos := self.find_PR_in_fight(drop, ((468, 735), (1321, 797))):
                        self.tap(pos)
                        self.sleep(0.5)
                        self.tap((1750, 550))
                        return
            self.tap_element("sss/abandon")

        elif scene == Scene.SSS_DROP_EC_BEFORE_FIGHT:
            if self.timeout():
                self.success = False
                return True
            if self.choose and self.find("sss/drop_check"):
                self.tap((1794, 900))
                return
            else:
                for drop in self.drops:
                    if drop not in agent:
                        if pos := self.find_EC(drop, 30, ((640, 630), (1280, 700))):
                            self.tap(pos)
                            self.sleep(0.5)
                            self.choose = True
                            return

        elif scene == Scene.SSS_ABANDON_DROP_IN_FIGHT:
            self.scene_graph_step(Scene.OPERATOR_FIGHT)

        elif scene in [Scene.OPERATOR_FIGHT, Scene.SSS_ACTION]:
            return True

        elif scene in self.waiting_scene:
            self.waiting_solver()

        else:
            return True
