use std::cell::RefCell;
use std::rc::Rc;

use leptos::html::Canvas;
use leptos::*;
use wasm_bindgen::prelude::Closure;
use wasm_bindgen::JsCast;
use wasm_bindgen::JsValue;
use web_sys::window;

use crate::space_colonization::Node;
use crate::space_colonization::Point;
use crate::space_colonization::SpaceColonization;

#[component]
pub fn Background(cx: Scope, class: &'static str) -> impl IntoView {
    let canvas = create_node_ref::<Canvas>(cx);

    canvas.on_load(cx, move |_| {
        let canvas = canvas.get().expect("canvas is mounted");
        let canvas_parent = canvas.parent_element().unwrap();
        let width = canvas_parent.client_width();
        let height = canvas_parent.client_height();
        let window_width = u32::try_from(width).unwrap();
        let window_height = u32::try_from(height).unwrap();
        canvas.set_width(window_width);
        canvas.set_height(window_height);

        let context = canvas
            .get_context("2d")
            .ok()
            .flatten()
            .expect("canvas to have context")
            .unchecked_into::<web_sys::CanvasRenderingContext2d>();
        log!("context = {:#?}", context);
        context.set_stroke_style(&JsValue::from("white"));
        let context_to_render = context.clone();
        // let render_node_fn : 'a Fn(&Node, &Node)  = |n: &Node, child: &Node| {
        let render_node_fn = move |n: &Node, child: &Node| {
            context_to_render.move_to(n.position.x.into(), n.position.y.into());
            context_to_render.line_to(child.position.x.into(), child.position.y.into());
        };
        let mut sc = SpaceColonization::new(
            width.try_into().unwrap(),
            height.try_into().unwrap(),
            render_node_fn,
        );
        let nodes = Rc::new(RefCell::new(Vec::new()));
        {
            let mut nodesMut = nodes.borrow_mut();
            nodesMut.push(Node::new(Point::new((
                (window_width / 3) as i32,
                (window_height / 3) as i32,
            ))));
            nodesMut.push(Node::new(Point::new((
                (window_width / 2) as i32,
                (window_height / 3) as i32,
            ))));
            nodesMut.push(Node::new(Point::new((
                (window_width / 3) as i32,
                (window_height / 2) as i32,
            ))));
            nodesMut.push(Node::new(Point::new((
                (window_width - 200) as i32,
                (window_height / 3) as i32,
            ))));
            nodesMut.push(Node::new(Point::new((
                (window_width - 100) as i32,
                (window_height - 100) as i32,
            ))));
        }
        // TODO Resize on window resize
        log!(
            "TODO resize on window resize canvas parent size = {} {}",
            canvas_parent.client_width(),
            canvas_parent.client_height()
        );
        context.set_stroke_style(&JsValue::from("white"));

        context.set_fill_style(&JsValue::from("yellow"));
        log!("About to render nodes");
        let start_time = window().unwrap().performance().unwrap().now();
        context.begin_path();
        /*
        let render_node_fn = |n: &Node, child: &Node| {
            context.move_to(n.position.x.into(), n.position.y.into());
            context.line_to(child.position.x.into(), child.position.y.into());
        };
        */
        // let render_id = window().unwrap().performance().unwrap().now();
        // sc.render_all_nodes(&nodes.borrow(), render_id, render_node_fn);
        context.stroke();

        let end_time = window().unwrap().performance().unwrap().now();
        log!(
            "Rendering nodes and {} attractors took {}",
            sc.attractors.size(),
            end_time - start_time
        );
        let context = context.clone();
        let closure = Closure::<dyn FnMut(_)>::new(move |_: web_sys::MouseEvent| {
            let start_time = window().unwrap().performance().unwrap().now();
            {
                let mut nodesMut = nodes.borrow_mut();
                sc.grow(&mut nodesMut);
            }
            // let render_id = window().unwrap().performance().unwrap().now();
            // context.begin_path();
            // sc.render_nodes(&nodes.borrow(), render_id, render_node_fn);

            /*
            context.set_fill_style(&JsValue::from("magenta"));
            for a in sc.attractors.iter().filter(|a| a.dead) {
                context.fill_rect(a.position.x.into(), a.position.y.into(), 5.0, 5.0);
            }
            context.set_fill_style(&JsValue::from("red"));
            for a in sc.attractors.iter().filter(|a| !a.dead) {
                context.fill_rect(a.position.x.into(), a.position.y.into(), 5.0, 5.0);
            }
            */
            context.stroke();
            let end_time = window().unwrap().performance().unwrap().now();
            log!(
                "Rendering nodes and {} attractors took {}",
                sc.attractors.size(),
                end_time - start_time
            );
        });

        let window = window().unwrap();
        window
            .set_interval_with_callback_and_timeout_and_arguments_0(
               closure.as_ref().unchecked_ref(),
              30,
         )
         .unwrap();

        // window
        //     .add_event_listener_with_callback(
        //         "click",
        //         closure.as_ref().unchecked_ref(),
        //     )
        //     .unwrap();
        closure.forget();
    });

    let class = format!("canvas {}", class);
    view! { cx,
        <div class={class}>
            <canvas node_ref=canvas></canvas>
        </div>
    }
}
