###############################################################################
# This file is part of the tango-takeoff project.
#
# Copyright Lund University
#
# Distributed under the GNU GPLv3 license. See LICENSE file for more info.
###############################################################################
from dataclasses import dataclass, field, fields
from enum import Enum
from typing import NamedTuple, Optional


class Server(NamedTuple):
    name: str
    host: Optional[str] = None
    level: Optional[int] = None

    def is_valid(self) -> bool:
        return "*" not in self.name and self.host is not None and self.level is not None


class Mode(Enum):
    UNCONTROLLED = 0
    CONTROLLED = 1

    def to_int(self):
        if self == Mode.UNCONTROLLED:
            return 0
        elif self == Mode.CONTROLLED:
            return 1

        raise RuntimeError("should not get here")


class Order(Enum):
    ASCENDING = 0
    DESCENDING = 1


class Level(NamedTuple):
    level: int
    servers: list[str]


class Host(NamedTuple):
    hostname: str
    levels: list[Level]


@dataclass
class Result:
    started: list[str] = field(default_factory=list)
    stopped: list[str] = field(default_factory=list)
    already_running: list[str] = field(default_factory=list)
    already_stopped: list[str] = field(default_factory=list)
    failed_to_start: list[str] = field(default_factory=list)
    failed_to_stop: list[str] = field(default_factory=list)
    changed_info: list[str] = field(default_factory=list)

    def __add__(self, other):
        if not isinstance(other, Result):
            raise TypeError("Unsupported operand type(s) for +")
        new = {}
        for _field in fields(self):
            new[_field.name] = getattr(self, _field.name) + getattr(other, _field.name)
        return Result(**new)

    @property
    def changed(self):
        return bool(self.started or self.stopped or self.changed_info)
