use std::collections::HashMap;

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

use crate::store::{
    auth::AuthState, notifications::NotificationState, storage::LocalStorageManager, theme::Theme,
};

/// Global application state
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppState {
    pub auth: AuthState,
    pub theme: Theme,
    pub notifications: NotificationState,
    pub sidebar_collapsed: bool,
    pub loading: bool,
    pub error: Option<String>,
    pub metadata: HashMap<String, serde_json::Value>,
}

impl Default for AppState {
    fn default() -> Self {
        Self {
            auth: AuthState::default(),
            theme: Theme::Light,
            notifications: NotificationState::default(),
            sidebar_collapsed: false,
            loading: false,
            error: None,
            metadata: HashMap::new(),
        }
    }
}

/// Global app state context
#[derive(Debug, Clone)]
pub struct AppStateContext {
    pub state: RwSignal<AppState>,
}

impl AppStateContext {
    pub fn new() -> Self {
        Self {
            state: RwSignal::new(AppState::default()),
        }
    }

    // Auth state methods
    pub fn set_auth_state(&self, auth: AuthState) {
        self.state.update(|state| state.auth = auth);
    }

    pub fn get_auth_state(&self) -> AuthState {
        self.state.get_untracked().auth
    }

    pub fn is_authenticated(&self) -> bool {
        self.state.get_untracked().auth.is_authenticated()
    }

    // Theme methods
    pub fn set_theme(&self, theme: Theme) {
        self.state.update(|state| state.theme = theme);
        // Save to localStorage
        LocalStorageManager::set("theme", &theme).ok();

        // Update DOM attribute
        if let Some(document) = web_sys::window().and_then(|w| w.document()) {
            if let Some(html) = document.document_element() {
                let theme_str = match theme {
                    Theme::Light => "light",
                    Theme::Dark => "dark",
                    Theme::Auto => get_system_theme_preference(),
                };
                let _ = html.set_attribute("data-theme", theme_str);
            }
        }
    }

    pub fn get_theme(&self) -> Theme {
        self.state.get_untracked().theme
    }

    pub fn toggle_theme(&self) {
        let current_theme = self.get_theme();
        let new_theme = match current_theme {
            Theme::Light => Theme::Dark,
            Theme::Dark => Theme::Light,
            Theme::Auto => Theme::Light,
        };
        self.set_theme(new_theme);
    }

    // Sidebar methods
    pub fn toggle_sidebar(&self) {
        self.state
            .update(|state| state.sidebar_collapsed = !state.sidebar_collapsed);
    }

    pub fn set_sidebar_collapsed(&self, collapsed: bool) {
        self.state
            .update(|state| state.sidebar_collapsed = collapsed);
    }

    pub fn is_sidebar_collapsed(&self) -> bool {
        self.state.get_untracked().sidebar_collapsed
    }

    // Loading state methods
    pub fn set_loading(&self, loading: bool) {
        self.state.update(|state| state.loading = loading);
    }

    pub fn is_loading(&self) -> bool {
        self.state.get_untracked().loading
    }

    // Error handling methods
    pub fn set_error(&self, error: Option<String>) {
        self.state.update(|state| state.error = error);
    }

    pub fn clear_error(&self) {
        self.set_error(None);
    }

    pub fn get_error(&self) -> Option<String> {
        self.state.get_untracked().error
    }

    // Notification methods
    pub fn add_notification(&self, notification: crate::store::notifications::Notification) {
        self.state.update(|state| {
            state.notifications.add_notification(notification);
        });
    }

    pub fn remove_notification(&self, id: uuid::Uuid) {
        self.state.update(|state| {
            state.notifications.remove_notification(id);
        });
    }

    pub fn clear_notifications(&self) {
        self.state.update(|state| {
            state.notifications.clear_notifications();
        });
    }

    // Metadata methods
    pub fn set_metadata(&self, key: String, value: serde_json::Value) {
        self.state.update(|state| {
            state.metadata.insert(key, value);
        });
    }

    pub fn get_metadata(&self, key: &str) -> Option<serde_json::Value> {
        self.state.get_untracked().metadata.get(key).cloned()
    }

    pub fn remove_metadata(&self, key: &str) {
        self.state.update(|state| {
            state.metadata.remove(key);
        });
    }

    // Persistence methods
    pub fn save_to_storage(&self) {
        let state = self.state.get_untracked();
        LocalStorageManager::set("app_state", &state).ok();
    }

    pub fn load_from_storage(&self) {
        if let Some(state) = LocalStorageManager::get::<AppState>("app_state") {
            self.state.set(state);
        }
    }
}

// Context provider
static APP_STATE_CONTEXT: std::sync::OnceLock<AppStateContext> = std::sync::OnceLock::new();

pub fn provide_app_state() -> AppStateContext {
    let context = APP_STATE_CONTEXT.get_or_init(|| {
        let ctx = AppStateContext::new();

        // Load saved theme from localStorage
        if let Some(theme) = LocalStorageManager::get::<Theme>("theme") {
            ctx.set_theme(theme);
        }

        // Load other state from storage
        ctx.load_from_storage();

        ctx
    });

    context.clone()
}

pub fn use_app_state() -> AppStateContext {
    APP_STATE_CONTEXT
        .get()
        .expect("AppStateContext must be provided before use")
        .clone()
}

// Convenience hooks using Leptos 0.6 API
pub fn use_auth_state() -> (Signal<AuthState>, SignalSetter<AuthState>) {
    let app_state = use_app_state();
    let (read, write) = create_slice(
        app_state.state,
        |state| state.auth.clone(),
        |state, auth: AuthState| state.auth = auth,
    );
    (read, write)
}

pub fn use_theme() -> (Signal<Theme>, SignalSetter<Theme>) {
    let app_state = use_app_state();
    let (read, write) = create_slice(
        app_state.state,
        |state| state.theme,
        |state, theme: Theme| {
            state.theme = theme;
            // Also update DOM and localStorage via the app_state context
        },
    );
    (read, write)
}

pub fn use_sidebar_collapsed() -> (Signal<bool>, SignalSetter<bool>) {
    let app_state = use_app_state();
    let (read, write) = create_slice(
        app_state.state,
        |state| state.sidebar_collapsed,
        |state, collapsed: bool| state.sidebar_collapsed = collapsed,
    );
    (read, write)
}

pub fn use_loading() -> (Signal<bool>, SignalSetter<bool>) {
    let app_state = use_app_state();
    let (read, write) = create_slice(
        app_state.state,
        |state| state.loading,
        |state, loading: bool| state.loading = loading,
    );
    (read, write)
}

pub fn use_error() -> (Signal<Option<String>>, SignalSetter<Option<String>>) {
    let app_state = use_app_state();
    let (read, write) = create_slice(
        app_state.state,
        |state| state.error.clone(),
        |state, error: Option<String>| state.error = error,
    );
    (read, write)
}

fn get_system_theme_preference() -> &'static str {
    web_sys::window()
        .and_then(|w| w.match_media("(prefers-color-scheme: dark)").ok())
        .flatten()
        .map(|mq| if mq.matches() { "dark" } else { "light" })
        .unwrap_or("light")
}
