from __future__ import annotations

from dataclasses import dataclass
from datetime import timedelta
from typing import Sequence

from numpy import ndarray

EMPTY_TIMEDELTA = timedelta(0)


@dataclass
class Iteration:
    """Single optimizer iteration during a run.

    Attributes:
        robustness: The robustness value of the sample
        sample: The input generated by the optimizer
    """

    robustness: float
    sample: ndarray


@dataclass
class Run:
    """All iterations of a single run of the optimizer.

    Attributes:
        history: List of optimizer iterations
        seed: The initial seed of the random number generator
        runtime: Time elapsed during run
    """

    history: Sequence[Iteration]
    run_time: timedelta

    @property
    def best_iter(self) -> Iteration:
        return min(self.history, key=lambda i: i.robustness)

    def __len__(self) -> int:
        return len(self.history)


@dataclass
class StaliroResult:
    runs: Sequence[Run]
    seed: int

    @property
    def best_run(self) -> Run:
        return min(self.runs, key=lambda r: r.best_iter.robustness)

    @property
    def run_time(self) -> timedelta:
        return sum((run.run_time for run in self.runs), EMPTY_TIMEDELTA)
