//! Coordinate conversion utilities for scene viewer.
//!
//! Handles conversions between:
//! - Scene coordinates (native scene dimensions)
//! - Canvas coordinates (scaled/offset for display)
//! - Viewport/client coordinates (browser window)

/// Coordinate transform state for converting between scene and canvas coordinates.
#[derive(Clone, Copy, Debug, Default)]
pub struct CoordinateTransform {
    pub scale_x: f64,
    pub scale_y: f64,
    pub offset_x: f64,
    pub offset_y: f64,
}

impl CoordinateTransform {
    /// Create a new transform with the given scale and offset values.
    pub fn new(scale_x: f64, scale_y: f64, offset_x: f64, offset_y: f64) -> Self {
        Self {
            scale_x,
            scale_y,
            offset_x,
            offset_y,
        }
    }

    /// Convert canvas coordinates to scene coordinates.
    pub fn canvas_to_scene(&self, canvas_x: f64, canvas_y: f64) -> (f64, f64) {
        if self.scale_x > 0.0 && self.scale_y > 0.0 {
            let scene_x = (canvas_x - self.offset_x) / self.scale_x;
            let scene_y = (canvas_y - self.offset_y) / self.scale_y;
            (scene_x, scene_y)
        } else {
            (0.0, 0.0)
        }
    }

    /// Convert scene coordinates to canvas coordinates.
    pub fn scene_to_canvas(&self, scene_x: f64, scene_y: f64) -> (f64, f64) {
        let canvas_x = scene_x * self.scale_x + self.offset_x;
        let canvas_y = scene_y * self.scale_y + self.offset_y;
        (canvas_x, canvas_y)
    }

    /// Clamp scene coordinates to scene bounds.
    pub fn clamp_to_scene(&self, x: f64, y: f64, scene_width: f64, scene_height: f64) -> (f64, f64) {
        (x.max(0.0).min(scene_width), y.max(0.0).min(scene_height))
    }

    /// Check if the transform has valid (non-zero) scales.
    pub fn is_valid(&self) -> bool {
        self.scale_x > 0.0 && self.scale_y > 0.0
    }
}

/// Calculate the aspect-ratio preserving scale and offset for fit mode.
///
/// Returns (draw_width, draw_height, offset_x, offset_y, scale_x, scale_y).
pub fn calculate_fit_transform(
    display_width: f64,
    display_height: f64,
    scene_width: f64,
    scene_height: f64,
) -> CoordinateTransform {
    if display_width == 0.0 || display_height == 0.0 {
        return CoordinateTransform::default();
    }

    let canvas_aspect = display_width / display_height;
    let scene_aspect = scene_width / scene_height;

    let (draw_width, draw_height, offset_x, offset_y) = if canvas_aspect > scene_aspect {
        // Canvas is wider than scene - letterbox on sides
        let h = display_height;
        let w = h * scene_aspect;
        let x = (display_width - w) / 2.0;
        (w, h, x, 0.0)
    } else {
        // Canvas is taller than scene - letterbox on top/bottom
        let w = display_width;
        let h = w / scene_aspect;
        let y = (display_height - h) / 2.0;
        (w, h, 0.0, y)
    };

    let scale_x = draw_width / scene_width;
    let scale_y = draw_height / scene_height;

    CoordinateTransform::new(scale_x, scale_y, offset_x, offset_y)
}

/// Calculate transform for pan mode (native resolution * zoom).
pub fn calculate_pan_transform(zoom: f64) -> CoordinateTransform {
    CoordinateTransform::new(zoom, zoom, 0.0, 0.0)
}
