from typing import Set, Any
from math import inf

from evrouting.utils import PriorityQueue
from evrouting.T import SoC, Time

from .T import Label
from .factories import SoCFunctionFactory


class LabelPriorityQueue(PriorityQueue):
    def __init__(self, f_soc: SoCFunctionFactory, l_set: Set[Label]):
        super().__init__()
        self.f_soc_factory: SoCFunctionFactory = f_soc
        self.l_set: Set[Label] = l_set

    def insert(self, label: Label):
        """Breaking ties with lowest soc at t_min."""
        soc_function = self.f_soc_factory(label)
        t_min: Time = soc_function.minimum

        # Might happen because of dummy charge stations
        if t_min == -inf:
            raise ValueError('Infeasible label.')

        soc_min: SoC = soc_function(t_min)

        super().insert(
            item=label,
            priority=t_min,
            count=soc_min
        )

        if self.peak_min() == label:
            self.dominance_check()

    def delete_min(self) -> Any:
        min_label = super().delete_min()
        self.dominance_check()
        return min_label

    def dominance_check(self):
        try:
            label: Label = self.peak_min()
        except KeyError:
            return

        soc = self.f_soc_factory(label)

        for other_label in self.l_set:
            if self.f_soc_factory(other_label) > soc:
                self.remove_item(label)
                return