# src/bansga/core/interfaces.py
"""Protocol/ABC definitions for the GA components (ISP + DIP)."""
from __future__ import annotations

from typing import Protocol, List, Any, Iterator
import numpy as np

class IHash(Protocol):
    def add_structure(self, container: "individual", force_rehash: bool) -> bool: ...
    def already_visited(self, container: "individual", ) -> bool: ...


class IAgent(Protocol):
    def is_active(self, ) -> bool: ...
    def append(self, obj: Any, ) -> bool: ...
    def flush(self, ) -> list: ...
    def get_batch(self, prune: bool, sleep: float,) -> Iterator: ...
    def update_behaviour(self, population: "Population", ctx: "GAContext",) -> bool: ...


class ILineage(Protocol):
    def assign_lineage(self, population: "Population", ctx: "GAContext") -> None: ...


class IDoE(Protocol):
    def assign_lineage(self, population: "Population", ctx: "GAContext") -> None: ...


class IPopulation(Protocol):
    def load_partitions(self, dataset_path: Any, ctx: "GAContext") -> Any: ...


class IThermostat(Protocol):
    def update(self, generation: int, stall: int = 0, signals: Any = None) -> float: ...


class ISelector(Protocol):
    def select(self, objectives:np.array, features:np.array, size:int) -> np.array[int]: ...
    def set_temperature(self, temperature:np.array ) -> bool[int]: ...

class ITransitionKernel(Protocol):
    def step(self, parents: Any, candidates: List[Any], population: Any, simulator: Any, ctx: Any) -> List[Any]: ...
    def allows_agent_sync(self) -> bool: ...

class IMutation(Protocol):
    def mutate(self, individual: Any, ctx: "GAContext") -> Any: ...


class ICrossover(Protocol):
    def crossover(self, parent1: Any, parent2: Any, ctx: "GAContext") -> Any: ...


class IVariation(Protocol):
    def mutate(self, individual: Any, ctx: "GAContext") -> Any: ...

class IGenerative(Protocol):
    """
    Protocol for generative guidance models.

    A generative model proposes feature-space targets that guide
    the evolutionary search. It does NOT generate structures.
    """
    def is_active(self, generation: int) -> bool: ...

    def generate_targets(
        self,
        *,
        generation: int,
        features: np.ndarray,
        objectives: np.ndarray,
        temperature: float,
    ) -> np.ndarray | None: ...


class IForeignerGenerator(Protocol):
    def generate(self, ctx: "GAContext") -> List[Any]: ...


class IEvaluator(Protocol):
    def evaluate(self, individuals: List[Any], ctx: "GAContext") -> List[Any]: ...


class ISimulator(Protocol):
    def validate(self, individuals: List[Any]) -> List[Any]: ...
    def run(self, individuals: List[Any]) -> List[Any]: ...


class IConvergence(Protocol):
    def should_stop(self, population: "Population", ctx: "GAContext") -> bool: ...


class ILogger(Protocol):
    def gen_start(self, gen: int, population: "Population") -> None: ...
    def gen_end(self, gen: int, population: "Population") -> None: ...
    def stall_count(self) -> int: ...


class IPlotter(Protocol):
    def gen_start(self, gen: int, population: "Population") -> None: ...
    def gen_end(self, gen: int, population: "Population") -> None: ...
    def stall_count(self) -> int: ...


    