from typing import Union, Optional
from collections import Counter
from dataclasses import dataclass
import cadquery as Cq
from nhf.materials import Role, KEY_ROLE, KEY_ITEM

@dataclass(frozen=True)
class Item:
    """
    A pre-fabricated item
    """
    mass: float

    #@property
    #def mass(self) -> float:
    #    """
    #    Mass, in grams
    #    """
    #    return self._mass

    #@mass.setter
    #def mass(self, value):
    #    assert value >= 0, "Mass cannot be negative"
    #    self._mass = value

    @property
    def name(self) -> str:
        pass

    @property
    def role(self) -> Optional[Role]:
        return None

    def generate(self, **kwargs) -> Union[Cq.Solid, Cq.Assembly, Cq.Workplane]:
        """
        Creates an assembly for this item. Subclass should implement this
        """
        return Cq.Assembly()

    def assembly(self, **kwargs) -> Cq.Assembly:
        """
        Interface for creating assembly with the necessary metadata
        """
        a = self.generate(**kwargs)
        if isinstance(a, Cq.Workplane) or isinstance(a, Cq.Solid):
            a = Cq.Assembly(a)
        if role := self.role:
            a.metadata[KEY_ROLE] = role
            a.color = role.color_avg()
        assert isinstance(a, Cq.Assembly)
        assert KEY_ITEM not in a.metadata
        a.metadata[KEY_ITEM] = self
        return a

    @staticmethod
    def count(a: Cq.Assembly) -> Counter:
        """
        Counts the number of items
        """
        occ = Counter()
        for _, obj in a.traverse():
            if KEY_ITEM not in obj.metadata:
                continue
            item = obj.metadata[KEY_ITEM]
            assert isinstance(item, Item)
            occ[item.name] += 1
        return occ