use crate::codec::ron::Ron;
use crate::codec::ron::RonEncoded;
use crate::models::{self};
use leptos::prelude::Get;
use leptos::prelude::Signal;
use leptos::server::Resource;
use server_fn::ServerFnError;
use std::collections::BTreeMap;

type RonResource<T> = Resource<Result<T, ServerFnError>, Ron>;

pub fn wall_by_uid(wall_uid: Signal<models::WallUid>) -> RonResource<models::Wall> {
    Resource::new_with_options(
        move || wall_uid.get(),
        move |wall_uid| async move { crate::server_functions::get_wall_by_uid(wall_uid).await.map(RonEncoded::into_inner) },
        false,
    )
}

/// Returns user interaction for a single problem
pub fn user_interaction(wall_uid: Signal<models::WallUid>, problem: Signal<Option<models::Problem>>) -> RonResource<Option<models::UserInteraction>> {
    Resource::new_with_options(
        move || (wall_uid.get(), problem.get()),
        move |(wall_uid, problem)| async move {
            let Some(problem) = problem else {
                return Ok(None);
            };
            crate::server_functions::get_user_interaction(wall_uid, problem)
                .await
                .map(RonEncoded::into_inner)
        },
        false,
    )
}

/// Returns all user interactions for a wall
pub fn user_interactions_for_wall(wall_uid: Signal<models::WallUid>) -> RonResource<BTreeMap<models::Problem, models::UserInteraction>> {
    Resource::new_with_options(
        move || wall_uid.get(),
        move |wall_uid| async move {
            crate::server_functions::get_user_interactions_for_wall(wall_uid)
                .await
                .map(RonEncoded::into_inner)
        },
        false,
    )
}
