use ruin_app::prelude::*;

#[ruin_runtime::async_main]
async fn main() -> ruin_app::Result<()> {
    App::new()
        .window(
            Window::new()
                .title("RUIN Async Data and Effects")
                .app_id("dev.ruin.async-data")
                .size(1080.0, 760.0),
        )
        .mount(view! {
            AsyncDataAndEffectsDemo() {}
        })
        .run()
        .await
}

#[component]
fn AsyncDataAndEffectsDemo() -> impl IntoView {
    let selected_path = use_signal(|| "Cargo.toml".to_string());
    let reload_nonce = use_signal(|| 0_u64);
    let preview_scroll = use_signal(|| 0.0_f32);

    let file_contents = use_resource({
        let selected_path = selected_path.clone();
        let reload_nonce = reload_nonce.clone();
        move || {
            let path = selected_path.get();
            let _ = reload_nonce.get();
            async move {
                ruin_runtime::fs::read_to_string(&path)
                    .await
                    .map_err(|error| error.to_string())
            }
        }
    });

    use_effect({
        let selected_path = selected_path.clone();
        let reload_nonce = reload_nonce.clone();
        move || {
            eprintln!(
                "async resource dependencies changed: path={}, reload={}",
                selected_path.get(),
                reload_nonce.get()
            );
        }
    });

    use_effect({
        let selected_path = selected_path.clone();
        let reload_nonce = reload_nonce.clone();
        let preview_scroll = preview_scroll.clone();
        move || {
            let _ = selected_path.get();
            let _ = reload_nonce.get();
            let _ = preview_scroll.set(0.0);
        }
    });

    use_window_title({
        let selected_path = selected_path.clone();
        move || format!("RUIN Async Demo ({})", selected_path.get())
    });

    view! {
        column(gap = 16.0, padding = 24.0) {
            text(role = TextRole::Heading(1), size = 32.0, weight = FontWeight::Semibold) {
                "Async data and effects"
            }

            text(color = colors::muted(), wrap = TextWrap::Word) {
                "This is a smaller truthful slice of example 01: local signals drive a real async \
                 resource, and an effect logs the dependency changes."
            }

            FileControls(selected_path = selected_path.clone(), reload_nonce = reload_nonce.clone()) {}

            block(
                padding = 16.0,
                gap = 10.0,
                background = surfaces::raised(),
                border_radius = 12.0,
            ) {
                text(size = 18.0) { "selected = "; selected_path.clone() }

                match file_contents.read() {
                    Pending => view! {
                        text(color = colors::muted()) {
                            "Loading file contents..."
                        }
                    },
                    Ready(Ok(contents)) => view! {
                        column(background = surfaces::raised(), gap = 10.0) {
                            text() { "bytes = "; contents.len() }

                            scroll_box(
                                height = 420.0,
                                offset_y = preview_scroll.clone(),
                                padding = 12.0,
                                background = surfaces::canvas(),
                                border_radius = 10.0,
                                border = (2.0, colors::muted()),
                            ) {
                                text(
                                    color = colors::muted(),
                                    font_family = TextFontFamily::Monospace,
                                ) {
                                    contents
                                }
                            }
                        }
                    },
                    Ready(Err(error)) => view! {
                        text(color = colors::danger()) { error.to_string() }
                    },
                }
            }
        }
    }
}

#[component]
fn FileControls(selected_path: Signal<String>, reload_nonce: Signal<u64>) -> impl IntoView {
    view! {
        row(gap = 8.0) {
            button(
                on_press = {
                    let selected_path = selected_path.clone();
                    move |_| {
                        let _ = selected_path.set("Cargo.toml".to_string());
                    }
                },
            ) {
                "Cargo.toml"
            }

            button(
                on_press = {
                    let selected_path = selected_path.clone();
                    move |_| {
                        let _ = selected_path.set("Cargo.lock".to_string());
                    }
                },
            ) {
                "Cargo.lock"
            }

            button(
                on_press = {
                    let reload_nonce = reload_nonce.clone();
                    move |_| {
                        reload_nonce.update(|value| *value += 1);
                    }
                },
            ) {
                "Reload"
            }
        }
    }
}
