from src.uml.request_generator import Request


class UMLCreator:
    # TODO: в методах, обремененных некой логикой, постоянно встречается проверка режима if not self.theor_mode.
    #  Есть предложение реализовать паттерн СТРАТЕГИЯ, который в зависимости от режима делал бы что-то
    #  разными способами. Это бы помогло избавиться от спагетти и обособить логику работы в зависимости от ситуации.
    def __init__(self, request_generator: Request, path_to_save: str):
        self._request_generator = request_generator
        self.path_to_save = path_to_save


    def _build_data(self):
        real_data = []
        ideal_data = []
        if not self.theor_mode:
            # TODO: Писать так условия - моветон. Как вариант, можно применить конструкцию match - case.
            for key, items in self.timings_dict.items():
                if key == 'closure': ideal_time = self._ideal_time[0]
                elif key == 'compression': ideal_time = self._ideal_time[1]
                elif key == 'welding': ideal_time = self.WeldTime
                elif key == 'opening': ideal_time = self._ideal_time[2]
                
                for item in items:
                    real_data.append([item[0]*self.scaler+0.0001, str(key) + '#green'])
                    real_data.append([item[1]*self.scaler, '{-}'])

                    if key == 'compression':
                        # TODO: Дублирование проверки значения ключа. Можно объединить проверки вверху и тут
                        #  в одном match - case выражении:
                        #  match key:
                        #       case "compression":
                        #           ...
                        #       case "opening":
                        #           ...
                        #       case _:
                        #           ...
                        ideal_data.append([(item[1]-ideal_time)*self.scaler, str(key) + '#yellow'])
                        ideal_data.append([(item[1]-0.0001)*self.scaler, '{-}'])
                    else:
                        ideal_data.append([item[0]*self.scaler+0.0001, str(key) + '#yellow'])
                        ideal_data.append([(item[0]+ideal_time)*self.scaler, '{-}'])
                        if key == 'opening':
                            ideal_data.append([item[1]*self.scaler+0.0001, 'coming #yellow'])
                            # TODO: elif key == 'opening': ideal_time = self._ideal_time[2]. Почему здесь при условии
                            #  значения ключа opening уже self._ideal_time[3]?
                            ideal_data.append([(item[1]+self._ideal_time[3])*self.scaler, '{-}'])

        else:
            # TODO: real_data уже определена как [] в самом начале. Если не попадаем в верхнее условие,
            #  то она таковой и останется. Дублирование.
            real_data = []
            # TODO: Похоже, что все данные в этом списке - константы. Следовательно, можно проинициализировать этот
            #  набор данных однократно при инициализации класса, а не делать это время всякий раз при вызове метода.
            ideal_data = [
                [0.0, 'closure #yellow'],
                [self._ideal_time[0] * self.scaler, '{-}'],
                [(self._ideal_time[0] + 0.0001) * self.scaler, 'compression #yellow'],
                [sum(self._ideal_time[:2]) * self.scaler, '{-}'],
                [(sum(self._ideal_time[:2])+ 0.0001) * self.scaler, 'welding #yellow'],
                [(sum(self._ideal_time[:2]) + self.WeldTime)*self.scaler, '{-}'],
                [(sum(self._ideal_time[:2]) + 0.0001 + self.WeldTime) * self.scaler, 'opening #yellow'],
                [(sum(self._ideal_time[:3]) + self.WeldTime) * self.scaler, 'coming #yellow'],
                [(sum(self._ideal_time[:4]) + self.WeldTime) * self.scaler, '{-}'],
            ]
        # TODO: Очень неудачный способ хранения данных разного типа: сложен в восприятии,
        #  легко ошибиться или запутаться.
        #  Используй NamedTuple или dataclass: будут определены поля, их типы.
        #  Взаимодействие также будет гораздо проще (по имени поля, а не индексу).
        # TODO: Похоже, что все данные в этом списке - константы. Следовательно, можно проинициализировать этот набор
        #  данных однократно при инициализации класса, а не делать это время всякий раз при вызове метода.
        client_data = [
            [0.0 * self.scaler, 'closure'],
            [0.165 * self.scaler, '{-}'],
            [0.166 * self.scaler, 'compression'],
            [0.176 * self.scaler, '{-}'],
            [0.180*self.scaler, 'welding'],
            [0.200*self.scaler, '{-}'],
            [0.210 * self.scaler, 'opening'],
            [0.300 * self.scaler, '{-}'],
        ]

        # TODO: Зачем метод возвращает self.bool_dict, если никаких манипуляций с ним не проводит?
        return real_data, client_data, ideal_data, self.bool_dict

    def _generate_svg(self, real_data, client_data, ideal_data, bool_data) -> None:
        
        self._request_generator.clear()
        self._request_generator.appendStr('scale 25 as 50 pixels')
        
        if not self.theor_mode:
            self._request_generator.addLineStyle('biba', 'red', 2)

            for i, [signal, changes] in enumerate(bool_data.items()):
                name = 'bool_' + str(i)
                # TODO: 3 строки ниже замени на list comprehension
                #  times = [[str(float(f[0])*scaler), f[1]] for f in changes]
                times = []
                for f in changes:
                    times.append([str(float(f[0])*self.scaler), f[1]])
                self._request_generator.addBinary(name, str(signal), 'biba')
                self._request_generator.setTimestamps(name, times)

            self._request_generator.addConcise('RD', 'Real data')
            self._request_generator.setTimestamps('RD', real_data)
        else: self.name = self.path_to_save + '/Ideal'

        self._request_generator.addConcise('CD', 'Client data')
        self._request_generator.setTimestamps('CD', client_data)
        self._request_generator.addConcise('ID', 'Ideal data')
        self._request_generator.setTimestamps('ID', ideal_data)
        try:    
            self._request_generator.generateSVG(self.name)
        except Exception as e:
            print(f"SVG generate error: {e}")

    def update_uml(self, 
                 operator_config: dict,
                 system_config : dict,
                 ideal_time: list[float],
                 bool_dict: dict,
                 float_dict: dict,
                 timings_dict: dict,
                 mode: bool,
                 name:str):
        # TODO: Аргумент mode вводит в заблуждение: ожидаешь увидеть какой-то режим, на деле же это флаг
        #  теоретического режима. Поправь название аргумента.
        # TODO: Инициализацию атрибутов класса в конструкторе надо делать!
        self._ideal_time = ideal_time
        self.bool_dict = bool_dict
        self.float_dict = float_dict
        self.timings_dict = timings_dict
        self.theor_mode = mode
        self.name = name
        self.scaler = int(system_config['UML_time_scaler'])
        self.WeldTime = operator_config['time_wielding']
        
        real, client, ideal, bool_ = self._build_data()
        self._generate_svg(real, client, ideal, bool_)
