"""AfsCell — N-dimensional learning cell that explores the field."""

import numpy as np
from typing import Optional

_cell_counter = 0


class AfsCell:
    """
    A cell in the AFS simulation.

    Cells move through N-dimensional space, gain energy near concepts,
    lose energy from metabolism, reproduce when energy is high, and
    die when energy is depleted.
    """

    __slots__ = (
        "id", "position", "velocity", "energy", "state",
        "age", "generation", "parent_id", "traits",
    )

    def __init__(self, n_dims: int, position: Optional[np.ndarray] = None,
                 energy: float = 75.0, cell_id: Optional[str] = None):
        global _cell_counter
        _cell_counter += 1
        self.id = cell_id or f"cell_{_cell_counter}"
        self.position = position if position is not None else np.random.uniform(0.2, 0.8, n_dims)
        self.velocity = np.zeros(n_dims, dtype=np.float64)
        self.energy = energy
        self.state = "warm"  # hot, warm, cool, cold
        self.age = 0
        self.generation = 0
        self.parent_id: Optional[str] = None
        self.traits = {
            "exploration_rate": np.random.uniform(0.5, 1.5),
            "energy_efficiency": np.random.uniform(0.7, 1.3),
            "commitment": np.random.uniform(0.0, 1.0),
        }

    def update_state(self, max_energy: float = 100.0):
        """Update energy state classification."""
        ratio = self.energy / max_energy
        if ratio >= 0.7:
            self.state = "hot"
        elif ratio >= 0.4:
            self.state = "warm"
        elif ratio >= 0.15:
            self.state = "cool"
        else:
            self.state = "cold"

    def spawn_child(self, transfer_ratio: float = 0.4,
                    offset: float = 0.1, mutation: float = 0.2) -> "AfsCell":
        """Create a child cell near this cell's position."""
        n = len(self.position)
        child = AfsCell(n, energy=self.energy * transfer_ratio)
        child.position = self.position + np.random.uniform(-offset, offset, n)
        child.position = np.clip(child.position, 0.0, 1.0)
        child.parent_id = self.id
        child.generation = self.generation + 1

        # Mutate traits
        for trait_name, value in self.traits.items():
            child.traits[trait_name] = value + np.random.uniform(-mutation, mutation)
            child.traits[trait_name] = max(0.1, min(2.0, child.traits[trait_name]))

        self.energy *= (1.0 - transfer_ratio)
        return child
