//! Internal questionnaire types and Leptos form renderer.
//!
//! Types are designed to be wire-compatible with TypeDialog's `FormDefinition`
//! so a future integration can swap the parsing layer without changing the UI
//! component.

use leptos::prelude::*;
use serde::{Deserialize, Serialize};

// ── Data model ───────────────────────────────────────────────────────────────

/// A single field element in the questionnaire form.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum QuestionnaireElement {
    Header {
        name: String,
        content: String,
        #[serde(default)]
        i18n: bool,
    },
    Text {
        name: String,
        prompt: String,
        #[serde(default)]
        i18n: bool,
        #[serde(default)]
        required: bool,
    },
    Select {
        name: String,
        prompt: String,
        #[serde(default)]
        i18n: bool,
        #[serde(default)]
        required: bool,
        options: Vec<SelectOption>,
    },
    Confirm {
        name: String,
        prompt: String,
        #[serde(default)]
        i18n: bool,
        #[serde(default)]
        required: bool,
    },
}

/// An option within a select element.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SelectOption {
    pub value: String,
    pub label: String,
}

/// A complete questionnaire form definition.
///
/// Wire-compatible with TypeDialog's `FormDefinition` for future integration.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QuestionnaireDefinition {
    pub name: String,
    #[serde(default)]
    pub i18n_prefix: String,
    pub elements: Vec<QuestionnaireElement>,
}

// ── Leptos renderer ──────────────────────────────────────────────────────────

/// Inline questionnaire form rendered in the activity CTA section.
///
/// Collects user answers and calls `on_submit` with `Vec<(key, value)>` pairs.
#[component]
pub fn QuestionnaireForm(
    definition: QuestionnaireDefinition,
    activity_id: String,
    #[prop(into)] on_submit_complete: Callback<()>,
) -> impl IntoView {
    let (answers, set_answers) = signal(std::collections::HashMap::<String, String>::new());
    let (submitting, set_submitting) = signal(false);
    let (error, set_error) = signal(Option::<String>::None);

    let definition = StoredValue::new(definition);
    let activity_id = StoredValue::new(activity_id);

    let handle_submit = move |ev: web_sys::SubmitEvent| {
        ev.prevent_default();

        let current = answers.get();
        let def = definition.get_value();

        // Validate required fields.
        let missing: Vec<String> = def
            .elements
            .iter()
            .filter_map(|el| match el {
                QuestionnaireElement::Text {
                    name,
                    required: true,
                    ..
                }
                | QuestionnaireElement::Select {
                    name,
                    required: true,
                    ..
                }
                | QuestionnaireElement::Confirm {
                    name,
                    required: true,
                    ..
                } => {
                    let filled = current.get(name).map_or(false, |v| !v.is_empty());
                    if filled {
                        None
                    } else {
                        Some(name.clone())
                    }
                }
                _ => None,
            })
            .collect();

        if !missing.is_empty() {
            set_error.set(Some(format!(
                "Please answer all required questions: {}",
                missing.join(", ")
            )));
            return;
        }

        set_error.set(None);
        set_submitting.set(true);

        let responses: Vec<(String, String)> = current.into_iter().collect();
        let aid = activity_id.get_value();

        leptos::task::spawn_local(async move {
            match super::server_fns::server_submit_internal_questionnaire(aid, responses).await {
                Ok(()) => {
                    set_submitting.set(false);
                    on_submit_complete.run(());
                }
                Err(e) => {
                    set_submitting.set(false);
                    set_error.set(Some(e.to_string()));
                }
            }
        });
    };

    view! {
        <form
            class="space-y-4"
            on:submit=handle_submit
        >
            {move || definition.get_value().elements.into_iter().map(|el| {
                render_element(el, answers, set_answers)
            }).collect::<Vec<_>>()}

            {move || error.get().map(|msg| view! {
                <p class="text-error text-sm">{msg}</p>
            })}

            <button
                type="submit"
                class="ds-btn-primary w-full"
                disabled=move || submitting.get()
            >
                {move || if submitting.get() { "Submitting…" } else { "Submit Evaluation" }}
            </button>
        </form>
    }
}

fn render_element(
    el: QuestionnaireElement,
    answers: ReadSignal<std::collections::HashMap<String, String>>,
    set_answers: WriteSignal<std::collections::HashMap<String, String>>,
) -> impl IntoView {
    match el {
        QuestionnaireElement::Header { content, .. } => view! {
            <h4 class="text-lg font-semibold ds-text mt-4">{content}</h4>
        }
        .into_any(),

        QuestionnaireElement::Text { name, prompt, .. } => {
            let name_clone = name.clone();
            let name_attr = name.clone();
            let name_id = format!("q-{name_attr}");
            view! {
                <div class="form-control">
                    <label class="label">
                        <span class="label-text ds-text">{prompt}</span>
                    </label>
                    <textarea
                        id=name_id
                        name=name_attr
                        class="textarea textarea-bordered w-full"
                        rows="3"
                        on:input=move |ev| {
                            let val = event_target_value(&ev);
                            set_answers.update(|m| { m.insert(name_clone.clone(), val); });
                        }
                        prop:value=move || {
                            answers.with(|m| m.get(&name).cloned().unwrap_or_default())
                        }
                    />
                </div>
            }
            .into_any()
        }

        QuestionnaireElement::Select {
            name,
            prompt,
            options,
            ..
        } => {
            let name_clone = name.clone();
            let name_attr = name.clone();
            let name_id = format!("q-{name_attr}");
            view! {
                <div class="form-control">
                    <label class="label">
                        <span class="label-text ds-text">{prompt}</span>
                    </label>
                    <select
                        id=name_id
                        name=name_attr
                        class="select select-bordered w-full"
                        on:change=move |ev| {
                            let val = event_target_value(&ev);
                            set_answers.update(|m| { m.insert(name_clone.clone(), val); });
                        }
                    >
                        <option value="" disabled selected>"— select —"</option>
                        {options.into_iter().map(|opt| {
                            let opt_val = opt.value.clone();
                            view! {
                                <option value={opt.value}>{opt_val} " - " {opt.label}</option>
                            }
                        }).collect::<Vec<_>>()}
                    </select>
                </div>
            }
            .into_any()
        }

        QuestionnaireElement::Confirm { name, prompt, .. } => {
            let name_clone = name.clone();
            let name_attr = name.clone();
            let name_id = format!("q-{name_attr}");
            view! {
                <div class="form-control">
                    <label class="label cursor-pointer gap-3">
                        <input
                            type="checkbox"
                            id=name_id
                            name=name_attr
                            class="checkbox"
                            on:change=move |ev| {
                                let checked = event_target_checked(&ev);
                                let val = if checked { "true" } else { "false" };
                                set_answers.update(|m| { m.insert(name_clone.clone(), val.to_string()); });
                            }
                        />
                        <span class="label-text ds-text">{prompt}</span>
                    </label>
                </div>
            }
            .into_any()
        }
    }
}
