//! Aspirational RUIN app API for fine-grained reactivity and keyed layout islands.
//!
//! Intentionally non-compiling; this is a design sketch.

use ruin::prelude::*;

#[ruin_runtime::async_main]
async fn main() -> ruin::Result<()> {
    App::new()
        .window(Window::new().title("RUIN Tasks").size(1180.0, 780.0))
        .mount::<TaskBoard>()
        .run()
        .await
}

#[component]
fn TaskBoard() -> impl View {
    let filter = use_signal(|| TaskFilter::All);
    let tasks = use_signal_vec(seed_tasks());

    let visible_ids = use_memo(move || {
        tasks.iter()
            .filter(|task| filter.get().matches(task.status))
            .map(|task| task.id)
            .collect::<Vec<_>>()
    });

    view! {
        column(fill = true, gap = 16, padding = 20) {
            text(role = TextRole::Heading(1), size = 28, weight = FontWeight::Semibold) {
                "Task board"
            }

            row(gap = 8) {
                button(
                    kind = if matches!(filter.get(), TaskFilter::All) {
                        ButtonKind::Primary
                    } else {
                        ButtonKind::Secondary
                    },
                    on_press = move |_| filter.set(TaskFilter::All),
                ) { "All" }

                button(
                    kind = if matches!(filter.get(), TaskFilter::OpenOnly) {
                        ButtonKind::Primary
                    } else {
                        ButtonKind::Secondary
                    },
                    on_press = move |_| filter.set(TaskFilter::OpenOnly),
                ) { "Open" }

                button(
                    kind = if matches!(filter.get(), TaskFilter::CompletedOnly) {
                        ButtonKind::Primary
                    } else {
                        ButtonKind::Secondary
                    },
                    on_press = move |_| filter.set(TaskFilter::CompletedOnly),
                ) { "Completed" }
            }

            text(color = colors::muted()) {
                "The goal here is fine-grained change tracking: reordering, toggling, and editing \
                 a single row should not force unrelated rows to rebuild or the entire layout tree \
                 to be recomputed."
            }

            column(fill = true, gap = 10) {
                for task_id in visible_ids keyed by *task_id {
                    layout_boundary(key = task_id) {
                        TaskRow(task = tasks.item(task_id)) {}
                    }
                }
            }
        }
    }
}

#[component]
fn TaskRow(task: ItemSignal<Task>) -> impl View {
    let expanded = use_signal(|| false);
    let title = use_memo(move || task.with(|task| task.title.clone()));
    let done = use_memo(move || task.with(|task| task.done));

    view! {
        row(gap = 12, padding = 12, align = Align::Center) {
            checkblock(
                checked = done,
                on_toggle = move |checked| task.update(|task| task.done = checked),
            ) {}

            column(fill = true, gap = 6) {
                text(weight = if done.get() { FontWeight::Medium } else { FontWeight::Semibold }) {
                    title
                }

                if expanded.get() {
                    text(color = colors::muted()) {
                        task.with(|task| task.notes.clone())
                    }
                }
            }

            icon_button(
                icon = if expanded.get() { Icon::ChevronUp } else { Icon::ChevronDown },
                on_press = move |_| expanded.toggle(),
            ) {}
        }
    }
}

#[derive(Clone)]
struct Task {
    id: u64,
    title: String,
    notes: String,
    status: TaskStatus,
    done: bool,
}

#[derive(Clone, Copy)]
enum TaskStatus {
    Backlog,
    Doing,
    Done,
}

#[derive(Clone, Copy)]
enum TaskFilter {
    All,
    OpenOnly,
    CompletedOnly,
}

impl TaskFilter {
    fn matches(self, status: TaskStatus) -> bool {
        match self {
            TaskFilter::All => true,
            TaskFilter::OpenOnly => !matches!(status, TaskStatus::Done),
            TaskFilter::CompletedOnly => matches!(status, TaskStatus::Done),
        }
    }
}

fn seed_tasks() -> Vec<Task> {
    Vec::new()
}
