from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Hashable, Mapping


SolutionMapping = Mapping[Hashable, Any]


@dataclass(eq=False)
class UpSolution:
    """Upper-level solution container for line contracting decisions."""

    x_sol: dict[Hashable, Any] = field(default_factory=dict)

    def __init__(self, x_dict: SolutionMapping | None = None):
        self.x_sol = dict(x_dict) if x_dict is not None else {}

    def get_route_sol(self, route_id: Hashable) -> Any:
        return self.x_sol.get(route_id)

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, UpSolution):
            return NotImplemented
        return self.x_sol == other.x_sol

    def __str__(self) -> str:
        return f"up_x: {self.x_sol}"


@dataclass(eq=False)
class MidSolution:
    """Middle-level solution container for service frequency decisions."""

    f_sol: dict[Hashable, Any] = field(default_factory=dict)

    def __init__(self, f_dict: SolutionMapping | None = None):
        self.f_sol = dict(f_dict) if f_dict is not None else {}

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, MidSolution):
            return NotImplemented
        return self.f_sol == other.f_sol

    def __str__(self) -> str:
        return f"mid_f: {self.f_sol}"


@dataclass(eq=False)
class LowSolution:
    """Lower-level solution container for link flow and waiting time results."""

    v_sol: dict[Hashable, Any] = field(default_factory=dict)
    t_sol: dict[Hashable, Any] = field(default_factory=dict)

    def __init__(self, v_dict: SolutionMapping | None = None, t_dict: SolutionMapping | None = None):
        self.v_sol = dict(v_dict) if v_dict is not None else {}
        self.t_sol = dict(t_dict) if t_dict is not None else {}

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, LowSolution):
            return NotImplemented
        return self.v_sol == other.v_sol and self.t_sol == other.t_sol

    def __str__(self) -> str:
        return f"low_vt: v_sol={self.v_sol}, t_sol={self.t_sol}"

