# Copyright (c) 2023 Adam Souzis
# SPDX-License-Identifier: MIT
"""
Expose TOSCA units as Python objects
Usage:

>>> from tosca import mb
>>> one_mb = 1 * mb
>>> one_mb
1000000.0
>>> one_mb.as_unit
1.0
>>> one_mb.to_yaml()
'1.0 MB'
"""
import math
from typing import Any, Generic, Type, TypeVar, Dict
from toscaparser.elements.scalarunit import (
    ScalarUnit_Size,
    ScalarUnit_Time,
    ScalarUnit_Frequency,
    ScalarUnit_Bitrate,
)


class _Scalar(float):
    __slots__ = ("unit",)  # unit to represent this value as
    SCALAR_UNIT_DICT: Dict[str, Any] = {}

    def __new__(cls, value, unit):
        return float.__new__(cls, value)

    def __init__(self, value, unit):
        super().__init__()
        self.unit = unit

    @property
    def as_unit(self) -> float:
        return self / self.SCALAR_UNIT_DICT[self.unit]

    def to_yaml(self, dict_cls=dict) -> str:
        "return this value and this type's TOSCA unit suffix, eg. 10 kB"
        val = self.as_unit
        as_int = math.floor(val)
        if val == as_int:
            val = as_int  # whole number, treat as int
        return f"{val} {self.unit}"

    # def __str__(self) -> str:
    #     return str(float(self))

    # def __repr__(self) -> str:
    #     return f"{self.__class__.__name__}({super().__repr__()})"


_S = TypeVar("_S", bound="_Scalar")

class _Unit(Generic[_S]):
    def __init__(self, scalar_type: Type[_S], unit: str):
        self.unit = scalar_type(scalar_type.SCALAR_UNIT_DICT[unit], unit)

    def __rmul__(self, other: float) -> _S:
        return self.unit.__class__(self.unit * other, self.unit.unit)

class Size(_Scalar):
    tosca_name = "scalar-unit.size"
    SCALAR_UNIT_DICT = ScalarUnit_Size.SCALAR_UNIT_DICT


class Frequency(_Scalar):
    tosca_name = "scalar-unit.frequency"
    SCALAR_UNIT_DICT = ScalarUnit_Frequency.SCALAR_UNIT_DICT


class Time(_Scalar):
    tosca_name = "scalar-unit.time"
    SCALAR_UNIT_DICT = ScalarUnit_Time.SCALAR_UNIT_DICT

class Bitrate(_Scalar):
    tosca_name = "scalar-unit.bitrate"
    SCALAR_UNIT_DICT = ScalarUnit_Bitrate.SCALAR_UNIT_DICT


B = _Unit(Size, "B")
b = B
kB = _Unit(Size, "kB")
kb = kB
KB = kB
KiB = _Unit(Size, "KiB")
kib = KiB
KIB = KiB
MB = _Unit(Size, "MB")
mb = MB
MiB = _Unit(Size, "MiB")
mib = MiB
MIB = MiB
GB = _Unit(Size, "GB")
gb = GB
GiB = _Unit(Size, "GiB")
gib = GiB
GIB = GiB
TB = _Unit(Size, "TB")
tb = TB
TiB = _Unit(Size, "TiB")
tib = TiB
TIB = TiB
d = _Unit(Time, "d")
D = d
h = _Unit(Time, "h")
H = h
m = _Unit(Time, "m")
M = m
s = _Unit(Time, "s")
S = s
ms = _Unit(Time, "ms")
MS = ms
us = _Unit(Time, "us")
US = us
ns = _Unit(Time, "ns")
NS = ns
Hz = _Unit(Frequency, "Hz")
hz = Hz
HZ = Hz
kHz = _Unit(Frequency, "kHz")
khz = kHz
KHZ = kHz
MHz = _Unit(Frequency, "MHz")
mhz = MHz
MHZ = MHz
GHz = _Unit(Frequency, "GHz")
ghz = GHz
GHZ = GHz
bps = _Unit(Bitrate, "bps")
BPS = bps
Kbps = _Unit(Bitrate, "Kbps")
kbps = Kbps
KBPS = Kbps
Kibps = _Unit(Bitrate, "Kibps")
kibps = Kibps
KIBPS = Kibps
Mbps = _Unit(Bitrate, "Mbps")
mbps = Mbps
MBPS = Mbps
Mibps = _Unit(Bitrate, "Mibps")
mibps = Mibps
MIBPS = Mibps
Gbps = _Unit(Bitrate, "Gbps")
gbps = Gbps
GBPS = Gbps
Gibps = _Unit(Bitrate, "Gibps")
gibps = Gibps
GIBPS = Gibps
Tbps = _Unit(Bitrate, "Tbps")
tbps = Tbps
TBPS = Tbps
Tibps = _Unit(Bitrate, "Tibps")
tibps = Tibps
TIBPS = Tibps

# units generated by:
# from toscaparser.elements.scalarunit import ScalarUnit_Size, ScalarUnit_Time, ScalarUnit_Frequency, ScalarUnit_Bitrate

# for scalar_cls in [ScalarUnit_Size, ScalarUnit_Time, ScalarUnit_Frequency, ScalarUnit_Bitrate]:
#     unit_class = scalar_cls.__name__[len("ScalarUnit_"):]
#     for name, scale in scalar_cls.SCALAR_UNIT_DICT.items():
#         print(f'{name} = _Unit({unit_class}, "{name}")')
#         if name != name.lower():
#             print(f"{name.lower()} = {name}")
#         if name != name.upper():
#             print(f"{name.upper()} = {name}")
