"""Runnable sample script. Demonstrates ticks request for some time range without subscription on updates.
"""

import logging
import threading
from datetime import datetime, timedelta, timezone

from tabulate import tabulate
from win32com.client import Dispatch, constants

import CELEnvironment

# region Settings

# Replace it with enabled symbol
SYMBOL = "CLE"

# 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 TicksRequestSample(CELEnvironment.CELSinkBase):
    def __init__(self):
        self.eventDone = threading.Event()
        self.celEnvironment = None
        self.ticks = None

    def Init(self, celEnvironment):
        self.celEnvironment = celEnvironment

    def Start(self):
        LOG.info("Creating ticks request...")
        request = Dispatch(self.celEnvironment.cqgCEL.CreateTicksRequest())
        request.Symbol = SYMBOL
        request.Type = constants.trtTimeRange
        request.RangeStart = datetime.now(timezone.utc) - timedelta(hours=1, minutes=1)
        request.RangeEnd = request.RangeStart + timedelta(minutes=1)
        request.TickFilter = constants.tfAll
        request.SessionsFilter = 31
        request.Limit = 100

        LOG.info("Starting the request: %s - %s (an accuracy to the minute)...", request.RangeStart, request.RangeEnd)
        self.ticks = self.celEnvironment.cqgCEL.RequestTicks(request)

        self.eventDone.wait(10)

        LOG.info("Done!")

    def OnDataError(self, cqgError, errorDescription):
        if cqgError is not None:
            error = Dispatch(cqgError)
            LOG.error("OnDataError: Code: %d. Description: '%s'", error.Code, error.Description)
        self.eventDone.set()

    def OnTicksResolved(self, cqgTicks, cqgError):
        if cqgError is not None:
            error = Dispatch(cqgError)
            LOG.error("OnTicksResolved: Code: %d. Description: '%s'", error.Code, error.Description)
        else:
            ticks = Dispatch(cqgTicks)
            LOG.info(
                "OnTicksResolved: Ticks count: %d. Ticks:\n%s",
                ticks.Count,
                tabulate(
                    [self.getTickRow(tick, index) for tick, index in zip(ticks, range(ticks.Count))],
                    headers=["Index", "Timestamp", "Vol", "Price", "PriceType", "SalesCondition"],
                ),
            )

        self.eventDone.set()

    # region Utility methods

    def validateValue(self, value):
        """Returns value if it is valid, otherwise "N/A" string.
        WARN: should be called only from callbacks.

        Args:
            value (datetime | float | int): Value to check.
        """
        return value if self.celEnvironment.cqgCELForCallback.IsValid(value) else "N/A"

    def getTickRow(self, tick, index: int) -> list:
        """Returns CQGTick values as list.
        WARN: should be called only from callbacks.

        Args:
            tick (CQGTick): Dispatched CQGTick object.
            index (int): Tick index.
        """
        res = [index, tick.Timestamp, tick.VolumeFractional, tick.Price, tick.PriceType, tick.SalesConditionLabel]
        return [self.validateValue(value) for value in res]

    # endregion


# 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(TicksRequestSample, CustomAPIConfiguration)
