"""
Moving averages strategy with hard stop

TP exit based on the opposite signal.

After exiting by SL we are waiting for the new signal,  doing nothing.
"""

import logging
from typing import Generator

from algo.data.reader import PriceStream
# from algo.data.reporter import get_influx_strategy_output
from algo.indicator import MAverage
from algo.trading.state import CurrentState
from algo.trading import OrderType, TradeResult
from algo.data.common import PricePoint
from algo.util import d
from algo.strategy.common import BaseStrategyParams


class MAHSStrategyParams(BaseStrategyParams):
    """ Stands for Moving Averages Hard Stop strategy"""
    first_avg_length: int  # number  of periods of the moving average 1
    second_avg_length: int  # number  of periods of the moving average 2
    stop_size: int  # stop loss size in pips


log = logging.getLogger(__name__)

# following pip size it hardcoded for the USDJPY
PIP_SIZE = 0.01


def run_trading(data_stream: PriceStream, params: MAHSStrategyParams, state: CurrentState) -> Generator[TradeResult, None, None]:
    (mavg1_len, mavg2_len, stop_size) = params
    mavg1 = MAverage(mavg1_len)
    mavg2 = MAverage(mavg2_len)
    price: PricePoint
    # state_reporter = get_influx_strategy_output()
    # trading_stream_id = 'influx-data-2022-10-31'
    prev_direction: OrderType = None
    signal: OrderType = None
    for price in data_stream:
        # report_data = {}
        # indicators arrangmenet section
        mavg1.tick(price.bid)
        mavg2.tick(price.bid)
        # log.debug('price-data', extra=d(price, mavg1, mavg2))

        if not (mavg1.ready() and mavg2.ready()):
            # skipping before ready
            continue
        # report_data.update({'mavg1': mavg1.value, 'mavg2': mavg2.value, 'price': price.bid})

        # desigion making section
        signal = None
        current_direction = _get_future_expectation(mavg1, mavg2)
        if current_direction != prev_direction:
            signal = current_direction
            prev_direction = current_direction

        #  existing  market conditionn
        if state.in_market:
            # SL exit
            if state.is_sl_time(price):
                trade = state.close(price)
                log.info('sl-closed-trade', extra=d(trade))
                # report_data.update({'close': price.bid})
                yield trade
            # TP exit (opposite signal received)
            if signal is not None and signal != state.order_type:
                # breaking DRY for the  readability
                trade = state.close(price)
                log.info('closed-trade', extra=d(trade))
                # report_data.update({'close': price.bid})
                yield trade

        # entering market condition
        if not state.in_market and signal is not None:
            log.info(  # TBD: confirm that lack of this logging in info mode actually speeds up simulation
                'open-trade',
                extra=d(state, price, signal)
            )
            # report_data.update({f'open_{expected_direction}': price.bid})
            state.open(price, signal, stop_size * PIP_SIZE)

        # state_reporter.report_point(
        #     trading_stream_id,
        #     price.time,
        #     report_data
        # )


def _get_future_expectation(mavg1: MAverage, mavg2: MAverage) -> OrderType:
    return OrderType.BUY if mavg1.value > mavg2.value else OrderType.SELL
