use chrono::{Duration, Local, NaiveDate, NaiveTime, Timelike};
use leptos::*;
use leptos_captcha::{Captcha, pow_dispatch};
use leptos_router::*;
use rust_decimal::Decimal;
use crate::backend::appearance::get_appearance;
use crate::backend::customer::get_remembered;
use crate::backend::data::{ApiResponse, Customer, DayHour, Reservation, ResProperty, SlotType, TmCheck};
use crate::backend::reservation::{CreateReservation, get_public_form_data, is_reserved};
use crate::backend::user::get_pow;
use crate::components::data_form::ForValidation;
use crate::components::modal_box::DialogOpener;
use crate::locales::trl;
use crate::pages::res_dialogs::{ResError, ResSaved};
use crate::validator::Validator;

#[component]
fn time_selector(
    hours: Vec<DayHour>,
    reservations: Vec<Reservation>,
    property: ResProperty,
    slots: RwSignal<Vec<String>>,
    price: RwSignal<Decimal>) -> impl IntoView {
    let checks = hours.into_iter().map(|h| {
        match property.slot {
            SlotType::Quarter => {
                let mut ret: Vec<TmCheck> = vec![];
                logging::log!("quarter");
                for n in 0..(h.to() - h.from()).num_minutes() * 4 / 60 {
                    ret.push(TmCheck {
                        from: h.from() + Duration::minutes(n * 15),
                        to: h.from() + Duration::minutes((n + 1) * 15)
                    });
                }
                ret
            }
            SlotType::Half => {
                let mut ret: Vec<TmCheck> = vec![];
                logging::log!("half");
                for n in 0..(h.to() - h.from()).num_minutes() * 2 / 60 {
                    ret.push(TmCheck {
                        from: h.from() + Duration::minutes(n * 30),
                        to: h.from() + Duration::minutes((n + 1) * 30)
                    });
                }
                ret
            }
            SlotType::Hour => {
                let mut ret: Vec<TmCheck> = vec![];
                for n in 0..(h.to() - h.from()).num_minutes() / 60 {
                    ret.push(TmCheck {
                        from: h.from() + Duration::minutes(n * 60),
                        to: h.from() + Duration::minutes((n + 1) * 60)
                    });
                }
                ret
            }
            SlotType::Day => {
                let mut ret: Vec<TmCheck> = vec![];
                ret.push(TmCheck {
                    from: NaiveTime::from_hms_opt(0,0,0).unwrap(),
                    to: NaiveTime::from_hms_opt(23, 59, 59).unwrap()
                });
                ret
            }
        }
    }).collect::<Vec<_>>().into_iter().flatten().collect::<Vec<_>>();

    let prop_id = property.id();
    let closed = checks.is_empty();
    view! {
        <For each=move || checks.clone() key=|c| c.from.minute() let:data>
            <input type="checkbox"
                class="btn-check"
                id={data.from.to_string() + &property.name.clone()}
                autocomplete="off"
                disabled={is_reserved(&reservations, &data.from, prop_id)}
                on:change= move |ev| {
                let mut sl = slots.get();
                if event_target_checked(&ev) {
                    sl.push(data.from.to_string() + "-" + &data.to.to_string() + "|" + &prop_id.to_string());
                    price.set(price.get() + property.price);
                    slots.set(sl);
                } else {
                    slots.set(sl.into_iter().filter(|s| { s.clone() != (data.from.to_string() + "-" + &data.to.to_string() + "|" + &prop_id.to_string())}).collect());
                    price.set(price.get() - property.price);
                }
            }/>
            <label class="btn btn-outline-primary" for={data.from.to_string() + &property.name.clone()}>{data.from.format("%H:%M").to_string()}</label>
        </For>
        <Show when=move || closed>
            <div class="fs-3">{trl("Closed")}</div>
        </Show>
    }
}

#[component]
pub fn Public() -> impl IntoView {
    let day = create_rw_signal(NaiveDate::default());
    let form_data = create_blocking_resource(move || day.get(), move |d| get_public_form_data(d));
    let slots = create_rw_signal::<Vec<String>>(vec![]);
    let price = create_rw_signal(Decimal::from(0));
    let cr_reservation = create_server_action::<CreateReservation>();
    let validator = Validator::new();
    let invalid_dlg = DialogOpener::new();
    let result_dlg = DialogOpener::new();
    let result = cr_reservation.value();
    let is_pending = create_rw_signal(None);
    let active_str = create_rw_signal("true".to_string());
    let get_customer = create_blocking_resource(||(), move |_| get_remembered());
    let appearance = create_blocking_resource(||(), move |_| get_appearance());
    let customer = create_rw_signal(Customer::default());

    create_effect(move |_| {
        day.set(Local::now().date_naive());
    });

    view! {
        <ResError opener=invalid_dlg validator=validator/>
        <ResSaved opener=result_dlg
            save_result=result
            day=day
            price=price.write_only()
            slots=slots.write_only()
            captcha_state=is_pending.read_only()/>

        <Transition fallback=move || view! {<p>{trl("Loading...")}</p> }>
        {
            appearance.get().map(|a| match a {
                Ok(a) => {
                let app = a.clone();
                view! {
                    <div>
                        <Show when=move || a.clone().banner.is_some()>
                            <div class="header_banner">
                                <h1 class="header_banner">{app.title.clone().unwrap_or_default()}</h1>
                            </div>
                        </Show>
                        <div>
                            <div class="header_banner_text" inner_html={app.text.unwrap_or("".to_string())}>

                            </div>
                        </div>
                    </div>
                }
                },
                Err(e) => {view! {<div><p>{trl("Error loading data")}</p>
                            <p>{e.to_string()}</p></div>
                        }}
            })
        }
        </Transition>

    <div class="card-body">
        <ActionForm
            on:submit=move |ev| {
                cr_reservation.set_pending(true);
                if let Ok(mut act) = CreateReservation::from_event(&ev) {
                    validator.check(act.entity(), &ev);

                    if !validator.is_valid() {
                        invalid_dlg.show();
                    } else {
                        ev.prevent_default();
                        pow_dispatch(get_pow, is_pending, move |pow| {
                            act.pow = pow.unwrap();
                            cr_reservation.dispatch(act);
                        });
                        result_dlg.show();
                    }
                }
            }
            action=cr_reservation>
        <div class="row mb-5">
            <div class="col-md">
                <div class="card mb-3">
                    <div class="card-body">
                    <h5 class="card-title"><i class="bx bx-basket"></i>" "{trl("Booking")}</h5>
                    <div class="row">
                        <div class="col mb-3">
                            <label  for="date" class="form-label">{trl("Date")}</label>
                            <input
                                type="date"
                                id="date"
                                class="form-control"
                                prop:value={move || day.get().format("%Y-%m-%d").to_string()}
                                on:input=move |ev| {
                                    price.set(Decimal::from(0));
                                    slots.set(vec![]);
                                    day.set(NaiveDate::parse_from_str(&event_target_value(&ev), "%Y-%m-%d").unwrap());
                                }
                                name="reservation[date]"
                            />
                        </div>
                    </div>
                    <Transition fallback=|| view! {<p>{trl("Loading...")}</p> }>
        {move || {
            get_customer.get().map(|c| match c {
                Err(_) => {},
                Ok(c) => {
                    if let Some(c) = c {
                        customer.set(c);
                    }
                }
            });
                    form_data.get().map(|u| match u {
                    Err(e) => {
                        view! {<div>{e.to_string()}</div>}}
                    Ok(u) => {
                        match u {
                            ApiResponse::Data(p) => {
                            view! {
                            <div>
                            <For each=move || p.clone()
                                            key=|prop| prop.property.id()
                                            let:data>
                                <div class="row">
                                    <div class="col mb-3">
                                        <div class="form-label">{data.property.name.clone()}</div>
                                            <div>
                                                <TimeSelector
                                                    hours={data.hours.clone()}
                                                    reservations={data.reservations.clone()}
                                                    property={data.property.clone()}
                                                    slots={slots}
                                                    price={price}/>
                                            </div>
                                    </div>
                                </div>
                            </For>
                            <For each=move || slots.get()
                                key=|s| s.clone()
                                let:data>
                                <input type="hidden"
                                    name="reservation[slots][]"
                                    value={data}/>
                            </For>
                            </div>
                            }
                        },
                        ApiResponse::Error(s) => {
                            view! {<div>{trl(&s)}</div>}
                        }
                    }}
                })
            }}
                    </Transition>
                        <div class="form-label">{trl("Total price of booking")}</div>
                        <div>{move || format!("{} Kč", price.get())}</div>
                    </div>
                </div>
            </div>
            <div class="col-md">
                <div class="card mb-3">
                    <div class="card-body">
                    <h5 class="card-title"><i class="bx bxs-contact"></i>" "{trl("Who is booking")}</h5>
                    <div class="row">
                        <div class="col mb-3">
                            <label  for="full_name" class="form-label">{trl("Full name")}</label>
                            <input
                                type="text"
                                id="full_name"
                                class="form-control"
                                placeholder={trl("Enter full name")}
                                prop:value={move || customer.get().full_name}
                                name="reservation[full_name]"
                            />
                        </div>
                    </div>
                    <div class="row">
                        <div class="col mb-3">
                            <label  for="email" class="form-label">"Email"</label>
                            <input
                                type="text"
                                id="email"
                                class="form-control"
                                placeholder={trl("Enter e-mail address")}
                                prop:value={move || customer.get().email}
                                name="reservation[email]"
                            />
                        </div>
                    </div>
                    <div class="row">
                        <div class="col mb-3">
                            <label  for="phone" class="form-label">{trl("Phone number")}</label>
                            <input
                                type="text"
                                id="phone"
                                class="form-control"
                                placeholder={trl("Enter phone number")}
                                prop:value={move || customer.get().phone}
                                name="reservation[phone]"
                            />
                        </div>
                    </div>
                    <div class="row">
                        <div class="col mb-3">
                            <label  for="note" class="form-label">{trl("Note")}</label>
                            <input
                                type="text"
                                id="note"
                                class="form-control"
                                placeholder={trl("Enter note")}
                                //prop:value={move || opener.empty()}
                                name="reservation[note]"
                            />
                        </div>
                    </div>
                    <input
                        type="checkbox"
                        id="remember"
                        class="form-check-input"
                        checked="true"
                        on:change=move |ev| active_str.set(if event_target_checked(&ev)
                                    { "true".to_string() } else { "false".to_string() }) />
                    <label for="remember" class="form-label">{trl("Remember for next time")}</label>
                    <input type="hidden" prop:value=active_str name="reservation[remember]"/>
                    <Captcha is_pending />
                    <div class="modal-footer">
                        <button type="submit" class="btn btn-primary">
                            {trl("Book")}
                        </button>
                    </div>
                    </div>
                </div>
            </div>
        </div>
        </ActionForm>
    </div>
    }
}