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;

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,
    )
}

/// Version of [problem_by_uid] that short circuits if the input problem_uid signal is None.
pub fn problem_by_uid_optional(
    wall_uid: Signal<models::WallUid>,
    problem_uid: Signal<Option<models::ProblemUid>>,
) -> RonResource<Option<models::Problem>> {
    Resource::new_with_options(
        move || (wall_uid.get(), problem_uid.get()),
        move |(wall_uid, problem_uid)| async move {
            let Some(problem_uid) = problem_uid else {
                return Ok(None);
            };
            crate::server_functions::get_problem_by_uid(wall_uid, problem_uid)
                .await
                .map(RonEncoded::into_inner)
                .map(Some)
        },
        false,
    )
}

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

pub fn user_interaction(
    wall_uid: Signal<models::WallUid>,
    problem_uid: Signal<Option<models::ProblemUid>>,
) -> RonResource<Option<models::UserInteraction>> {
    Resource::new_with_options(
        move || (wall_uid.get(), problem_uid.get()),
        move |(wall_uid, problem_uid)| async move {
            let Some(problem_uid) = problem_uid else {
                return Ok(None);
            };
            crate::server_functions::get_user_interaction(wall_uid, problem_uid)
                .await
                .map(RonEncoded::into_inner)
        },
        false,
    )
}
