import logging
from typing import List

from v20 import Context
from v20.order import MarketOrder
from v20.response import Response
from v20.trade import Trade
from v20.position import Position
from v20.transaction import MarketOrderTransaction, OrderFillTransaction

# should be from algo.config, but autofromatter keeps me in a hostage
from algo.config import config
from algo.trading import OrderType
from algo.constant import Symbol  # issues with
from algo.util import d
# from http import HttpStatus

log = logging.getLogger(__name__)


class RestApi:
    @staticmethod
    def get_rest_api():
        return Context(
            hostname=config.oanda_rest_host_name,
            token=config.oanda_token,
        )

    def __init__(self, default_instrument: Symbol) -> None:
        self._api = self.get_rest_api()
        # keep as a copy to shorten all API call
        self._account_id = config.oanda_account_id
        self._default_instrument = default_instrument

    def _get_direction_sign(self, direction: OrderType):
        return 1 if direction == OrderType.BUY else -1

    def open(self, direction: OrderType) -> OrderFillTransaction:
        """
        order opening, should do retry and it should be able to fail, informing trader
        """
        order_spec: MarketOrder = MarketOrder(
            type='MARKET',  # MARKET is a default value
            instrument=self._default_instrument.value,
            # positive buy, negative - sell
            units=10000 * self._get_direction_sign(direction)  # 10000 (10k) makes the pip cost 0.7
        )

        response: Response = self._api.order.create(
            accountID=self._account_id,
            order=order_spec
        )
        # response.body.keys() are following
        # 'orderCreateTransaction', 'orderFillTransaction', 'relatedTransactionIDs', 'lastTransactionID'])
        # response.status == 201 on success... should I retry?
        fill_transaction_order: OrderFillTransaction = response.body['orderFillTransaction']
        #  fields:  {"id": "7339", "time": "2022-12-15T08:02:37.590498811Z", "userID": 18976729, "accountID": "101-011-18976729-002", "batchID": "7338", "requestID": "25023463674101443", "type": "ORDER_FILL",
        log.info('open-order-response', extra=d(response.status, fill_transaction_order.dict()))
        return fill_transaction_order

    def close_all_trades(self) -> OrderFillTransaction:
        close_result = None
        for trade in self.get_open_trades():
            log.info('closing trade', extra=d(trade.dict()))
            close_result = self.close_trade(trade.id)
        return close_result

    def close_trade(self, trade_id) -> OrderFillTransaction:
        response: Response = self._api.trade.close(
            accountID=self._account_id,
            tradeSpecifier=trade_id
        )
        rbody = response.body
        # createTransactionOrder: MarketOrderTransaction = rbody['orderCreateTransaction']
        fill_transaction_order: OrderFillTransaction = rbody['orderFillTransaction']
        # 'relatedTransactionIDs', 'lastTransactionID'
        # fields:  {"id": "7325", "time": "2022-12-15T07:48:20.643980574Z", "userID": 18976729, "accountID": "101-011-18976729-002", "batchID": "7324", "requestID": "43037858587515207", "type": "ORDER_FILL", "orderID": "7324", "instrument": "USD_JPY", "units": "-10000.0", "gainQuoteHomeConversionFactor": "0.007327005386", "lossQuoteHomeConversionFactor": "0.007400643631", "price": 135.793, "fullVWAP": 135.793,
        log.info('close-trade-response', extra=d(fill_transaction_order.dict()))
        return fill_transaction_order

    def get_open_positions(self) -> List[Position]:
        response: Response = self._api.position.list_open(accountID=self._account_id)
        log.info(
            'get_current_positions',
            extra=d(body=response.body, rtype=type(response))
        )
        return response.body.get('positions', [])

    def get_open_trades(self) -> List[Trade]:
        response: Response = self._api.trade.list_open(
            accountID=self._account_id
        )
        log.info(
            'get-open-trades-response',
            extra=d(body=response.body, rtype=type(response))
        )
        return response.body.get('trades', [])
