"""The sample makes historical RangeBars requests and waits for responses for 20 sec"""

import logging
import threading
from datetime import datetime, timedelta, timezone

import win32com.client
from tabulate import tabulate
from win32com.client import constants

import CELEnvironment

#region Settings

# Replace it with enabled symbol
SYMBOL = "EP"

# Logging settings: specify log level and log format here.
# Set log level to DEBUG to see more internal messages.
# See more information about logging lib usage: https://docs.python.org/3/howto/logging-cookbook.html
CELEnvironment.LOG_LEVEL = logging.INFO
# CELEnvironment.LOG_FORMAT = ...

# CELEnvironment.SinkInternal uses own LOG_LEVEL (which is inherited from the global one) and own LOG_FORMAT.
# You can redefine them as follows:
# CELEnvironment.SinkInternal.LOG_LEVEL = logging.DEBUG
# CELEnvironment.SinkInternal.LOG_FORMAT = ...

LOG = CELEnvironment.GetLogger()

#endregion


class RangeBarsSample(CELEnvironment.CELSinkBase):
    def __init__(self):
        self.eventDone = threading.Event()

    def Init(self, celEnvironment):
        self.celEnvironment = celEnvironment

    def Start(self):
        LOG.info("Create range bars request")
        request = win32com.client.Dispatch(self.celEnvironment.cqgCEL.CreateRangeBarsRequest())
        request.Symbol = SYMBOL
        request.RangeStart = datetime.now(timezone.utc) - timedelta(hours=2)
        request.RangeEnd = datetime.now(timezone.utc) - timedelta(hours=1)
        request.RangeUnit = win32com.client.constants.ruTick
        request.Range = 5
        request.SessionsFilter = "all"

        # NOTE: next line does nothing (the default `spSession` value is used) if extended Range/Renko feature
        # is not enabled for the account
        request.StartPoint = constants.spMonth

        LOG.info("Request range bars (%s - %s)", request.RangeStart, request.RangeEnd)
        self.rangeBars = self.celEnvironment.cqgCEL.RequestRangeBars(request)

        LOG.info("Waiting results for 20 seconds...")
        self.eventDone.wait(20)

        LOG.info("Done!")

    def OnDataError(self, cqgError, errorDescription):
        assert cqgError is not None
        error = win32com.client.Dispatch(cqgError)
        LOG.error("OnDataError: Code: %d Description: %s", error.Code, error.Description)
        self.eventDone.set()

    def OnRangeBarsResolved(self, cqgRangeBars, cqgError):
        if cqgError is not None:
            error = win32com.client.Dispatch(cqgError)
            LOG.error("OnRangeBarsResolved: Code: %d Description: %s", error.Code, error.Description)
            self.eventDone.set()
            return

        rangeBars = win32com.client.Dispatch(cqgRangeBars)
        headers = ["Timestamp", "Open", "High", "Low", "Close", "Mid", "HLC3", "Avg", "Range", "ActualVol", "TickVol"]
        data = []
        for rangeBar in rangeBars:
            data.append([
                rangeBar.Timestamp,
                rangeBar.Open,
                rangeBar.High,
                rangeBar.Low,
                rangeBar.Close,
                rangeBar.Mid,
                rangeBar.HLC3,
                rangeBar.Avg,
                rangeBar.Range,
                rangeBar.ActualVolumeFractional,
                rangeBar.TickVolume
            ])

        LOG.info("OnRangeBarsResolved: Bars count: %d. Bars:\n%s", rangeBars.Count, tabulate(data, headers=headers))
        self.eventDone.set()


# If CQGCEL.APIConfiguration must be customized then do it in this function
def CustomAPIConfiguration(APIConfiguration):
    LOG.info("Set UTC time zone. All time values passed to (received from) CQG API should correspond to this setting. ")
    APIConfiguration.TimeZoneCode = constants.tzUTC


if __name__ == "__main__":
    CELEnvironment.Start(RangeBarsSample, CustomAPIConfiguration)
