import uuid
from dataclasses import dataclass
from typing import Literal, Dict

from opentrons.protocol_api import Labware, InstrumentContext, TrashBin, WasteChute, OFF_DECK
from opentrons.protocol_api._types import OffDeckType
from opentrons.protocol_api.core.labware import LabwareLoadParams, AbstractLabware
from opentrons.protocol_api.protocol_context import ModuleTypes
from opentrons.types import Point, DeckSlotName

from ..data import StaticItemsDict, DynamicItemsDict
from ..helpers import get_location


@dataclass
class LabwareData:
    load_name: str
    """Labware name used for loading the module"""
    location: str
    """Deck slot the labware or it's parent is in"""
    namespace: str | None = None
    """Namespace used for loading the labware"""
    parent: uuid.UUID | None = None
    """Item identifier of parent labware or module"""
    child: uuid.UUID | None = None
    """Item identifier of child labware"""

    def update(self, instance: Labware, static_items: StaticItemsDict):
        location = get_location(instance)
        if location is not None:
            self.location = location
        else:
            raise RuntimeError("Couldn't update location of labware: "+ self.load_name + " with location: " + self.location)

        self.child = static_items.get_generic_id_by_reference(instance.child)

        self.parent = static_items.get_generic_id_by_reference(instance.parent)

    @staticmethod
    def from_instance(instance: Labware, static_items: StaticItemsDict):
        namespace = instance.uri.split('/')[0]

        data = LabwareData(load_name=instance.load_name, location="", namespace=namespace)
        data.update(instance, static_items)
        return data


@dataclass
class LabwareWrapper:
    labware_instance: Labware | None
    """The instance used for usage in the Opentrons API"""
    data: LabwareData
    """Data needed to instantiate the instance"""

    def __eq__(self, other):
        if isinstance(other, LabwareWrapper):
            return self.labware_instance == other.labware_instance
        if isinstance(other, Labware):
            return self.labware_instance == other
        return False

    @staticmethod
    def from_instance(instance: Labware, static_items: StaticItemsDict):
        return LabwareWrapper(labware_instance=instance,
                              data=LabwareData.from_instance(instance=instance, static_items=static_items))
