# CelerisLab/body/sync_plan.py
"""
BodySyncPlan -- topology change descriptor for runtime body sync. (D2Q9 only)

Design:
    A ``BodySyncPlan`` is constructed by ``ObjectManager.build_sync_plan()``
    and consumed by ``Simulation.sync_bodies()``.  It describes the full
    topology transition from the current formal object set to the next one,
    including flags, compact lists, and cell-level change masks.

    The plan does NOT hold DDF data -- that must be read from ``LBMField``
    at sync time.  Keeping the plan free of large array copies makes it
    cheap to construct and discard.

Change masks use D2Q9 neighbour offsets.  D3Q19 support would require
extending ``released_fluid_mask`` neighbour enumeration.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import List

import numpy as np

from .objects import SimObject


@dataclass
class BodySyncPlan:
    """Topology transition plan produced by ``ObjectManager.build_sync_plan()``.

    Attributes:
        next_objects: New formal object list with ``obj_id = 0..n-1``.
        next_count: Length of *next_objects*.
        next_flags: Merged uint16 flag array for the new topology.
        curved_host: 8-tuple of SoA arrays for CurvedLinkSoA.assign_host().
        sensor_host: 2-tuple (cells, obj_id) for SensorSoA.assign_host().
        force_region_host: 2-tuple (cells, obj_id) for ForceRegionSoA.assign_host().
        added_solid_mask: Bool array -- True where ``old_fluid -> new_solid``.
        released_fluid_mask: Bool array -- True where ``old_obstacle -> new_fluid``.
        new_sensor_counts: Int array of sensor cell counts per object.
    """
    next_objects: List[SimObject]
    next_count: int
    next_flags: np.ndarray
    curved_host: tuple
    sensor_host: tuple
    force_region_host: tuple
    added_solid_mask: np.ndarray
    released_fluid_mask: np.ndarray
    new_sensor_counts: np.ndarray
