from pydantic import Field

from common.message import Message, Pose


class PirSensorConfig(Message):
    """
    Configuration for PIR (Passive Infrared) motion sensor.

    PIR sensors detect infrared radiation changes caused by moving warm objects.
    The sensor uses a dual-element design with interleaved zones for motion detection.
    """

    # Core sensor parameters
    update_rate_hz: float = Field(default=10.0, description="Sensor update frequency in Hz")
    max_range: float = Field(default=12.0, description="Maximum detection range in meters")

    # Field of view
    horiz_fov_deg: float = Field(default=90.0, description="Horizontal field of view in degrees")
    vert_fov_deg: float = Field(default=60.0, description="Vertical field of view in degrees")

    # Sensing elements
    num_elements: int = Field(default=2, description="Number of sensing elements (typically 2)")
    rays_per_h: int = Field(default=64, description="Number of rays in horizontal direction")
    rays_per_v: int = Field(default=16, description="Number of rays in vertical direction")

    # DSP / electronics parameters
    gain: float = Field(default=0.01, description="Amplifier gain")
    hp_corner_hz: float = Field(default=0.1, description="High-pass filter corner frequency in Hz")
    lp_corner_hz: float = Field(default=10.0, description="Low-pass filter corner frequency in Hz")

    hold_time_s: float = Field(default=2.0, description="Detection hold time in seconds")

    # Lens parameters
    lens_transmission: float = Field(default=0.9, description="Lens transmission coefficient (0-1)")
    lens_segments_h: int = Field(default=8, description="Number of horizontal lens segments for interleaved pattern")

    # Environment parameters
    ambient_temp_c: float = Field(default=20.0, description="Ambient temperature in Celsius")

    # Hard-coded theshold (if not none) overrides auto-calibration
    threshold: float | None = Field(default=None, description="Detection threshold (auto-calibrated if None)")
    threshold_scale: float = Field(default=1.0, description="Scale factor applied to auto-calibrated threshold")

    # Auto-threshold calibration parameters
    target_delta_t: float = Field(default=10.0, description="Target temperature difference for threshold calibration in Celsius")
    target_distance: float = Field(default=5.0, description="Target distance for threshold calibration in meters")
    target_emissivity: float = Field(default=0.98, description="Target emissivity for threshold calibration")


class GetPirSensor(Message):
    """
    Get an existing PIR sensor.
    """

    path: str | None = Field(default=None, description="USD path of the PIR sensor prim")


class GetPirSensorResponse(Message):
    """
    Response from getting a PIR sensor.
    """

    path: str


class AddPirSensor(Message):
    """
    Add a PIR sensor.
    """

    path: str = Field(description="USD path for the PIR sensor")
    config: PirSensorConfig = Field(default_factory=PirSensorConfig)
    world_pose: Pose | None = Field(default=None, description="World pose (position and orientation)")
    local_pose: Pose | None = Field(default=None, description="Local pose (translation and orientation)")


class GetPirDetectionStatus(Message):
    """
    Get PIR sensor detection status.
    """

    path: str


class SetPirDebugMode(Message):
    """
    Enable or disable debug visualization for a PIR sensor.
    """

    path: str
    enabled: bool = Field(description="Whether to enable debug ray visualization")


class SetPirMaterial(Message):
    """
    Set PIR-specific thermal properties on a prim.

    These properties define how the prim appears to PIR sensors.
    """

    path: str = Field(description="USD path of the prim to configure")
    emissivity: float = Field(default=0.9, description="Material emissivity (0-1)")
    temperature_c: float | None = Field(default=None, description="Surface temperature in Celsius")
