"""Frozen geometry and sign primitives derived from Celeris source.

No branch is called a cloak until the action-reversal CFD oracle is reviewed.
Coordinates are lattice/Cartesian: x right, y up.
"""
from __future__ import annotations
from dataclasses import dataclass
import numpy as np


def wall_velocity(omega: float, rx: float, ry: float) -> tuple[float, float]:
    """Celeris curved-wall law: (Uw,Vw)=(-omega*ry, omega*rx)."""
    return (-float(omega) * float(ry), float(omega) * float(rx))


@dataclass(frozen=True)
class CanonicalContract:
    diameter: float = 20.0
    u_inf: float = 0.01
    re_d: float = 50.0
    half_height_d: float = 15.0
    upstream_d: float = 50.0
    downstream_d: float = 50.0
    rear_dx_d: float = 1.3
    rear_dy_d: float = 0.75
    primary_station_d: float = 10.0

    @property
    def radius(self) -> float: return self.diameter / 2.0
    @property
    def viscosity(self) -> float: return self.u_inf * self.diameter / self.re_d
    @property
    def nx(self) -> int: return int(round((self.upstream_d + self.downstream_d) * self.diameter))
    @property
    def ny(self) -> int: return int(round(2.0 * self.half_height_d * self.diameter))
    @property
    def center_y(self) -> float: return (self.ny - 1.0) / 2.0
    @property
    def centers(self) -> tuple[tuple[float,float], ...]:
        x0 = self.upstream_d * self.diameter
        return ((x0, self.center_y),
                (x0 + self.rear_dx_d*self.diameter, self.center_y + self.rear_dy_d*self.diameter),
                (x0 + self.rear_dx_d*self.diameter, self.center_y - self.rear_dy_d*self.diameter))
    @property
    def body_order(self) -> tuple[str,...]: return ("front", "rear_y_plus", "rear_y_minus")

    def omega_from_s(self, s: float) -> float:
        return float(s) * self.u_inf / self.radius

    def action(self, s: float, branch: str) -> np.ndarray:
        o = self.omega_from_s(s)
        if branch == "plus-minus": return np.array([0.0, +o, -o])
        if branch == "minus-plus": return np.array([0.0, -o, +o])
        raise ValueError("branch must be 'plus-minus' or 'minus-plus'")

    def oracle(self, s: float = 1.0) -> dict:
        """Explicit outer/gap cardinal-point velocities for both branches."""
        out = {"schema": "steady-pinball-sign-oracle/v1", "coordinates": "x-right_y-up"}
        for branch in ("plus-minus", "minus-plus"):
            a = self.action(s, branch)
            # y+ rear: outer is top (ry=+R), gap-facing is bottom (ry=-R).
            # y- rear: outer is bottom (ry=-R), gap-facing is top (ry=+R).
            out[branch] = {
                "action": a.tolist(),
                "rear_y_plus_outer_top": wall_velocity(a[1], 0.0, +self.radius),
                "rear_y_plus_gap_bottom": wall_velocity(a[1], 0.0, -self.radius),
                "rear_y_minus_outer_bottom": wall_velocity(a[2], 0.0, -self.radius),
                "rear_y_minus_gap_top": wall_velocity(a[2], 0.0, +self.radius),
            }
        return out
