import yaml
from dataclasses import dataclass, field, asdict
from typing import Any, List, Dict, Optional
from utils.consts import *
from utils.flows.flow import Filter


@dataclass
class MonthlyRenewalData:
    day: int
    hour: int
    minute: int
    timezone: str


@dataclass
class Spillover:
    max: int


@dataclass
class QuotaLimit:
    max: int
    interval: int
    interval_unit: str
    spillover: Optional[Spillover] = None


@dataclass
class InternalLimit(QuotaLimit):
    id: str = ""
    parent_id: str = ""
    filter: Optional[Filter] = None


@dataclass
class FixedWindowConfig(QuotaLimit):
    group_by_header: Optional[str] = None
    monthly_renewal: Optional[MonthlyRenewalData] = None


@dataclass
class ConcurrentConfig:
    max: int


@dataclass
class HeaderBasedConfig:
    header: str
    value: str


@dataclass
class StrategyConfig:
    fixed_window: Optional[FixedWindowConfig] = None
    concurrent: Optional[ConcurrentConfig] = None
    header_based: Optional[HeaderBasedConfig] = None
    allocation_percentage: Optional[int] = None


@dataclass
class QuotaConfig:
    id: Optional[str] = None
    filter: Optional[Filter] = None
    strategy: Optional[StrategyConfig] = None


@dataclass
class ChildQuotaConfig(QuotaConfig):
    parent_id: Optional[str] = None


@dataclass
class ResourceQuotaRepresentation:
    quotas: List[QuotaConfig] = field(default_factory=list)
    internal_limits: List[ChildQuotaConfig] = field(default_factory=list)

    def add_quota(self, quota: QuotaConfig):
        self.quotas.append(quota)

    def add_child_limit(self, limit: ChildQuotaConfig):
        self.internal_limits.append(limit)

    def to_dict(self) -> Dict[Any, Any]:
        def dict_factory(data: Any) -> Dict[Any, Any]:
            return {
                k: v
                for k, v in data
                if v is not None and (not isinstance(v, list) or v)
            }

        return asdict(self, dict_factory=dict_factory)

    def build_yaml(self):
        def custom_represent_dict(dumper: Any, data: Any):
            new_data = {}
            for k, v in data.items():
                if isinstance(k, Enum):
                    k = str(k)
                if isinstance(v, Enum):
                    v = str(v)
                cleaned_key = k.rstrip("_")
                new_data[cleaned_key] = v

            return dumper.represent_dict(new_data)

        yaml.add_representer(dict, custom_represent_dict)
        return yaml.dump(
            self.to_dict(), default_flow_style=False, sort_keys=False, canonical=False
        )
