import MetaTrader5 as mt5
from datetime import datetime
import pandas as pd
from utils.common import Period

DEVIATION = 20



mt5_period_mapper = {
    Period.M1: mt5.TIMEFRAME_M1,
    Period.M5: mt5.TIMEFRAME_M5,
    Period.M15: mt5.TIMEFRAME_M15,
    Period.M30: mt5.TIMEFRAME_M30,
    Period.H1: mt5.TIMEFRAME_H1,
    Period.H4: mt5.TIMEFRAME_H4,
    Period.D1: mt5.TIMEFRAME_D1,
    Period.W1: mt5.TIMEFRAME_W1
}


class Mt5Client:
    def __init__(self,path=''):
        if path == '':
            mt5_path = r"C:\Program Files\Tickmill MT5 Terminal\terminal64.exe"
            mt5.initialize(mt5_path)
        # timezone = pytz.timezone("Etc/GMT-2")

    def get_bars(self, symbol, period: Period, utc_from: datetime, utc_to: datetime) -> pd.DataFrame:
        rates = mt5.copy_rates_range(symbol, mt5_period_mapper.get(period), utc_from, utc_to)
        rates_frame = pd.DataFrame(rates)
        rates_frame['time'] = pd.to_datetime(rates_frame['time'], unit='s')
        rates_frame.index = rates_frame['time']

        return rates_frame

    def get_last_bar(symbol: str, period: Period):
        rates = mt5.copy_rates_from_pos(symbol, mt5_period_mapper.get(period), 0, 1)
        if rates is None or len(rates) == 0:
            return None
        return rates[0]

    def position_total(self):
        return mt5.positions_total()

    def buy(self, symbol, volume):
        tick = mt5.symbol_info_tick(symbol)
        request = {
            "action": mt5.TRADE_ACTION_DEAL,
            "symbol": symbol,
            "volume": volume,
            "type": 0,
            "price": tick.ask,
            "deviation": DEVIATION,
            "magic": 100,
            "comment": "python market order",
            "type_time": mt5.ORDER_TIME_GTC,
            "type_filling": mt5.ORDER_FILLING_IOC,
        }

        order_result = mt5.order_send(request)
        print(order_result)

        return order_result

    def sell(self, symbol, volume):
        tick = mt5.symbol_info_tick(symbol)
        request = {
            "action": mt5.TRADE_ACTION_DEAL,
            "symbol": symbol,
            "volume": volume,
            "type": 1,
            "price": tick.bid,
            "deviation": DEVIATION,
            "magic": 100,
            "comment": "python market order",
            "type_time": mt5.ORDER_TIME_GTC,
            "type_filling": mt5.ORDER_FILLING_IOC,
        }

        order_result = mt5.order_send(request)
        print(order_result)

        return order_result

    def close(self, ticket):
        positions = mt5.positions_get()

        for pos in positions:
            tick = mt5.symbol_info_tick(pos.symbol)
            # 0 represents buy, 1 represents sell - inverting order_type to close the position
            type_dict = {0: 1, 1: 0}
            price_dict = {0: tick.ask, 1: tick.bid}

            if pos.ticket == ticket:
                request = {
                    "action": mt5.TRADE_ACTION_DEAL,
                    "position": pos.ticket,
                    "symbol": pos.symbol,
                    "volume": pos.volume,
                    "type": type_dict[pos.type],
                    "price": price_dict[pos.type],
                    "deviation": DEVIATION,
                    "magic": 100,
                    "comment": "python close order",
                    "type_time": mt5.ORDER_TIME_GTC,
                    "type_filling": mt5.ORDER_FILLING_IOC,
                }
                order_result = mt5.order_send(request)
                print(order_result)

                return order_result

        return 'Ticket does not exist'

    def close_all_buy(self):
        positions = mt5.positions_get()
        for position in positions:
            if position.type == mt5.ORDER_TYPE_BUY:
                self.close(position.ticket)

    def close_all_sell(self):
        positions = mt5.positions_get()
        for position in positions:
            if position.type == mt5.ORDER_TYPE_SELL:
                self.close(position.ticket)


if __name__ == '__main__':
    client = Mt5Client()
    sym = 'EURUSD'
    period = Period.H1
    utc_from = datetime(2019, 1, 2)
    utc_to = datetime(2025, 7, 27)
    bars = client.get_bars(sym, period, utc_from, utc_to)

    bars.to_csv(f'{sym}_{period.name}.csv', index=False)
