from typing import Optional, Tuple

import numpy as np
import pandas as pd

   
#TODO: Реализовать поиск времени простоя
class DowntimeAnalyzer:
    def __init__(self) -> None:
        ...

    def generate_downtime_report(self) -> list:
        ...

    def _separate_conditions(self, TWC_raw:pd.DataFrame, robot_raw:pd.DataFrame) -> Tuple[dict, dict]:
        robot_splitter = RobotConditionSplitter()
        TWC_splitter = TWC_ConditionSplitter()
        #comm_splitter = CommConditionSplitter()
        rob_conditions = robot_splitter.split(robot_raw)
        TWC_conditions = TWC_splitter.split(TWC_raw)
        #comm_df = comm_splitter.split(rob_conditions["communication"], TWC_conditions["communication"])
        return (rob_conditions, TWC_conditions)


class ConditionSplitter:
    def __init__(self):
        self._signals = []

    def _find_indexes(self,
                       signal: str,  
                       dataframe: pd.DataFrame) -> list[list[float], list[float]]:
        stage_diff = np.diff(dataframe[signal])
        start_idx = np.where(stage_diff == 1)
        finish_idx = np.where(stage_diff == -1)
        return start_idx[0], finish_idx[0]
    
    def _find_events(self, 
                        dataframe: pd.DataFrame, 
                        signals: list[str]) -> Optional[dict[dict[pd.Series]]]: 
        intervals = {}
        end_time = 0
        for signal in signals:
            start_idx, finish_idx = np.array(self._find_indexes(signal, dataframe))
            start_series = dataframe.loc[start_idx, "time"].reset_index(drop=True)
            end_series = dataframe.loc[finish_idx, "time"].reset_index(drop=True)
            end_series.fillna(end_time)
            intervals[signal] = {"rise": start_series,
                                "fall": end_series}
        return intervals
    
    def _form_intervals(self, 
                        start: pd.Series, 
                        end: pd.Series) -> dict:
        if len(start) != len(end):
            for i in range(1, len(end)):
                if end[i-1] > start[i]:
                   start = start.drop(i).reset_index(drop=True)
        intervals = {'start':start.tolist, 'end':end.tolist}
        return intervals
    

class RobotConditionSplitter(ConditionSplitter):
    def __init__(self):
        self._signals = [
            "$OUT3012", 
            "$IN3003", 
            "$OUT3003", 
            "$OUT3244"
        ]

    def split(self, dataframe: pd.DataFrame) -> dict:
        events = self._find_events(dataframe, self._signals)
        communication_sig = {'sent':events["$OUT3244"]["fall"], 'received':events[""][""]}
        point_interval = self._form_intervals(start=events["$OUT3012"]["rise"], end=events["$OUT3012"]["fall"])
        movement_interval = self._form_intervals(start=events["$OUT3244"]["rise"], end=events["$OUT3244"]["fall"])
        conditions = {"communication":communication_sig, "waiting": point_interval, "moving": movement_interval}
        return conditions

    
class TWC_ConditionSplitter(ConditionSplitter):
    def __init__(self):
        self._signals = [
            "Closing",
            "Squeeze",
            "Welding",
            "Relief", 
            "Oncoming"
        ]

    def split(self, dataframe: pd.DataFrame) -> dict:
        events = self._find_events(dataframe, self._signals)
        communication_sig = {'sent':events[""][""], 'received':events[""][""]} #ситара что-то делает -конец сигнала
        closing_interval = self._form_intervals(start=events["Closing"]["rise"], end=events["Closing"]["fall"])
        squeeze_interval = self._form_intervals(start=events["Squeeze"]["rise"], end=events["Squeeze"]["fall"])
        relief_interval = self._form_intervals(start=events["Relief"]["rise"], end=events["Relief"]["fall"])
        oncoming_interval = self._form_intervals(start=events["Oncoming"]["rise"], end=events["Oncoming"]["fall"])
        conditions = {
            "communication":communication_sig, 
            'closing':closing_interval,
            'squeeze':squeeze_interval,
            'relief':relief_interval,
            'oncoming':oncoming_interval
            }
        return conditions


class CommConditionSplitter(ConditionSplitter):
    """
    Определяет промежуток, в который происходит взаимодействие между нодами.
    """

    def split(self, node1: dict, node2: dict) -> pd.DataFrame:
        n1_to_n2 = self._form_intervals(start=node1['sent'], end=node2['received'])
        n2_to_n1 = self._form_intervals(start=node2['sent'], end=node1['received'])
        return pd.concat([pd.DataFrame(n1_to_n2), pd.DataFrame(n2_to_n1)])
    

if __name__ == "__main__":
    path = "D:\downloads\Test2\TeslaTIME29_71_KRCIO.dat"
