//! Image primitive - embedded image
//!
//! Uses 5 data-coordinate points: center + 4 edge points (top, right, bottom, left)

use super::super::{
    Primitive, PrimitiveColor, PrimitiveData, PrimitiveKind, PrimitiveMetadata, RenderContext,
    crisp,
};
use serde::{Deserialize, Serialize};

/// Image primitive with 5 data-coordinate anchor points
///
/// Points are stored as:
/// - center_bar, center_price: Center point
/// - radius_bars: Horizontal half-size in bars
/// - radius_price: Vertical half-size in price units
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Image {
    pub data: PrimitiveData,
    /// Center bar
    pub center_bar: f64,
    /// Center price
    pub center_price: f64,
    /// Horizontal radius in bars (distance from center to left/right edge)
    pub radius_bars: f64,
    /// Vertical radius in price units (distance from center to top/bottom edge)
    pub radius_price: f64,
    /// Image URL (data URL or http URL)
    pub url: String,
}

fn default_radius_bars() -> f64 {
    5.0
}
fn default_radius_price() -> f64 {
    100.0
}

impl Image {
    pub fn new(bar: f64, price: f64, color: &str) -> Self {
        Self {
            data: PrimitiveData {
                type_id: "image".to_string(),
                display_name: "Image".to_string(),
                color: PrimitiveColor::new(color),
                width: 1.0,
                ..Default::default()
            },
            center_bar: bar,
            center_price: price,
            radius_bars: default_radius_bars(),
            radius_price: default_radius_price(),
            url: String::new(),
        }
    }

    /// Create from center and edge point
    pub fn from_points(
        center_bar: f64,
        center_price: f64,
        edge_bar: f64,
        edge_price: f64,
        color: &str,
    ) -> Self {
        let radius_bars = (edge_bar - center_bar).abs().max(1.0);
        let radius_price = (edge_price - center_price).abs().max(1.0);
        let mut image = Self::new(center_bar, center_price, color);
        image.radius_bars = radius_bars;
        image.radius_price = radius_price;
        image
    }
}

impl Primitive for Image {
    fn type_id(&self) -> &'static str {
        "image"
    }
    fn display_name(&self) -> &str {
        &self.data.display_name
    }
    fn kind(&self) -> PrimitiveKind {
        PrimitiveKind::Annotation
    }
    fn data(&self) -> &PrimitiveData {
        &self.data
    }
    fn data_mut(&mut self) -> &mut PrimitiveData {
        &mut self.data
    }

    /// Returns 2 points: center and corner (for TwoPoint behavior)
    fn points(&self) -> Vec<(f64, f64)> {
        vec![
            (self.center_bar, self.center_price),
            (
                self.center_bar + self.radius_bars,
                self.center_price + self.radius_price,
            ),
        ]
    }

    fn set_points(&mut self, pts: &[(f64, f64)]) {
        if let Some(&(b, p)) = pts.first() {
            self.center_bar = b;
            self.center_price = p;
        }
        // Second point defines the corner (for TwoPoint creation)
        if let Some(&(b2, p2)) = pts.get(1) {
            self.radius_bars = (b2 - self.center_bar).abs().max(0.5);
            self.radius_price = (p2 - self.center_price).abs().max(1.0);
        }
    }

    fn translate(&mut self, bd: f64, pd: f64) {
        self.center_bar += bd;
        self.center_price += pd;
    }

    fn render(&self, ctx: &mut dyn RenderContext, _is_selected: bool) {
        let dpr = ctx.dpr();
        let cx = ctx.bar_to_x(self.center_bar);
        let cy = ctx.price_to_y(self.center_price);

        // Calculate screen-space half-sizes from data coordinates
        let half_w = (ctx.bar_to_x(self.center_bar + self.radius_bars) - cx).abs();
        let half_h = (ctx.price_to_y(self.center_price + self.radius_price) - cy).abs();

        // Top-left corner for image drawing
        let img_x = cx - half_w;
        let img_y = cy - half_h;
        let img_w = half_w * 2.0;
        let img_h = half_h * 2.0;

        // Try to draw the actual image if URL is set
        let image_drawn = if !self.url.is_empty() {
            ctx.draw_image(&self.url, img_x, img_y, img_w, img_h)
        } else {
            false
        };

        // Draw placeholder if image not loaded or no URL
        if !image_drawn {
            ctx.set_stroke_color(&self.data.color.stroke);
            ctx.set_stroke_width(1.0);
            ctx.stroke_rect(crisp(img_x, dpr), crisp(img_y, dpr), img_w, img_h);

            // Draw X through the rectangle to indicate image placeholder
            ctx.begin_path();
            ctx.move_to(crisp(img_x, dpr), crisp(img_y, dpr));
            ctx.line_to(crisp(img_x + img_w, dpr), crisp(img_y + img_h, dpr));
            ctx.move_to(crisp(img_x + img_w, dpr), crisp(img_y, dpr));
            ctx.line_to(crisp(img_x, dpr), crisp(img_y + img_h, dpr));
            ctx.stroke();
        }
    }

    fn to_json(&self) -> String {
        serde_json::to_string(self).unwrap_or_default()
    }
    fn clone_box(&self) -> Box<dyn Primitive> {
        Box::new(self.clone())
    }
}

pub fn metadata() -> PrimitiveMetadata {
    PrimitiveMetadata {
        type_id: "image",
        display_name: "Image",
        kind: PrimitiveKind::Annotation,
        factory: |points, color| {
            let (b, p) = points.first().copied().unwrap_or((0.0, 100.0));
            Box::new(Image::new(b, p, color))
        },
        supports_text: true,
        has_levels: false,
        has_points_config: false,
    }
}
