# -*- coding:utf-8 -*-
#
# Author:jing
# Date: 2020/6/4
from dataclasses import dataclass
from typing import Dict, Tuple

from pot_libs.common.components.electric import Electric
from pot_libs.sanic_api import Model
from pot_libs.sanic_api.column import Opt, Int
from unify_api.modules.uassistant.components.assistant import Conclusion, \
    Result, normalize, delta


class Conclusions(object):
    def __init__(self):
        self.conclusions: Dict[Tuple, Conclusion] = {}

    def check(self, result: Result):
        if result.result in self.conclusions:
            self.conclusions[result.result].check(result)
        else:
            self.conclusions[result.result] = Conclusion(
                left=result.degree,
                right=result.degree,
                result=result.result,
                opt_degree=result.degree,
                opt_degrees=result.degrees
            )


@dataclass
class Graph(Model):
    ua: int = Int()
    ub: int = Int()
    uc: int = Int()
    ia: int = Int()
    ib: int = Opt(Int())
    ic: int = Int()

    def rotate(self, degree):
        return Graph(
            ua=self.ua - degree,
            ub=self.ub - degree,
            uc=self.uc - degree,
            ia=self.ia,
            ib=self.ib,
            ic=self.ic,
        )

    def _get_best(self, degree):
        mapper = {
            'A': self.ua,
            'B': self.ub,
            'C': self.uc,
            '-A': normalize(self.ua + 180),
            '-B': normalize(self.ub + 180),
            '-C': normalize(self.uc + 180)
        }
        best = None
        min_d = None
        for i, ud in mapper.items():
            diff = delta(degree, ud)
            if min_d is None or diff < min_d:
                min_d = diff
                best = i
        return best, min_d

    def opt(self, rotated_degree):
        best_a, min_a = self._get_best(self.ia)
        best_c, min_c = self._get_best(self.ic)
        if self.ib > -9000:
            best_b, min_b = self._get_best(self.ib)
            result = Result(result=(best_a, best_b, best_c),
                            degree=rotated_degree,
                            degrees=(min_a, min_b, min_c))
        else:
            result = Result(result=(best_a, best_c), degree=rotated_degree,
                            degrees=(min_a, min_c))
            return result
        print(self, result)
        return result


def get_graph(electric: Electric):
    ua = 0
    if electric.ctnum == 3:
        ub = -electric.angleAB
        uc = -electric.angleAC
        ia = ua - electric.phA
        ib = ub - electric.phB
        ic = uc - electric.phC
    else:
        sign = 1 if electric.angleUabUcb > 0 else -1
        ub = 120 * sign
        uc = -120 * sign
        ia = 30 - electric.phUabIa
        ib = -9999
        ic = 90 - electric.phUcbIc

    return Graph(**{
        k: int(round(v)) for k, v in
        dict(ua=ua, ub=ub, uc=uc, ia=ia, ib=ib, ic=ic).items()
    })


def calc_result(electric: Electric):
    graph = get_graph(electric)
    conclusions = Conclusions()
    for a in range(-89, 90):
        cur = graph.rotate(a)
        result = cur.opt(a)
        conclusions.check(result)
    return [
        _ for _ in conclusions.conclusions.values()
        if sum(_.opt_degrees) < 70
    ]
