import os
import pickle

import pandas as pd
import datetime
import numpy as np

from tqdm import tqdm

from market_trade.core.indicators_v2 import ind_BB
from market_trade.core.signals_v2 import sig_BB, SignalsAggregator
from market_trade.core.dealManager import DealManager
from market_trade.core.trandeVoter import TradeVoter
from market_trade.core.riskManager import RiskManager


class DecisionManager:
    """Manages trading decisions based on signals, probability voting, and risk management.

    Coordinates the entire decision-making pipeline:
    1. Signals from indicators
    2. Probability-based voting (TradeVoter)
    3. Risk assessment (RiskManager)
    4. Deal tracking (DealManager)

    Example configuration:
        sig_config = {
            'sig_BB': {
                'className': sig_BB,
                'params': {'source': 'close', 'target': 'close'},
                'indicators': {
                    'ind_BB': {
                        'className': ind_BB,
                        'params': {'MeanType': 'SMA', 'window': 30, 'valueType': 'close', 'kDev': 2.5}
                    }
                }
            }
        }
    """

    def __init__(self, name: str, sig_dict: dict):
        """Initialize DecisionManager with configuration.

        Args:
            name: Identifier for this decision manager instance.
            sig_dict: Dictionary of signal configurations.
        """
        self.RM = RiskManager()
        self.DM = DealManager()
        self.TV = TradeVoter(name)
        self.SA = SignalsAggregator(sig_dict)
        self.sig_dict = sig_dict

    def get_online_answer(self, signals_ans: dict, price: float) -> dict:
        """Get trading decision for current market conditions.

        Args:
            signals_ans: Dictionary of signal data.
            price: Current market price.

        Returns:
            Risk-adjusted decision dictionary.
        """
        probability_decision = self.TV.get_decision_by_signals(self.get_signals_answer(signals_ans))
        rmd = self.RM.get_decision(
            probability_decision=probability_decision,
            price=price,
            deals=self.DM.deals
        )
        return rmd

    def get_signals_answer(self, signals_data_dict: dict) -> dict:
        """Get answers from all configured signals.

        Args:
            signals_data_dict: Dictionary of signal data inputs.

        Returns:
            Dictionary of signal results.
        """
        return self.SA.get_answer(signals_data_dict)

    def get_right_answer(self, value_1: float, value_2: float) -> str:
        """Determine correct direction based on value comparison.

        Args:
            value_1: First value (current).
            value_2: Second value (next).

        Returns:
            Direction: 'down' if value decreases, 'up' if increases, 'none' if same.
        """
        if value_1 > value_2:
            ans = 'down'
        elif value_1 < value_2:
            ans = 'up'
        else:
            ans = 'none'

        return ans

    def get_retro_trend_answer(self, retro_template_dict: dict, data: pd.DataFrame, window: int) -> dict:
        """Run retrospective analysis on historical data.

        Slides a window through historical data to generate training data
        for probability matrix generation.

        Args:
            retro_template_dict: Template defining signal structure.
            data: Historical market data.
            window: Size of sliding window.

        Returns:
            Dictionary with 'signalsAns' and 'rightAns' lists.
        """
        req_sig = {}
        ans = {
            'signalsAns': [],
            'rightAns': []
        }
        target = ''

        for k in tqdm(range(data.shape[0] - window - 1)):
            for i in retro_template_dict.keys():
                req_sig[i] = {'signalData': data[k:k+window], 'indicatorData': {}}
                target = self.SA.signals[i].params['target']
                for j in retro_template_dict[i]['indicatorData'].keys():
                    req_sig[i]['indicatorData'][j] = data[k:k+window]

            sig_ans = self.get_signals_answer(req_sig)
            right_ans = self.get_right_answer(data[target][k], data[target][k+1])

            ans['signalsAns'].append(sig_ans)
            ans['rightAns'].append(right_ans)

        return ans

    def generate_matrix_probability_from_dict(self, dict_signals: dict) -> None:
        """Generate probability matrices from retrospective signal data.

        Args:
            dict_signals: Dictionary containing 'signalsAns' and 'rightAns' from retro analysis.
        """
        self.TV.create_matrix_amounts(dict_signals['signalsAns'][0].keys())
        for i in range(len(dict_signals['signalsAns'])):
            self.TV.set_decision_by_signals(
                signal_decisions=dict_signals['signalsAns'][i],
                trande=dict_signals['rightAns'][i]
            )
        self.TV.generate_matrix_probability()

    def create_dump(self, postfix: str = '') -> str:
        """Save decision manager state to pickle file.

        Args:
            postfix: Optional postfix for filename.

        Returns:
            Absolute path to saved file.
        """
        data_dict = {
            'RM': self.RM,
            'DM': self.DM,
            'TV': self.TV,
            'SA': self.SA,
            'sigDict': self.sig_dict
        }
        file_name = 'data_' + postfix + '.pickle'
        with open(file_name, 'wb') as f:
            pickle.dump(data_dict, f)

        return os.path.abspath(file_name)

    def load_dump(self, path: str) -> None:
        """Load decision manager state from pickle file.

        Args:
            path: Path to pickle file.
        """
        with open(path, 'rb') as f:
            data_dict = pickle.load(f)

        self.RM = data_dict['RM']
        self.DM = data_dict['DM']
        self.TV = data_dict['TV']
        self.SA = data_dict['SA']
        self.sig_dict = data_dict['sigDict']
