use std::rc::Rc;
use heck::ToTitleCase;
use leptos::*;
use leptos_router::Router;
use magister::{ColorBalance, PlayerInitDescriptor, Game, GameCreationError};
use phosphor_leptos::Horse;
use crate::display::Player as PlayerDisplay;
#[component]
fn SubtypePlayer() -> impl IntoView {
use magister::card::Subtype;
let (subtype_str, set_subtype_str) = create_signal("".to_string());
let subtype = move || Subtype::new(subtype_str.get());
let (member, set_member) = create_signal(String::new());
let is_member = {
move || {
let member = member.get();
let subtype = subtype();
!member.is_empty()
&& member
.split_whitespace()
.all(|mem_sub| subtype.is_member(mem_sub))
}
};
let is_quasimember = {
move || {
let member = member.get();
let subtype = subtype();
!member.is_empty()
&& member
.split_whitespace()
.all(|mem_sub| subtype.is_quasimember(mem_sub))
}
};
view! {
<div class="w-1/2">
<label class="input input-bordered flex items-center gap-2">
<Horse size="24px"/>
<input
type="text"
class="grow"
placeholder="Subtype"
prop:value=move || subtype_str.get()
on:input=move |ev| set_subtype_str.set(event_target_value(&ev))
/>
</label>
<ul class="list-disc list-inside">
{move || {
subtype()
.subtypes()
.map(|st| view! { <li>{st.to_title_case()}</li> })
.collect_view()
}}
</ul>
<div class="join w-full flex">
<label class="input input-bordered flex items-center gap-2 join-item grow">
<input
type="text"
class="grow"
placeholder="Member?"
prop:value=move || member.get()
on:input=move |ev| set_member.set(event_target_value(&ev))
/>
</label>
<button class="btn join-item" on:click=move |_| set_member.update(|qm| qm.clear())>
"Clear"
</button>
</div>
<ul class="list-inside list-disc">
<li>
"Is Member? (“Search for a X card.”) "
<span
class=("text-error", move || !member.get().is_empty() && !is_member())
class=("text-primary", is_member)
>
{is_member}
</span>
</li>
<li>
"Is Quasimember? (“Search for a X or similar card.”) "
<span
class=("text-error", move || !member.get().is_empty() && !is_quasimember())
class=("text-primary", is_quasimember)
>
{is_quasimember}
</span>
</li>
<li>"Canonical Subtype: " {move || format!("`{}`", subtype())}</li>
<li>"Exact Subtype: " {move || format!("`{:?}`", subtype())}</li>
</ul>
</div>
}
}
#[tracing::instrument]
#[component]
pub fn App() -> impl IntoView {
let player_1_balance = ColorBalance::default();
let player_1_deck = vec![];
let player_1_guardians = vec![];
let player_2_balance = ColorBalance {
suffering: 3,
divine: 3,
..Default::default()
};
let player_2_deck = vec![];
let player_2_guardians = vec![];
let player_decks: Vec<PlayerInitDescriptor> = vec![
(player_1_balance, player_1_deck, player_1_guardians).into(),
(player_2_balance, player_2_deck, player_2_guardians).into(),
];
let player_decks_len = player_decks.len();
let dem_res = create_local_resource(
|| (),
|_| async {
let response = gloo_net::http::Request::get("/api/v0/clicked")
.send()
.await
.map_err(Rc::new)?;
let json = response.json::<Vec<Box<str>>>().await.map_err(Rc::new)?;
Ok::<_, Rc<gloo_net::Error>>(
json.into_iter()
.map(|s| Rc::from(s) as Rc<str>)
.collect::<Vec<_>>(),
)
},
);
let is_dem_res_error = move || dem_res.with(|res| res.as_ref().is_some_and(|res| res.is_err()));
let dem_res_data = move || {
if dem_res.loading().get() {
None
} else {
dem_res.with(|res| res.clone().and_then(|d| d.ok()))
}
};
let dem_res_error = move || {
if dem_res.loading().get() {
None
} else {
dem_res.with(|res| res.clone().and_then(|d| d.err()))
}
};
view! {
<GameProvider player_decks=player_decks>
<Router>
<h1 class="font-bold text-4xl">Hello</h1>
{(0..player_decks_len)
.map(|idx| view! { <PlayerDisplay index=idx/> })
.collect_view()}
<SubtypePlayer/>
<div class="flex w-1/2 items-center">
<Show
when=move || !is_dem_res_error() && !dem_res.loading().get()
fallback=move || {
view! {
<Show when=move || dem_res_error().is_some()>
<div class="text-error grow">
{move || format!("ERROR: {}", dem_res_error().unwrap())}
</div>
</Show>
}
}
>
<div class="grow">{move || dem_res_data().unwrap().join(", ")}</div>
</Show>
<button class="btn join-item" on:click=move |_| dem_res.refetch()>
"Reload"
</button>
</div>
</Router>
</GameProvider>
}
}
#[derive(Debug, Clone, Copy)]
pub struct GameReader(pub(crate) ReadSignal<Result<Game, GameCreationError>>);
#[derive(Debug, Clone, Copy)]
pub struct GameWriter(pub(crate) WriteSignal<Result<Game, GameCreationError>>);
#[tracing::instrument(skip(children, player_decks))]
#[component]
fn GameProvider(
#[prop(into)] player_decks: MaybeSignal<Vec<PlayerInitDescriptor>>,
children: Children,
) -> impl IntoView {
let (game, set_game) = create_signal(Game::new(player_decks.get()));
provide_context(GameReader(game));
provide_context(GameWriter(set_game));
tracing::info!("logging something for game use...");
children()
}