import pandas as pd
import datetime
import numpy as np
#import random

class TradeVoter():

    def __init__(self, name):

        self.name = name  # Instance identifier
        self.trade_values_list = ['up', 'none', 'down']  # Valid trade directions
        self.matrix_amounts = None  # Sum matrix for signal combinations
        self.keys_matrix_amounts = None  # Matrix keys, technical field
        self.matrix_probability = None  # Probability matrix for decision making


    # Function to create DataFrame with specified columns and indices. Indices are unique combinations.
    def create_df_by_names(self, names_index, column_names, default_value=0.0):
        df = pd.DataFrame(dict.fromkeys(column_names, [default_value]*pow(3, len(names_index))),
                          index=pd.MultiIndex.from_product([self.trade_values_list]*len(names_index), names=names_index)
                        )
        return df

    # Create sum matrix with default value
    def create_matrix_amounts(self, names_index: list) -> pd.DataFrame:
        self.matrix_amounts = self.create_df_by_names(names_index, self.trade_values_list, 0)
        self.keys_matrix_amounts = self.matrix_amounts.to_dict('tight')['index_names']
        self.create_matrix_probability(names_index)
        return self.matrix_amounts

    # Create probability matrix with default value
    def create_matrix_probability(self, names_index: list) -> pd.DataFrame:
        self.matrix_probability = self.create_df_by_names(names_index, self.trade_values_list)
        return self.matrix_probability

    # Set values in sum matrix. signalDecisions - indicator values key:value; trande - actual value
    def set_decision_by_signals(self, signal_decisions: dict, trande: str) -> None:
        buff = []
        for i in self.keys_matrix_amounts:
            buff.append(signal_decisions[i])
        self.matrix_amounts.loc[tuple(buff), trande] += 1

    # Fill probability matrix with calculated values from sum matrix
    def generate_matrix_probability(self) -> None:
        for i in range(self.matrix_amounts.shape[0]):
            print(self.matrix_amounts)
            row_sum = sum(self.matrix_amounts.iloc[i]) + 1
            self.matrix_probability.iloc[i]['up'] = self.matrix_amounts.iloc[i]['up'] / row_sum
            self.matrix_probability.iloc[i]['none'] = self.matrix_amounts.iloc[i]['none'] / row_sum
            self.matrix_probability.iloc[i]['down'] = self.matrix_amounts.iloc[i]['down'] / row_sum

    # Get decision from probability matrix based on signal values
    def get_decision_by_signals(self, signal_decisions: dict) -> dict:
        ans = {}
        splice_search = self.matrix_probability.xs(tuple(signal_decisions.values()),
                                                       level=list(signal_decisions.keys())
                                                      )
        ans['probability'] = splice_search.to_dict('records')[0]
        ans['trande'] = splice_search.iloc[0].idxmax()
        return ans

    # Get probability and sum matrices as dictionaries
    def get_matrix_dict(self) -> dict:
        ans = {}
        ans['amounts'] = self.matrix_amounts.to_dict('tight')
        ans['probability'] = self.matrix_probability.to_dict('tight')
        return ans

    # Set probability and sum matrices from dictionaries
    def set_matrix_dict(self, matrix_dict: dict) -> dict:
        if matrix_dict['amounts'] != None:
            self.matrix_amounts = pd.DataFrame.from_dict(y['amounts'], orient='tight')
        if matrix_dict['probability'] != None:
            self.matrix_probability = pd.DataFrame.from_dict(y['probability'], orient='tight')
