//! Settings popup component for scene viewer configuration.

use leptos::ev::MouseEvent;
use leptos::prelude::*;

use super::modals::Modal;
use super::settings::{
    TEXT_EM_MAX, TEXT_EM_MIN, TEXT_EM_STEP, ViewerSettings, ZOOM_MAX, ZOOM_STEP, calculate_min_zoom,
};
use crate::utils::LocalStoragePersist;

/// Settings popup component for scene viewer configuration.
///
/// Provides controls for:
/// - Panning mode (native resolution with scroll)
/// - Zoom level (when panning enabled)
/// - Enlarge props (when panning disabled)
///
/// Props:
/// - `open`: Signal controlling visibility
/// - `settings`: RwSignal for viewer settings (read/write)
/// - `on_close`: Callback when popup should close
#[component]
pub fn SettingsPopup(
    #[prop(into)] open: Signal<bool>,
    settings: RwSignal<ViewerSettings>,
    on_close: Callback<()>,
    /// Scene dimensions (width, height) for calculating min zoom.
    #[prop(default = (800.0, 600.0))]
    scene_dimensions: (f64, f64),
    /// Viewport dimensions signal for calculating min zoom.
    #[prop(into, optional)]
    viewport_dimensions: Option<Signal<(f64, f64)>>,
) -> impl IntoView {
    // Derived signals for each setting
    let panning = Signal::derive(move || settings.get().panning_enabled);
    let zoom = Signal::derive(move || settings.get().zoom_level);
    let enlarge = Signal::derive(move || settings.get().enlarge_props);
    let text_em = Signal::derive(move || settings.get().text_em_size);

    // Calculate effective minimum zoom based on scene/viewport dimensions
    let effective_min_zoom = Signal::derive(move || {
        let (scene_w, scene_h) = scene_dimensions;
        let (vp_w, vp_h) = viewport_dimensions
            .map(|s| s.get())
            .unwrap_or((800.0, 600.0));
        calculate_min_zoom(scene_w, scene_h, vp_w, vp_h)
    });

    // Toggle handlers
    let on_panning_toggle = move |_| {
        settings.update(|s| {
            s.panning_enabled = !s.panning_enabled;
            // Reset scroll when disabling pan mode
            if !s.panning_enabled {
                s.reset_scroll();
            }
            s.save();
        });
    };

    let on_enlarge_toggle = move |_| {
        settings.update(|s| {
            s.enlarge_props = !s.enlarge_props;
            s.save();
        });
    };

    let on_zoom_decrease = move |_| {
        let min_zoom = effective_min_zoom.get();
        settings.update(|s| {
            s.adjust_zoom_with_min(-ZOOM_STEP, min_zoom);
            s.save();
        });
    };

    let on_zoom_increase = move |_| {
        let min_zoom = effective_min_zoom.get();
        settings.update(|s| {
            s.adjust_zoom_with_min(ZOOM_STEP, min_zoom);
            s.save();
        });
    };

    let on_zoom_input = move |ev| {
        let val: f64 = event_target_value(&ev).parse().unwrap_or(1.0);
        let min_zoom = effective_min_zoom.get();
        settings.update(|s| {
            s.zoom_level = val.clamp(min_zoom, ZOOM_MAX);
            s.save();
        });
    };

    let on_text_em_decrease = move |_| {
        settings.update(|s| {
            s.adjust_text_em(-TEXT_EM_STEP);
            s.save();
        });
    };

    let on_text_em_increase = move |_| {
        settings.update(|s| {
            s.adjust_text_em(TEXT_EM_STEP);
            s.save();
        });
    };

    let on_text_em_input = move |ev: leptos::ev::Event| {
        let val: f64 = event_target_value(&ev).parse().unwrap_or(1.0);
        settings.update(|s| {
            s.text_em_size = val.clamp(TEXT_EM_MIN, TEXT_EM_MAX);
            s.save();
        });
    };

    view! {
        <Modal
            open=open
            on_close=on_close
            title="Scene Settings"
            title_id="settings-modal-title"
        >
            // Settings toggles
            <div class="space-y-4">
                // Panning toggle
                <SettingsToggle
                    label="Native Resolution (Pan Mode)"
                    description="View scene at 1:1 pixel size, scroll to pan around"
                    checked=panning
                    on_change=on_panning_toggle
                />

                // Zoom controls (only when panning enabled)
                <Show when=move || panning.get()>
                    <div class="space-y-2">
                        <label class="block text-white font-medium">
                            "Zoom: " {move || format!("{}%", (zoom.get() * 100.0) as i32)}
                        </label>
                        <div class="flex items-center gap-2">
                            <button
                                type="button"
                                class="px-3 py-1 bg-gray-700 hover:bg-gray-600 text-white rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                                on:click=on_zoom_decrease
                                disabled={move || zoom.get() <= effective_min_zoom.get()}
                                aria-label="Zoom out"
                            >
                                "-"
                            </button>
                            <input
                                type="range"
                                min=move || effective_min_zoom.get().to_string()
                                max=ZOOM_MAX.to_string()
                                step=ZOOM_STEP.to_string()
                                class="flex-1 h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer accent-blue-500"
                                prop:value=move || zoom.get().to_string()
                                on:input=on_zoom_input
                                aria-label="Zoom level"
                            />
                            <button
                                type="button"
                                class="px-3 py-1 bg-gray-700 hover:bg-gray-600 text-white rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                                on:click=on_zoom_increase
                                disabled={move || zoom.get() >= ZOOM_MAX}
                                aria-label="Zoom in"
                            >
                                "+"
                            </button>
                        </div>
                    </div>
                </Show>

                // Enlarge props toggle (always visible)
                <SettingsToggle
                    label="Enlarge Props"
                    description="Scale props relative to 1920x1080 for consistent size"
                    checked=enlarge
                    on_change=on_enlarge_toggle
                />

                // Text size controls
                <div class="space-y-2">
                    <label class="block text-white font-medium">
                        "Text Size: " {move || format!("{}%", (text_em.get() * 100.0) as i32)}
                    </label>
                    <p class="text-gray-400 text-sm mb-2">
                        "Scale display names, chat bubbles, and emotion badges"
                    </p>
                    <div class="flex items-center gap-2">
                        <button
                            type="button"
                            class="px-3 py-1 bg-gray-700 hover:bg-gray-600 text-white rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                            on:click=on_text_em_decrease
                            disabled={move || text_em.get() <= TEXT_EM_MIN}
                            aria-label="Decrease text size"
                        >
                            "-"
                        </button>
                        <input
                            type="range"
                            min=TEXT_EM_MIN.to_string()
                            max=TEXT_EM_MAX.to_string()
                            step=TEXT_EM_STEP.to_string()
                            class="flex-1 h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer accent-blue-500"
                            prop:value=move || text_em.get().to_string()
                            on:input=on_text_em_input
                            aria-label="Text size"
                        />
                        <button
                            type="button"
                            class="px-3 py-1 bg-gray-700 hover:bg-gray-600 text-white rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                            on:click=on_text_em_increase
                            disabled={move || text_em.get() >= TEXT_EM_MAX}
                            aria-label="Increase text size"
                        >
                            "+"
                        </button>
                    </div>
                </div>
            </div>

            // Keyboard shortcuts help
            <div class="mt-6 pt-4 border-t border-gray-700 space-y-1">
                <p class="text-gray-400 text-sm">
                    "Keyboard: "
                    <kbd class="px-1.5 py-0.5 bg-gray-700 rounded text-xs font-mono">"s"</kbd>
                    " to open settings"
                </p>
                <Show when=move || panning.get()>
                    <p class="text-gray-400 text-sm">
                        "Arrow keys to pan, "
                        <kbd class="px-1.5 py-0.5 bg-gray-700 rounded text-xs font-mono">"+"</kbd>
                        <kbd class="px-1.5 py-0.5 bg-gray-700 rounded text-xs font-mono">"-"</kbd>
                        " to zoom"
                    </p>
                </Show>
            </div>
        </Modal>
    }
}

/// Individual toggle switch component.
#[component]
fn SettingsToggle(
    /// Label text for the toggle.
    label: &'static str,
    /// Description text shown below label.
    description: &'static str,
    /// Whether the toggle is currently enabled.
    #[prop(into)]
    checked: Signal<bool>,
    /// Handler called when toggle is clicked.
    on_change: impl Fn(MouseEvent) + 'static,
) -> impl IntoView {
    view! {
        <button
            type="button"
            class="w-full flex items-start gap-4 p-3 rounded-lg hover:bg-gray-700/50 transition-colors text-left"
            on:click=on_change
            role="switch"
            aria-checked=move || checked.get().to_string()
        >
            // Toggle switch
            <div
                class=move || format!(
                    "relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors {}",
                    if checked.get() { "bg-blue-600" } else { "bg-gray-600" }
                )
                aria-hidden="true"
            >
                <span
                    class=move || format!(
                        "pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition {}",
                        if checked.get() { "translate-x-5" } else { "translate-x-0" }
                    )
                />
            </div>
            // Label and description
            <div class="flex-1 min-w-0">
                <span class="block text-white font-medium">{label}</span>
                <span class="block text-gray-400 text-sm">{description}</span>
            </div>
        </button>
    }
}
