from abc import abstractmethod
from decimal import Decimal
from dataclasses import dataclass
from datetime import datetime


@dataclass(eq=True)
class CpmCoef:
    field: str
    value: str
    rate: Decimal
    active_from: datetime
    active_to: datetime

    def __init__(self, field: str, value: str, rate, active_from=None, active_to=None):
        self.field = field
        self.value = value
        self.rate = Decimal(rate)
        self.active_from = active_from
        self.active_to = active_to


@dataclass(eq=True)
class CpmData:
    base_cpm: Decimal
    final_cpm: Decimal
    coefs: list[CpmCoef]

    def __init__(self, base_cpm, final_cpm=None, coefs=[]):
        self.base_cpm = Decimal(base_cpm)
        self.final_cpm = Decimal(base_cpm) if final_cpm is None else Decimal(final_cpm)
        self.coefs = coefs.copy()


class CpmUndefined(Exception):
    pass


class BaseCpmFilter:
    def __init__(self, **settings):
        self.settings = settings

    @abstractmethod
    def __call__(self, *, cpm_data: CpmData, **kwargs) -> CpmData:
        raise NotImplementedError


class BaseCoefCpmFilter(BaseCpmFilter):
    def __call__(self, *, cpm_data: CpmData, **kwargs) -> CpmData:
        coefs = self.get_coefs(**kwargs)
        for coef in coefs:
            if coef.rate != Decimal("1.0"):
                cpm_data.final_cpm *= coef.rate
                cpm_data.coefs.append(coef)
        return cpm_data

    @abstractmethod
    def get_coefs(self, **kwargs) -> list[CpmCoef]:
        pass


__all__ = ["CpmUndefined", "BaseCpmFilter", "BaseCoefCpmFilter", "CpmData", "CpmCoef"]
