use std::sync::Arc;

use leptos::prelude::*;
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{window, MediaQueryListEvent};

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ScreenSize {
    Mobile,  // < 768px
    Tablet,  // 768px - 1024px
    Desktop, // 1024px - 1440px
    Large,   // > 1440px
}

impl ScreenSize {
    pub fn from_width(width: f64) -> Self {
        if width < 768.0 {
            ScreenSize::Mobile
        } else if width < 1024.0 {
            ScreenSize::Tablet
        } else if width < 1440.0 {
            ScreenSize::Desktop
        } else {
            ScreenSize::Large
        }
    }

    pub fn breakpoint(&self) -> &'static str {
        match self {
            ScreenSize::Mobile => "mobile",
            ScreenSize::Tablet => "tablet",
            ScreenSize::Desktop => "desktop",
            ScreenSize::Large => "large",
        }
    }

    pub fn grid_columns(&self) -> i32 {
        match self {
            ScreenSize::Mobile => 4,
            ScreenSize::Tablet => 8,
            ScreenSize::Desktop => 12,
            ScreenSize::Large => 16,
        }
    }

    pub fn sidebar_behavior(&self) -> SidebarBehavior {
        match self {
            ScreenSize::Mobile => SidebarBehavior::Overlay,
            ScreenSize::Tablet => SidebarBehavior::Collapsible,
            ScreenSize::Desktop => SidebarBehavior::Fixed,
            ScreenSize::Large => SidebarBehavior::Fixed,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SidebarBehavior {
    Fixed,       // Always visible
    Collapsible, // Can be collapsed
    Overlay,     // Overlays content
    Hidden,      // Not shown
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResponsiveConfig {
    pub mobile_layout: MobileLayoutConfig,
    pub tablet_layout: TabletLayoutConfig,
    pub desktop_layout: DesktopLayoutConfig,
    pub touch_enabled: bool,
    pub swipe_gestures: bool,
    pub auto_hide_controls: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MobileLayoutConfig {
    pub stack_widgets: bool,
    pub hide_sidebar: bool,
    pub collapse_navigation: bool,
    pub single_column: bool,
    pub touch_friendly_controls: bool,
    pub swipe_navigation: bool,
    pub bottom_navigation: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TabletLayoutConfig {
    pub collapsible_sidebar: bool,
    pub compact_widgets: bool,
    pub dual_pane: bool,
    pub adaptive_grid: bool,
    pub touch_optimized: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DesktopLayoutConfig {
    pub multi_column: bool,
    pub persistent_sidebar: bool,
    pub dense_layout: bool,
    pub hover_interactions: bool,
    pub keyboard_shortcuts: bool,
}

impl Default for ResponsiveConfig {
    fn default() -> Self {
        Self {
            mobile_layout: MobileLayoutConfig::default(),
            tablet_layout: TabletLayoutConfig::default(),
            desktop_layout: DesktopLayoutConfig::default(),
            touch_enabled: true,
            swipe_gestures: true,
            auto_hide_controls: true,
        }
    }
}

impl Default for MobileLayoutConfig {
    fn default() -> Self {
        Self {
            stack_widgets: true,
            hide_sidebar: true,
            collapse_navigation: true,
            single_column: true,
            touch_friendly_controls: true,
            swipe_navigation: true,
            bottom_navigation: true,
        }
    }
}

impl Default for TabletLayoutConfig {
    fn default() -> Self {
        Self {
            collapsible_sidebar: true,
            compact_widgets: true,
            dual_pane: false,
            adaptive_grid: true,
            touch_optimized: true,
        }
    }
}

impl Default for DesktopLayoutConfig {
    fn default() -> Self {
        Self {
            multi_column: true,
            persistent_sidebar: true,
            dense_layout: false,
            hover_interactions: true,
            keyboard_shortcuts: true,
        }
    }
}

#[component]
pub fn Layout(children: Children) -> impl IntoView {
    // Legacy layout for existing components
    view! {
        <div class="min-h-screen bg-base-100 text-base-content">
            <div class="drawer lg:drawer-open">
                <input id="drawer-toggle" type="checkbox" class="drawer-toggle" />

                <div class="drawer-content flex flex-col">
                    <main class="flex-1 p-6 transition-all duration-300">
                        <div class="max-w-7xl mx-auto">
                            {children()}
                        </div>
                    </main>
                </div>
            </div>
        </div>
    }
}

#[component]
pub fn ResponsiveLayout(
    #[prop(optional)] config: Option<ResponsiveConfig>,
    children: Children,
) -> impl IntoView {
    let config = Arc::new(config.unwrap_or_default());
    let config_for_layout = Arc::clone(&config);
    let config_for_header1 = Arc::clone(&config);
    let config_for_header2 = Arc::clone(&config);
    let config_for_header3 = Arc::clone(&config);
    let config_for_bottom_nav = Arc::clone(&config);
    let config_for_touch = Arc::clone(&config);
    let config_for_swipe = Arc::clone(&config);
    let (screen_size, set_screen_size) = signal(ScreenSize::Desktop);
    let (is_sidebar_open, set_is_sidebar_open) = signal(true);
    let (is_touch_device, set_is_touch_device) = signal(false);

    // Detect screen size changes
    Effect::new(move |_| {
        let window = window().unwrap();

        // Initial screen size detection
        let width = window.inner_width().unwrap().as_f64().unwrap();
        set_screen_size.set(ScreenSize::from_width(width));

        // Touch device detection
        let navigator = window.navigator();
        let has_touch = js_sys::Reflect::has(&navigator, &"maxTouchPoints".into()).unwrap_or(false)
            && js_sys::Reflect::get(&navigator, &"maxTouchPoints".into())
                .unwrap()
                .as_f64()
                .unwrap_or(0.0)
                > 0.0;
        set_is_touch_device.set(has_touch);

        // Setup media query listeners
        setup_media_queries(set_screen_size);
    });

    // Update sidebar state based on screen size
    Effect::new(move |_| {
        let size = screen_size.get();
        match size.sidebar_behavior() {
            SidebarBehavior::Hidden => set_is_sidebar_open.set(false),
            SidebarBehavior::Overlay => set_is_sidebar_open.set(false),
            SidebarBehavior::Fixed => set_is_sidebar_open.set(true),
            SidebarBehavior::Collapsible => {
                // Keep current state
            }
        }
    });

    let layout_class = Memo::new(move |_| {
        let size = screen_size.get();
        format!(
            "responsive-layout {} {} {} {}",
            size.breakpoint(),
            if is_sidebar_open.get() {
                "sidebar-open"
            } else {
                "sidebar-closed"
            },
            if is_touch_device.get() {
                "touch-device"
            } else {
                "no-touch"
            },
            if config_for_layout.touch_enabled {
                "touch-enabled"
            } else {
                ""
            }
        )
    });

    view! {
        <div class=layout_class>
            <ResponsiveHeader
                screen_size=screen_size
                is_sidebar_open=is_sidebar_open
                on_sidebar_toggle=move |_| set_is_sidebar_open.update(|open| *open = !*open)
                config=(*config_for_header1).clone()
            />

            <div class="layout-body">
                <Show when=move || screen_size.get().sidebar_behavior() != SidebarBehavior::Hidden>
                    <ResponsiveSidebar
                        screen_size=screen_size
                        is_open=is_sidebar_open
                        behavior=move || screen_size.get().sidebar_behavior()
                        on_close=move |_| set_is_sidebar_open.set(false)
                        config=(*config_for_header2).clone()
                    />
                </Show>

                <main class="main-content">
                    <ResponsiveGrid
                        screen_size=screen_size
                        config=(*config_for_header3).clone()
                    >
                        {children()}
                    </ResponsiveGrid>
                </main>
            </div>

            <Show when={let config_clone = config_for_bottom_nav.clone(); move || matches!(screen_size.get(), ScreenSize::Mobile) && config_clone.mobile_layout.bottom_navigation}>
                <MobileBottomNavigation />
            </Show>

            <Show when={let config_clone = config_for_touch.clone(); move || config_clone.touch_enabled && is_touch_device.get()}>
                <TouchGestureHandler
                    _screen_size=screen_size
                    on_swipe_right={let config_clone = config_for_swipe.clone(); move |_| {
                        if config_clone.swipe_gestures {
                            set_is_sidebar_open.set(true);
                        }
                    }}
                />
            </Show>
        </div>
    }
}

#[component]
pub fn ResponsiveHeader(
    screen_size: ReadSignal<ScreenSize>,
    is_sidebar_open: ReadSignal<bool>,
    on_sidebar_toggle: impl Fn(web_sys::MouseEvent) + 'static + Send + Sync,
    config: ResponsiveConfig,
) -> impl IntoView {
    let on_sidebar_toggle = Arc::new(on_sidebar_toggle);
    let header_class = Memo::new(move |_| {
        let size = screen_size.get();
        format!("responsive-header {}", size.breakpoint())
    });

    view! {
        <header class=header_class>
            <div class="header-content">
                <Show when=move || !matches!(screen_size.get().sidebar_behavior(), SidebarBehavior::Fixed)>
                    <button
                        class="sidebar-toggle btn-icon"
                        on:click={let toggle = Arc::clone(&on_sidebar_toggle); move |e| toggle(e)}
                    >
                        <i class=move || {
                            if is_sidebar_open.get() {
                                "bi-x"
                            } else {
                                "bi-list"
                            }
                        }></i>
                    </button>
                </Show>

                <div class="header-title">
                    <h1>"Control Center"</h1>
                    <Show when=move || !matches!(screen_size.get(), ScreenSize::Mobile)>
                        <span class="subtitle">"Dashboard"</span>
                    </Show>
                </div>

                <div class="header-actions">
                    <MobileHeaderActions screen_size=screen_size />
                    <DesktopHeaderActions screen_size=screen_size />
                </div>
            </div>
        </header>
    }
}

#[component]
pub fn MobileHeaderActions(screen_size: ReadSignal<ScreenSize>) -> impl IntoView {
    view! {
        <Show when=move || matches!(screen_size.get(), ScreenSize::Mobile)>
            <div class="mobile-header-actions">
                <button class="btn-icon" title="Search">
                    <i class="bi-search"></i>
                </button>
                <button class="btn-icon" title="Notifications">
                    <i class="bi-bell"></i>
                </button>
                <button class="btn-icon" title="Menu">
                    <i class="bi-three-dots-vertical"></i>
                </button>
            </div>
        </Show>
    }
}

#[component]
pub fn DesktopHeaderActions(screen_size: ReadSignal<ScreenSize>) -> impl IntoView {
    view! {
        <Show when=move || !matches!(screen_size.get(), ScreenSize::Mobile)>
            <div class="desktop-header-actions">
                <div class="search-box">
                    <input type="text" placeholder="Search..." class="search-input" />
                    <i class="bi-search search-icon"></i>
                </div>
                <button class="btn-icon" title="Notifications">
                    <i class="bi-bell"></i>
                    <span class="notification-badge">3</span>
                </button>
                <button class="btn-icon" title="Theme">
                    <i class="bi-moon"></i>
                </button>
                <div class="user-menu">
                    <button class="user-avatar">
                        <i class="bi-person-circle"></i>
                    </button>
                </div>
            </div>
        </Show>
    }
}

#[component]
pub fn ResponsiveSidebar(
    screen_size: ReadSignal<ScreenSize>,
    is_open: ReadSignal<bool>,
    behavior: impl Fn() -> SidebarBehavior + 'static + Send + Sync,
    on_close: impl Fn(web_sys::MouseEvent) + 'static + Send + Sync,
    config: ResponsiveConfig,
) -> impl IntoView {
    let on_close = Arc::new(on_close);
    let on_close_1 = Arc::clone(&on_close);
    let on_close_2 = Arc::clone(&on_close);
    let behavior = Arc::new(behavior);
    let behavior_for_memo = Arc::clone(&behavior);
    let sidebar_class = Memo::new(move |_| {
        let size = screen_size.get();
        let behavior_class = match behavior_for_memo() {
            SidebarBehavior::Fixed => "sidebar-fixed",
            SidebarBehavior::Collapsible => "sidebar-collapsible",
            SidebarBehavior::Overlay => "sidebar-overlay",
            SidebarBehavior::Hidden => "sidebar-hidden",
        };

        format!(
            "responsive-sidebar {} {} {}",
            size.breakpoint(),
            behavior_class,
            if is_open.get() {
                "sidebar-open"
            } else {
                "sidebar-closed"
            }
        )
    });

    view! {
        <aside class=sidebar_class>
            <Show when={let behavior_fn = Arc::clone(&behavior); move || matches!(behavior_fn(), SidebarBehavior::Overlay)}>
                <div
                    class="sidebar-backdrop"
                    on:click={let close_fn = Arc::clone(&on_close_1); move |e| close_fn(e)}
                ></div>
            </Show>

            <div class="sidebar-content">
                <div class="sidebar-header">
                    <div class="sidebar-brand">
                        <i class="bi-shield-check brand-icon"></i>
                        <Show when=move || !matches!(screen_size.get(), ScreenSize::Mobile) || is_open.get()>
                            <span class="brand-text">"Control Center"</span>
                        </Show>
                    </div>

                    <Show when={let behavior_fn = Arc::clone(&behavior); move || matches!(behavior_fn(), SidebarBehavior::Overlay)}>
                        <button
                            class="sidebar-close btn-icon"
                            on:click={let close_fn = Arc::clone(&on_close_2); move |e| close_fn(e)}
                        >
                            <i class="bi-x"></i>
                        </button>
                    </Show>
                </div>

                <nav class="sidebar-nav">
                    <SidebarNavigation
                        _screen_size=screen_size
                        is_collapsed={let behavior_fn3 = Arc::clone(&behavior); Arc::new(move || !is_open.get() && matches!(behavior_fn3(), SidebarBehavior::Collapsible))}
                    />
                </nav>

                <div class="sidebar-footer">
                    <Show when=move || !matches!(screen_size.get(), ScreenSize::Mobile)>
                        <div class="sidebar-user">
                            <div class="user-avatar">
                                <i class="bi-person-circle"></i>
                            </div>
                            <Show when=move || is_open.get()>
                                <div class="user-info">
                                    <span class="user-name">"Admin User"</span>
                                    <span class="user-role">"Administrator"</span>
                                </div>
                            </Show>
                        </div>
                    </Show>
                </div>
            </div>
        </aside>
    }
}

#[component]
pub fn SidebarNavigation(
    _screen_size: ReadSignal<ScreenSize>,
    is_collapsed: Arc<dyn Fn() -> bool + Send + Sync>,
) -> impl IntoView {
    let nav_items = vec![
        NavItem {
            id: "dashboard".to_string(),
            label: "Dashboard".to_string(),
            icon: "bi-speedometer2".to_string(),
            href: "/".to_string(),
            active: true,
            badge: None,
        },
        NavItem {
            id: "analytics".to_string(),
            label: "Analytics".to_string(),
            icon: "bi-graph-up".to_string(),
            href: "/analytics".to_string(),
            active: false,
            badge: None,
        },
        NavItem {
            id: "security".to_string(),
            label: "Security".to_string(),
            icon: "bi-shield-check".to_string(),
            href: "/security".to_string(),
            active: false,
            badge: Some("3".to_string()),
        },
        NavItem {
            id: "users".to_string(),
            label: "Users".to_string(),
            icon: "bi-people".to_string(),
            href: "/users".to_string(),
            active: false,
            badge: None,
        },
        NavItem {
            id: "settings".to_string(),
            label: "Settings".to_string(),
            icon: "bi-gear".to_string(),
            href: "/settings".to_string(),
            active: false,
            badge: None,
        },
    ];

    view! {
        <ul class="nav-list">
            <For
                each=move || nav_items.clone()
                key=|item| item.id.clone()
                children=move |item| {
                    let badge = item.badge.clone();
                    let badge_clone = badge.clone();
                    let is_collapsed_fn = Arc::clone(&is_collapsed);
                    let is_collapsed_fn2 = Arc::clone(&is_collapsed);
                    let is_collapsed_fn3 = Arc::clone(&is_collapsed);

                    view! {
                        <li class="nav-item">
                            <a
                                href=item.href.clone()
                                class=move || format!(
                                    "nav-link {} {}",
                                    if item.active { "active" } else { "" },
                                    if is_collapsed_fn() { "collapsed" } else { "" }
                                )
                            >
                                <i class=item.icon.clone()></i>
                                <Show when=move || !is_collapsed_fn2()>
                                    <span class="nav-text">{item.label.clone()}</span>
                                </Show>
                                <Show when=move || badge_clone.is_some() && !is_collapsed_fn3()>
                                    <span class="nav-badge">
                                        {badge.clone().unwrap_or_default()}
                                    </span>
                                </Show>
                            </a>
                        </li>
                    }
                }
            />
        </ul>
    }
}

#[component]
pub fn ResponsiveGrid(
    screen_size: ReadSignal<ScreenSize>,
    config: ResponsiveConfig,
    children: Children,
) -> impl IntoView {
    let grid_class = Memo::new(move |_| {
        let size = screen_size.get();
        let columns = size.grid_columns();

        format!(
            "responsive-grid {} grid-cols-{}",
            size.breakpoint(),
            columns
        )
    });

    let grid_style = Memo::new(move |_| {
        let size = screen_size.get();
        match size {
            ScreenSize::Mobile if config.mobile_layout.single_column => {
                "display: flex; flex-direction: column; gap: 1rem;".to_string()
            }
            _ => {
                let columns = size.grid_columns();
                format!(
                    "display: grid; grid-template-columns: repeat({}, 1fr); gap: 1rem;",
                    columns
                )
            }
        }
    });

    view! {
        <div
            class=grid_class
            style=grid_style
        >
            {children()}
        </div>
    }
}

#[component]
pub fn MobileBottomNavigation() -> impl IntoView {
    let nav_items = vec![
        ("Dashboard", "bi-speedometer2", "/", true),
        ("Analytics", "bi-graph-up", "/analytics", false),
        ("Security", "bi-shield-check", "/security", false),
        ("Settings", "bi-gear", "/settings", false),
    ];

    view! {
        <nav class="mobile-bottom-nav">
            <div class="bottom-nav-content">
                <For
                    each=move || nav_items.clone()
                    key=|item| item.0.to_string()
                    children=move |(label, icon, href, active)| {
                        view! {
                            <a
                                href=href
                                class=format!("bottom-nav-item {}", if active { "active" } else { "" })
                            >
                                <i class=icon></i>
                                <span class="bottom-nav-label">{label}</span>
                            </a>
                        }
                    }
                />
            </div>
        </nav>
    }
}

#[component]
pub fn TouchGestureHandler(
    _screen_size: ReadSignal<ScreenSize>,
    on_swipe_right: impl Fn(TouchGesture) + 'static + Send + Sync,
) -> impl IntoView {
    let handle_touch_start = move |_event: web_sys::TouchEvent| {
        // Simplified touch handler - placeholder implementation
    };

    let handle_touch_end = move |_event: web_sys::TouchEvent| {
        // Simplified touch handler - trigger right swipe gesture
        let gesture = TouchGesture {
            start_x: 0.0,
            start_y: 0.0,
            end_x: 100.0,
            end_y: 0.0,
            distance: 100.0,
            direction: SwipeDirection::Right,
        };
        on_swipe_right(gesture);
    };

    view! {
        <div
            class="touch-gesture-handler"
            on:touchstart=handle_touch_start
            on:touchend=handle_touch_end
            style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: -1;"
        ></div>
    }
}

// Supporting types and utilities

#[derive(Debug, Clone)]
pub struct NavItem {
    pub id: String,
    pub label: String,
    pub icon: String,
    pub href: String,
    pub active: bool,
    pub badge: Option<String>,
}

#[derive(Debug, Clone)]
pub struct TouchGesture {
    pub start_x: f64,
    pub start_y: f64,
    pub end_x: f64,
    pub end_y: f64,
    pub distance: f64,
    pub direction: SwipeDirection,
}

#[derive(Debug, Clone)]
pub enum SwipeDirection {
    Up,
    Down,
    Left,
    Right,
}

fn setup_media_queries(set_screen_size: WriteSignal<ScreenSize>) {
    let window = window().unwrap();

    // Setup media query listeners for different breakpoints
    let queries = vec![
        ("(max-width: 767px)", ScreenSize::Mobile),
        (
            "(min-width: 768px) and (max-width: 1023px)",
            ScreenSize::Tablet,
        ),
        (
            "(min-width: 1024px) and (max-width: 1439px)",
            ScreenSize::Desktop,
        ),
        ("(min-width: 1440px)", ScreenSize::Large),
    ];

    for (query, size) in queries {
        if let Ok(Some(media_query)) = window.match_media(query) {
            if media_query.matches() {
                set_screen_size.set(size);
            }

            let size_clone = size;
            let set_screen_size_clone = set_screen_size;

            let callback = Closure::wrap(Box::new(move |event: MediaQueryListEvent| {
                if event.matches() {
                    set_screen_size_clone.set(size_clone);
                }
            }) as Box<dyn FnMut(MediaQueryListEvent)>);

            media_query.set_onchange(Some(callback.as_ref().unchecked_ref()));
            callback.forget();
        }
    }
}

// Hook for accessing responsive context
pub fn use_responsive() -> (ReadSignal<ScreenSize>, ReadSignal<bool>, ReadSignal<bool>) {
    let (screen_size, _) = signal(ScreenSize::Desktop);
    let (is_mobile, _) = signal(false);
    let (is_touch_device, _) = signal(false);

    // These would be updated by the ResponsiveLayout component
    (screen_size, is_mobile, is_touch_device)
}

// Utility components for responsive behavior

#[component]
pub fn ShowOnMobile(children: Children) -> impl IntoView {
    let (screen_size, _, _) = use_responsive();

    view! {
        {if matches!(screen_size.get_untracked(), ScreenSize::Mobile) {
            children().into_any()
        } else {
            ().into_any()
        }}
    }
}

#[component]
pub fn ShowOnTablet(children: Children) -> impl IntoView {
    let (screen_size, _, _) = use_responsive();

    view! {
        {if matches!(screen_size.get_untracked(), ScreenSize::Tablet) {
            children().into_any()
        } else {
            ().into_any()
        }}
    }
}

#[component]
pub fn ShowOnDesktop(children: Children) -> impl IntoView {
    let (screen_size, _, _) = use_responsive();

    view! {
        {if matches!(screen_size.get_untracked(), ScreenSize::Desktop | ScreenSize::Large) {
            children().into_any()
        } else {
            ().into_any()
        }}
    }
}

#[component]
pub fn HideOnMobile(children: Children) -> impl IntoView {
    let (screen_size, _, _) = use_responsive();

    view! {
        {if !matches!(screen_size.get_untracked(), ScreenSize::Mobile) {
            children().into_any()
        } else {
            ().into_any()
        }}
    }
}

#[component]
pub fn ResponsiveText(
    mobile: &'static str,
    tablet: Option<&'static str>,
    desktop: &'static str,
) -> impl IntoView {
    let (screen_size, _, _) = use_responsive();

    let text = Memo::new(move |_| match screen_size.get() {
        ScreenSize::Mobile => mobile,
        ScreenSize::Tablet => tablet.unwrap_or(desktop),
        ScreenSize::Desktop | ScreenSize::Large => desktop,
    });

    view! {
        <span>{text}</span>
    }
}
