import typing as tp

from nile.api.v1 import datetime as nd


def make_datetime(date_iso: tp.Optional[str]) -> tp.Optional[nd.Datetime]:
    """
    1. Trims part after seconds
    2021-03-11T13:11:53.371685+03:00
                       ^^^^^^^^^^
                       unwanted part
    2. Replaces 'T' symbol with space
    """
    if date_iso is None:
        return None
    formatted_iso = date_iso[:len("YYYY-mm-dd HH:MM:SS")].replace("T", " ")
    return nd.Datetime.from_iso(formatted_iso)


def convert_bytes_to_str(value: tp.Optional[bytes]) -> tp.Optional[str]:
    return value.decode("utf-8") if value else None


class Window:
    def __init__(self: tp.Any, start: nd.Datetime, end: nd.Datetime) -> None:
        self.start = start
        self.end = end

    def __eq__(self: tp.Any, other: tp.Any) -> bool:
        return self.start == other.start and self.end == other.end

    def __repr__(self: tp.Any) -> str:
        return f"[{self.start}; {self.end}]"

    def includes(self: tp.Any, timepoint: tp.Optional[nd.Datetime]) -> bool:
        if timepoint is None:
            return False
        return self.start <= timepoint and timepoint < self.end


class WindowsConfig:
    def __init__(self: tp.Any, from_date: str, to_date: str, windows_days: tp.List[int]) -> None:
        self.from_date = from_date
        self.to_date = to_date
        self.windows_days = windows_days

        self.left_margin = nd.Datetime.from_iso(from_date).next(offset=-max(windows_days)+1)
        self.right_margin = nd.Datetime.from_iso(to_date).next()

    def windows(self: tp.Any) -> tp.Generator[tp.Tuple[str, Window, int], None, None]:
        for fielddate_bytes in nd.datetime_range(self.from_date, self.to_date):
            fielddate: str = fielddate_bytes.decode("utf-8")
            for window_days in self.windows_days:
                window = Window(
                    nd.Datetime.from_iso(fielddate).next(offset=-window_days + 1),
                    nd.Datetime.from_iso(fielddate).next())
                yield (fielddate, window, window_days)

    def dates(self: tp.Any) -> tp.List[str]:
        return [date.decode("utf-8") for date in nd.datetime_range(self.from_date, self.to_date)]
