from __future__ import annotations

from dataclasses import dataclass, field
from enum import Flag, FlagBoundary, auto
from typing import Final

from .batprotocol import (
    SimulationFeaturesPDict,
    SimulationMetadataPDict,
    __batprotocol_version__,
)


class SimulationFeatures(Flag, boundary=FlagBoundary.STRICT):
    """
    Configuration of simulation features.

    See batprotocol::fb::EDCRequestedSimulationFeatures for reference.
    """

    DYNAMIC_REGISTRATION = auto()
    """Enable dynamic registration of jobs and profiles."""

    PROFILE_REUSE = auto()
    """Allow existing profiles to be used to register new dynamic jobs."""

    ACKNOWLEDGE_DYNAMIC_JOBS = auto()
    """Ask Batsim to emit back a JobSubmittedEvent upon creation of a dynamic job."""

    FORWARD_PROFILES_ON_JOB_SUBMISSION = auto()
    """Include profile information in JobSubmittedEvent."""

    FORWARD_PROFILES_ON_JOBS_KILLED = auto()
    """Include profile information in JobsKilledEvent."""

    FORWARD_PROFILES_ON_SIMULATION_BEGINS = auto()
    """Include profile information in SimulationBeginsEvent."""

    @classmethod
    def default(cls) -> SimulationFeatures:
        return cls(0)

    def to_protocol_dict(self) -> SimulationFeaturesPDict:
        return {
            'dynamic_registration': SimulationFeatures.DYNAMIC_REGISTRATION in self,
            'profile_reuse': SimulationFeatures.PROFILE_REUSE in self,
            'acknowledge_dynamic_jobs': SimulationFeatures.ACKNOWLEDGE_DYNAMIC_JOBS in self,  # noqa: E501 (reason: improves readability)
            'forward_profiles_on_job_submission': SimulationFeatures.FORWARD_PROFILES_ON_JOB_SUBMISSION in self,  # noqa: E501 (reason: improves readability)
            'forward_profiles_on_jobs_killed': SimulationFeatures.FORWARD_PROFILES_ON_JOBS_KILLED in self,  # noqa: E501 (reason: improves readability)
            'forward_profiles_on_simulation_begins': SimulationFeatures.FORWARD_PROFILES_ON_SIMULATION_BEGINS in self,  # noqa: E501 (reason: improves readability)
        }  # fmt: skip


@dataclass
class SimulationMetadata:
    """
    Container for information about the simulation.

    The information contained in SimulationMetadata is set during the initial
    handshake with Batsim.
    """

    edc_init_str: str | None = None

    # Batsim and batprotocol information
    batprotocol_version: Final[str] = __batprotocol_version__
    batsim_version: str | None = None
    batsim_commit: str | None = None

    # simulation features requested by the EDC
    requested_features: SimulationFeatures = field(
        default_factory=SimulationFeatures.default
    )

    def to_protocol_dict(self) -> SimulationMetadataPDict:
        return {
            'batprotocol_version': self.batprotocol_version,
            'requested_simulation_features': self.requested_features.to_protocol_dict(),
        }
