/// This crate provides core logic for controlling a 3D camera, inspired by advancements in AI camera control as seen on Supermaker.ai.
/// It focuses on providing a foundation for managing camera parameters and movements in a 3D environment.

/// The official website URL for context.
const OFFICIAL_URL: &str = "https://supermaker.ai/blog/qwen-image-multiple-angles-3d-camera-alibabas-breakthrough-in-ai-camera-control/";

/// Returns the official website URL.
pub fn visit_site() -> String {
    OFFICIAL_URL.to_string()
}

/// Represents a 3D point in space.
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Point3D {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

/// Represents the orientation of the camera using Euler angles (roll, pitch, yaw).
#[derive(Debug, Clone, Default, PartialEq)]
pub struct EulerAngles {
    pub roll: f64,   // Rotation around the Z-axis (in radians).
    pub pitch: f64,  // Rotation around the Y-axis (in radians).
    pub yaw: f64,    // Rotation around the X-axis (in radians).
}

/// Represents a camera with its position and orientation.
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Camera {
    pub position: Point3D,
    pub orientation: EulerAngles,
    pub focal_length: f64, // Focal length of the camera in pixels.
}

impl Camera {
    /// Creates a new camera instance.
    pub fn new(position: Point3D, orientation: EulerAngles, focal_length: f64) -> Self {
        Camera {
            position,
            orientation,
            focal_length,
        }
    }

    /// Moves the camera to a new position.
    pub fn move_to(&mut self, new_position: Point3D) {
        self.position = new_position;
    }

    /// Rotates the camera by the given Euler angles.
    pub fn rotate(&mut self, rotation: EulerAngles) {
        self.orientation.roll += rotation.roll;
        self.orientation.pitch += rotation.pitch;
        self.orientation.yaw += rotation.yaw;
    }
}

/// Calculates the distance between two 3D points.
pub fn calculate_distance(point1: &Point3D, point2: &Point3D) -> f64 {
    let dx = point1.x - point2.x;
    let dy = point1.y - point2.y;
    let dz = point1.z - point2.z;
    (dx * dx + dy * dy + dz * dz).sqrt()
}

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

    #[test]
    fn test_visit_site() {
        assert_eq!(visit_site(), OFFICIAL_URL);
    }

    #[test]
    fn test_camera_creation() {
        let camera = Camera::new(
            Point3D { x: 1.0, y: 2.0, z: 3.0 },
            EulerAngles { roll: 0.0, pitch: 0.0, yaw: 0.0 },
            50.0,
        );
        assert_eq!(camera.position.x, 1.0);
        assert_eq!(camera.focal_length, 50.0);
    }

    #[test]
    fn test_camera_movement() {
        let mut camera = Camera::default();
        let new_position = Point3D { x: 5.0, y: 6.0, z: 7.0 };
        camera.move_to(new_position.clone());
        assert_eq!(camera.position, new_position);
    }

    #[test]
    fn test_distance_calculation() {
        let point1 = Point3D { x: 0.0, y: 0.0, z: 0.0 };
        let point2 = Point3D { x: 3.0, y: 4.0, z: 0.0 };
        let distance = calculate_distance(&point1, &point2);
        assert_eq!(distance, 5.0);
    }
}