use dioxus_native_core::real_dom::NodeImmutable;
use freya_dom::prelude::DioxusNode;
use freya_engine::prelude::*;
use freya_node_state::{BorderAlignment, BorderStyle, Fill, References, ShadowPosition, Style};
use torin::prelude::Area;
pub fn render_rect(
    area: &Area,
    node_ref: &DioxusNode,
    canvas: &mut Canvas,
    font_collection: &FontCollection,
) {
    let node_style = &*node_ref.get::<Style>().unwrap();
    let mut paint = Paint::default();
    let mut path = Path::new();
    let area = area.to_f32();
    paint.set_anti_alias(true);
    paint.set_style(PaintStyle::Fill);
    let area = area.to_f32();
    match &node_style.background {
        Fill::Color(color) => {
            paint.set_color(*color);
        }
        Fill::LinearGradient(gradient) => {
            paint.set_shader(gradient.into_shader(area));
        }
    }
    let radius = node_style.corner_radius;
    let rounded_rect = RRect::new_rect_radii(
        Rect::new(area.min_x(), area.min_y(), area.max_x(), area.max_y()),
        &[
            (radius.top_left, radius.top_left).into(),
            (radius.top_right, radius.top_right).into(),
            (radius.bottom_right, radius.bottom_right).into(),
            (radius.bottom_left, radius.bottom_left).into(),
        ],
    );
    if node_style.corner_radius.smoothing > 0.0 {
        path.add_path(
            &node_style.corner_radius.smoothed_path(rounded_rect),
            (area.min_x(), area.min_y()),
            None,
        );
    } else {
        path.add_rrect(rounded_rect, None);
    }
    canvas.draw_path(&path, &paint);
    for shadow in node_style.shadows.iter() {
        if shadow.fill != Fill::Color(Color::TRANSPARENT) {
            let mut shadow_paint = paint.clone();
            let mut shadow_path = Path::new();
            match &shadow.fill {
                Fill::Color(color) => {
                    shadow_paint.set_color(*color);
                }
                Fill::LinearGradient(gradient) => {
                    shadow_paint.set_shader(gradient.into_shader(area));
                }
            }
            let outset: Point = match shadow.position {
                ShadowPosition::Normal => {
                    shadow_paint.set_style(PaintStyle::Fill);
                    (shadow.spread, shadow.spread).into()
                }
                ShadowPosition::Inset => {
                    shadow_paint.set_style(PaintStyle::Stroke);
                    shadow_paint.set_stroke_width(shadow.blur / 2.0 + shadow.spread);
                    (-shadow.spread / 2.0, -shadow.spread / 2.0).into()
                }
            };
            if shadow.blur > 0.0 {
                shadow_paint.set_mask_filter(MaskFilter::blur(
                    BlurStyle::Normal,
                    shadow.blur / 2.0,
                    false,
                ));
            }
            if node_style.corner_radius.smoothing > 0.0 {
                shadow_path.add_path(
                    &node_style
                        .corner_radius
                        .smoothed_path(rounded_rect.with_outset(outset)),
                    Point::new(area.min_x(), area.min_y()) - outset,
                    None,
                );
            } else {
                shadow_path.add_rrect(rounded_rect.with_outset(outset), None);
            }
            shadow_path.offset((shadow.x, shadow.y));
            canvas.save();
            canvas.clip_path(
                &path,
                match shadow.position {
                    ShadowPosition::Normal => ClipOp::Difference,
                    ShadowPosition::Inset => ClipOp::Intersect,
                },
                true,
            );
            canvas.draw_path(&shadow_path, &shadow_paint);
            canvas.restore();
        }
    }
    if node_style.border.width > 0.0 && node_style.border.style != BorderStyle::None {
        let mut border_paint = paint.clone();
        let mut border_path = Path::new();
        border_paint.set_anti_alias(true);
        border_paint.set_style(PaintStyle::Stroke);
        match &node_style.border.fill {
            Fill::Color(color) => {
                border_paint.set_color(*color);
            }
            Fill::LinearGradient(gradient) => {
                border_paint.set_shader(gradient.into_shader(area));
            }
        }
        border_paint.set_stroke_width(node_style.border.width);
        let outset = Point::new(node_style.border.width / 2.0, node_style.border.width / 2.0)
            * match node_style.border.alignment {
                BorderAlignment::Center => 0.0,
                BorderAlignment::Inner => -1.0,
                BorderAlignment::Outer => 1.0,
            };
        if node_style.corner_radius.smoothing > 0.0 {
            border_path.add_path(
                &node_style
                    .corner_radius
                    .smoothed_path(rounded_rect.with_outset(outset)),
                Point::new(area.min_x(), area.min_y()) - outset,
                None,
            );
        } else {
            border_path.add_rrect(rounded_rect.with_outset(outset), None);
        }
        canvas.draw_path(&border_path, &border_paint);
    }
    let references = node_ref.get::<References>().unwrap();
    if let Some(canvas_ref) = &references.canvas_ref {
        (canvas_ref.runner)(canvas, font_collection, area);
    }
}