//! `gimbal_controller` — ViewPro A40 UDP control + smooth-pan primitive.
//!
//! Real implementation lands in:
//! - AZ-653 `gimbal_a40_transport`
//! - AZ-654 `gimbal_zoom_out_sweep`
//! - AZ-655 `gimbal_smooth_pan_plan`
//! - AZ-656 `gimbal_centre_on_target`

use serde::{Deserialize, Serialize};
use tokio::sync::watch;

use shared::error::{AutopilotError, Result};
use shared::health::ComponentHealth;
use shared::models::gimbal::GimbalState;

const NAME: &str = "gimbal_controller";

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct GimbalCommand {
    pub yaw_deg: f32,
    pub pitch_deg: f32,
}

pub struct GimbalController {
    state_tx: watch::Sender<GimbalState>,
}

impl GimbalController {
    pub fn new(initial: GimbalState) -> Self {
        let (state_tx, _rx) = watch::channel(initial);
        Self { state_tx }
    }

    pub fn handle(&self) -> GimbalControllerHandle {
        GimbalControllerHandle {
            state_tx: self.state_tx.clone(),
        }
    }
}

#[derive(Clone)]
pub struct GimbalControllerHandle {
    state_tx: watch::Sender<GimbalState>,
}

impl GimbalControllerHandle {
    pub async fn set_pose(&self, _command: GimbalCommand) -> Result<()> {
        Err(AutopilotError::NotImplemented(
            "gimbal_controller::set_pose (AZ-653)",
        ))
    }

    pub async fn zoom(&self, _level: f32) -> Result<()> {
        Err(AutopilotError::NotImplemented(
            "gimbal_controller::zoom (AZ-654)",
        ))
    }

    pub fn state(&self) -> GimbalState {
        *self.state_tx.borrow()
    }

    pub fn state_stream(&self) -> watch::Receiver<GimbalState> {
        self.state_tx.subscribe()
    }

    pub fn health(&self) -> ComponentHealth {
        ComponentHealth::disabled(NAME)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_compiles() {
        let initial = GimbalState {
            yaw: 0.0,
            pitch: 0.0,
            zoom: 1.0,
            ts_monotonic_ns: 0,
            command_in_flight: false,
        };
        let h = GimbalController::new(initial).handle();
        assert_eq!(h.state().zoom, 1.0);
        assert_eq!(h.health().level, shared::health::HealthLevel::Disabled);
    }
}
