use crate::util::model::member::{Member, MembersMigration};
use dioxus::prelude::{dioxus_elements::FileEngine, *};
use std::sync::Arc;

#[derive(Debug)]
struct UploadedFile {
    name: String,
    contents: String,
}

#[derive(PartialEq)]
enum Steps {
    Upload,
    Verify,
    Done,
}

#[component]
pub fn Migration() -> Element {
    let step = use_signal(|| Steps::Upload);
    let members_migration = use_signal(|| (0, MembersMigration::new()));

    rsx! {
        div {
            class: "flex flex-col items-center justify-center py-10",
            ul {
                class: "steps pb-10",
                li { class: "step step-primary", "Uploaden" },
                li {
                    class: "step",
                    class: if let Steps::Verify | Steps::Done = *step.read() { { "step-primary" } },
                    "Controleren"
                },
                li {
                    class: "step",
                    class: if let Steps::Done = *step.read() { { "step-primary" } },
                    "Klaar"
                },
            },
            match *step.read() {
                Steps::Upload => rsx! { Upload { step: step, members_migration: members_migration } },
                Steps::Verify => rsx! { Verify { step: step, members_migration: members_migration } },
                Steps::Done => rsx! { Done {} },
            }
        }
    }
}

#[component]
fn Upload(step: Signal<Steps>, members_migration: Signal<(u16, MembersMigration)>) -> Element {
    let mut file_uploaded = use_signal(|| None);

    let mut loading = use_signal(|| false);

    let read_files = move |file_engine: Arc<dyn FileEngine>| async move {
        let files = file_engine.files();
        for file_name in &files {
            if let Some(contents) = file_engine.read_file_to_string(file_name).await {
                file_uploaded.set(Some(UploadedFile {
                    name: file_name.clone(),
                    contents,
                }));
            }
        }
    };

    let upload_files = move |evt: FormEvent| async move {
        if let Some(file_engine) = evt.files() {
            read_files(file_engine).await;
        }
    };

    let sumbit = move |_evt: FormEvent| async move {
        match &*file_uploaded.read() {
            Some(file) => {
                loading.set(true);

                if let Ok(response) = upload_members_list(file.contents.clone()).await {
                    members_migration.set(response);
                    step.set(Steps::Verify);
                    loading.set(false);
                }
                loading.set(false);
            }
            None => tracing::info!("File doesn't exists"),
        }
    };

    rsx! {
        form {
            class: "flex flex-col items-center w-full h-full max-w-md mx-auto px-2",
            onsubmit: sumbit,
            h2 { class: "text-xl mb-5", "Selecteer de ledenlijst" },
            input {
                r#type: "file",
                class: "file-input file-input-bordered w-full",
                accept: ".csv",
                multiple: false,
                autocomplete: "off",
                onchange: upload_files,
            }
            button {
                class: "btn btn-primary btn-wide mt-5",
                disabled: file_uploaded.read().is_none() || loading(),
                if loading() {
                    span { class: "loading loading-spinner" }
                }
                "Uploaden"
            }
        }
    }
}

#[component]
fn Verify(step: Signal<Steps>, members_migration: Signal<(u16, MembersMigration)>) -> Element {
    let mut loading = use_signal(|| false);

    let submit_accept = move |_| async move {
        loading.set(true);

        if let Ok(_response) = migration_response(true, members_migration.read().0).await {
            step.set(Steps::Done);
            loading.set(false);
        };
        loading.set(false);
    };

    rsx! {
        div {
            class: "flex flex-col items-center justify-center w-full mx-auto px-2",
            h2 { class: "text-xl mb-5", "Controleer de verandering" },
            div {
                class: "flex flex-wrap gap-5",
                div {
                    class: "card bg-base-200 p-5",
                    h2 { class: "card-title mb-1", "Toevoegen" }
                    MembersTable { members: members_migration.read().1.inserted.clone() }
                }
                div {
                    class: "card bg-base-200 p-5",
                    h2 { class: "card-title mb-1", "Verwijderen" }
                    MembersTable { members: members_migration.read().1.removed.clone() }
                }
                div {
                    class: "card bg-base-200 p-5",
                    h2 { class: "card-title mb-1", "Updaten" }
                    MembersTable { members: members_migration.read().1.updated.clone() }
                }
            }
            button {
                class: "btn btn-primary btn-wide mt-5",
                onclick: submit_accept,
                disabled: loading(),
                if loading() {
                    span { class: "loading loading-spinner" }
                }
                "Toepassen"
            }
        }
    }
}

#[component]
fn Done() -> Element {
    rsx! {
        div {
            class: "flex flex-col items-center justify-center w-full mx-auto px-2",
            h2 { class: "text-xl mb-5", "Ledenlijst is geüpdate" },
            div {
                class: "w-80 mt-10",
                img {
                    src: "/gifs/nick.webp",
                }
            }
            button {
                class: "btn btn-primary btn-wide mt-5",
                "Terug naar Start"
            }
        }
    }
}

#[component]
fn MembersTable(members: Vec<Member>) -> Element {
    rsx! {
        div {
            class: "h-[30rem] w-96 overflow-auto font-normal",
            table {
                class: "table table-pin-rows",
                thead {
                    tr {
                        th { "Relatiecode" }
                        th { "Naam" }
                    }
                }
                tbody {
                    for member in members {
                        tr {
                            th { "{member.id}" }
                            th { "{member.name.full}" }
                        }
                    }
                }
            }

        }
    }
}

#[server]
async fn upload_members_list(input: String) -> Result<(u16, MembersMigration), ServerFnError> {
    match MembersMigration::migrate_proposal(input).await {
        Ok(r) => Ok(r),
        Err(err) => Err(ServerFnError::new(err.to_string())),
    }
}

#[server]
async fn migration_response(correct: bool, id: u16) -> Result<(), ServerFnError> {
    if correct {
        match MembersMigration::migrate(id).await {
            Err(err) => Err(ServerFnError::new(err.to_string())),
            Ok(_) => Ok(()),
        }?;
    } else {
        tracing::info!("Migrations denied");
    }

    Ok(())
}
