from __future__ import annotations

from abc import ABC
from typing import ClassVar

if __name__ != "__main__":
    from ..resources import length_units, LENGTHUNITS

_volume_pr_doses = {
    "C": 0.18,
    "Default_Si": 0.15,
    "PZT": 0.24,
    "Si": 0.27,
    "Al": 0.30,
    "Ti": 0.37,
    "Cr": 0.10,
    "Fe": 0.29,
    "Ni": 0.14,
    "Cu": 0.25,
    "Mo": 0.12,
    "Ta": 0.32,
    "W": 0.12,
    "Au": 1.50,
    "MgO": 0.15,
    "SiO2": 0.24,
    "Al2O3": 0.08,
    "TiO": 0.15,
    "Si3N4": 0.20,
    "TiN": 0.15,
    "Fe2O3": 0.25,
    "GaAs": 0.20,
    "Pt": 0.23,
    "PMMA": 0.40
}


# Print all material classes for copy pasting if you change or add values in the volume pr. doses dict
def _print_classes():
    string = "class Materials:\n    __slots__ = ()\n\n"
    for k, v in _volume_pr_doses.items():
        string += f"    class {k}(Material):\n        _volume_pr_dose = _volume_pr_doses['{k}']\n\n"
    print(string)


class Material(ABC):
    _volume_pr_dose: ClassVar[float]
    _thickness: float

    __slots__ = ["_volume_pr_dose", "_thickness"]

    def __init__(self, thickness: float = float('inf'), units: LENGTHUNITS = "um"):
        if thickness == float('inf'):
            self._thickness = thickness
        else:
            self._thickness = length_units(thickness, units, "m")

    def get_thickness(self, units: LENGTHUNITS = "um") -> float:
        """Returns the thickness of the material in the specified units."""
        if self._thickness == float('inf'):
            return float('inf')
        else:
            return length_units(self._thickness, "m", units)

    @property
    def volume_pr_dose(self) -> float:
        """Returns the volume pr. dose for the material in units of microns cubed over nanocoloumbs [um^3/nC]."""
        return self._volume_pr_dose

    def __repr__(self) -> str:
        thickness = "inf" if self._thickness == float('inf') else f"{self.get_thickness('um')} μm"
        return (f"{self.__class__.__name__}(thickness={thickness}, "
                f"volume_pr_dose={self._volume_pr_dose} μm³/nC)")


class Materials:
    __slots__ = ()

    class C(Material):
        _volume_pr_dose = _volume_pr_doses['C']

    class Default_Si(Material):
        _volume_pr_dose = _volume_pr_doses['Default_Si']

    class PZT(Material):
        _volume_pr_dose = _volume_pr_doses['PZT']

    class Si(Material):
        _volume_pr_dose = _volume_pr_doses['Si']

    class Al(Material):
        _volume_pr_dose = _volume_pr_doses['Al']

    class Ti(Material):
        _volume_pr_dose = _volume_pr_doses['Ti']

    class Cr(Material):
        _volume_pr_dose = _volume_pr_doses['Cr']

    class Fe(Material):
        _volume_pr_dose = _volume_pr_doses['Fe']

    class Ni(Material):
        _volume_pr_dose = _volume_pr_doses['Ni']

    class Cu(Material):
        _volume_pr_dose = _volume_pr_doses['Cu']

    class Mo(Material):
        _volume_pr_dose = _volume_pr_doses['Mo']

    class Ta(Material):
        _volume_pr_dose = _volume_pr_doses['Ta']

    class W(Material):
        _volume_pr_dose = _volume_pr_doses['W']

    class Au(Material):
        _volume_pr_dose = _volume_pr_doses['Au']

    class MgO(Material):
        _volume_pr_dose = _volume_pr_doses['MgO']

    class SiO2(Material):
        _volume_pr_dose = _volume_pr_doses['SiO2']

    class Al2O3(Material):
        _volume_pr_dose = _volume_pr_doses['Al2O3']

    class TiO(Material):
        _volume_pr_dose = _volume_pr_doses['TiO']

    class Si3N4(Material):
        _volume_pr_dose = _volume_pr_doses['Si3N4']

    class TiN(Material):
        _volume_pr_dose = _volume_pr_doses['TiN']

    class Fe2O3(Material):
        _volume_pr_dose = _volume_pr_doses['Fe2O3']

    class GaAs(Material):
        _volume_pr_dose = _volume_pr_doses['GaAs']

    class Pt(Material):
        _volume_pr_dose = _volume_pr_doses['Pt']

    class PMMA(Material):
        _volume_pr_dose = _volume_pr_doses['PMMA']

if __name__ == "__main__":
    _print_classes()