use leptos::prelude::*;
use leptos::context::Provider;
use crate::components::prelude::*;
use serde::{Serialize, Deserialize};
use rust_shared::repository::model::{ProxyType, ProxyFormat, PoolType, ProxyRegion, Profile};
use crate::utils::pool_utils::get_available_pools;

/// Convert ProxyRegion to string representation
pub fn proxy_region_to_string(region: &ProxyRegion) -> &'static str {
    match region {
        ProxyRegion::Auto => "auto",
        ProxyRegion::USA => "usa",
        ProxyRegion::Europe => "eur",
        ProxyRegion::Australia => "aus",
        ProxyRegion::Singapore => "sgp",
        ProxyRegion::Japan => "jpn",
        ProxyRegion::Brazil => "bra",
    }
}

/// Convert ProxyRegion to flag emoji
pub fn proxy_region_to_flag(region: &ProxyRegion) -> &'static str {
    match region {
        ProxyRegion::Auto => "🧠",
        ProxyRegion::USA => "🇺🇸",
        ProxyRegion::Europe => "🇪🇺",
        ProxyRegion::Australia => "🇦🇺",
        ProxyRegion::Singapore => "🇸🇬",
        ProxyRegion::Japan => "🇯🇵",
        ProxyRegion::Brazil => "🇧🇷",
    }
}

/// Convert ProxyRegion to translated display name
pub fn proxy_region_to_display_name(region: &ProxyRegion) -> String {
    match region {
        ProxyRegion::Auto => t8s!("AUTO").to_string(),
        ProxyRegion::USA => t8s!("USA").to_string(),
        ProxyRegion::Europe => t8s!("EUROPE").to_string(),
        ProxyRegion::Australia => t8s!("AUSTRALIA").to_string(),
        ProxyRegion::Singapore => t8s!("SINGAPORE").to_string(),
        ProxyRegion::Japan => t8s!("JAPAN").to_string(),
        ProxyRegion::Brazil => t8s!("BRAZIL").to_string(),
    }
}

/// Convert PoolType to translated display name
pub fn pool_type_to_display_name(pool_type: &PoolType) -> String {
    match pool_type {
        PoolType::Datacenter => t8s!("Datacenter").to_string(),
        PoolType::Residential => t8s!("Residential").to_string(),
        PoolType::ResidentialPremium => t8s!("Residential Premium").to_string(),
        PoolType::Mobile => t8s!("Mobile").to_string(),
    }
}

/// Convert PoolType to string representation for API
pub fn pool_type_to_string(pool_type: &PoolType) -> &'static str {
    match pool_type {
        PoolType::Datacenter => "datacenter",
        PoolType::Residential => "residential",
        PoolType::ResidentialPremium => "residential_premium",
        PoolType::Mobile => "mobile",
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ProxyParameters {
    pub pool_type: PoolType,
    pub server_region: ProxyRegion,
    pub countries: Vec<String>,
    pub states: Vec<String>,
    pub cities: Vec<String>,
    pub zip_codes: Vec<String>,
    pub protocol: String,
    pub proxy_type: ProxyType,
    pub proxy_count: u32,
    pub asn_include: Vec<String>,
    pub asn_exclude: Vec<String>,
    pub anonymity: bool,
    pub format: ProxyFormat,
}

impl Default for ProxyParameters {
    fn default() -> Self {
        Self {
            pool_type: PoolType::Datacenter, // Fallback when no profile available
            server_region: ProxyRegion::Auto,
            countries: vec![],
            states: vec![],
            cities: vec![],
            zip_codes: vec![],
            protocol: "https".to_string(),
            proxy_type: ProxyType::Rotating,
            proxy_count: 5,
            asn_include: vec![],
            asn_exclude: vec![],
            anonymity: true,
            format: ProxyFormat::default(),
        }
    }
}

impl ProxyParameters {
    /// Create default parameters with the first available pool from user's profile
    pub fn default_with_profile(profile: &Profile) -> Self {
        let available_pools = get_available_pools(profile);
        let pool_type = available_pools.first().copied().unwrap_or(PoolType::Datacenter);
        
        Self {
            pool_type,
            server_region: ProxyRegion::Auto,
            countries: vec![],
            states: vec![],
            cities: vec![],
            zip_codes: vec![],
            protocol: "https".to_string(),
            proxy_type: ProxyType::Rotating,
            proxy_count: 5,
            asn_include: vec![],
            asn_exclude: vec![],
            anonymity: true,
            format: ProxyFormat::default(),
        }
    }
}

// context for sharing proxy parameters across components
#[derive(Clone)]
pub struct ProxyParamsContext {
    pub parameters: RwSignal<ProxyParameters>,
    pub update_countries: Callback<Vec<String>>,
    pub update_states: Callback<Vec<String>>,
    pub update_cities: Callback<Vec<String>>,
    pub update_zip_codes: Callback<Vec<String>>,
    pub update_pool_type: Callback<PoolType>,
    pub update_server_region: Callback<ProxyRegion>,
    pub update_protocol: Callback<String>,
    pub update_proxy_count: Callback<u32>,
    pub update_proxy_type: Callback<ProxyType>,
    pub update_anonymity: Callback<bool>,
    pub update_asn_include: Callback<Vec<String>>,
    pub update_asn_exclude: Callback<Vec<String>>,
    pub update_format: Callback<ProxyFormat>,
    pub reset_to_defaults: Callback<()>,
}

impl ProxyParamsContext {
    const STORAGE_KEY: &'static str = "vproxy_proxy_parameters";
    
    fn load_from_storage() -> Option<ProxyParameters> {
        // Only try to access localStorage in browser environment
        #[cfg(target_arch = "wasm32")]
        {
            // Wrap in panic-safe block to prevent poisoning
            std::panic::catch_unwind(|| {
                if let Some(window) = web_sys::window() {
                    if let Ok(Some(storage)) = window.local_storage() {
                        if let Ok(Some(data)) = storage.get_item(Self::STORAGE_KEY) {
                            match serde_json::from_str::<ProxyParameters>(&data) {
                                Ok(params) => {
                                    log::info!("Loaded proxy parameters from localStorage");
                                    return Some(params);
                                }
                                Err(e) => {
                                    log::warn!("Failed to parse saved proxy parameters: {}", e);
                                }
                            }
                        }
                    }
                }
                None
            }).unwrap_or_else(|_| {
                log::warn!("Panic occurred while loading proxy parameters from localStorage");
                None
            })
        }
        #[cfg(not(target_arch = "wasm32"))]
        None
    }
    
    fn save_to_storage(params: &ProxyParameters) {
        // Only try to access localStorage in browser environment
        #[cfg(target_arch = "wasm32")]
        {
            // Wrap in panic-safe block to prevent poisoning
            let _ = std::panic::catch_unwind(|| {
                if let Some(window) = web_sys::window() {
                    if let Ok(Some(storage)) = window.local_storage() {
                        if let Ok(json) = serde_json::to_string(params) {
                            if let Err(e) = storage.set_item(Self::STORAGE_KEY, &json) {
                                log::warn!("Failed to save proxy parameters to localStorage: {:?}", e);
                            } else {
                                log::debug!("Saved proxy parameters to localStorage");
                            }
                        }
                    }
                }
            });
        }
    }
    
    pub fn clear_storage() {
        // Only try to access localStorage in browser environment
        #[cfg(target_arch = "wasm32")]
        {
            // Wrap in panic-safe block to prevent poisoning
            let _ = std::panic::catch_unwind(|| {
                if let Some(window) = web_sys::window() {
                    if let Ok(Some(storage)) = window.local_storage() {
                        if let Err(e) = storage.remove_item(Self::STORAGE_KEY) {
                            log::warn!("Failed to clear proxy parameters from localStorage: {:?}", e);
                        } else {
                            log::info!("Cleared proxy parameters from localStorage");
                        }
                    }
                }
            });
        }
    }
    
    pub fn new() -> Self {
        // Start with defaults to avoid any initialization panics
        let parameters = RwSignal::new(ProxyParameters::default());
        
        // Try to load from localStorage asynchronously after initialization
        #[cfg(target_arch = "wasm32")]
        {
            let parameters_clone = parameters.clone();
            // Use spawn_local to defer the localStorage access
            leptos::task::spawn_local(async move {
                if let Some(saved_params) = Self::load_from_storage() {
                    parameters_clone.set(saved_params);
                } else {
                    // If no saved params, try to initialize with user's available pools
                    let auth = crate::auth::use_auth();
                    if let Some(profile) = auth.get_profile() {
                        let default_params = ProxyParameters::default_with_profile(&profile);
                        parameters_clone.set(default_params);
                    }
                }
            });
        }
        
        let update_countries = Callback::new({
            let parameters = parameters.clone();
            move |countries: Vec<String>| {
                parameters.update(|p| {
                    p.countries = countries;
                    Self::save_to_storage(p);
                });
            }
        });
        
        let update_states = Callback::new({
            let parameters = parameters.clone();
            move |states: Vec<String>| {
                parameters.update(|p| {
                    p.states = states;
                    Self::save_to_storage(p);
                });
            }
        });
        
        let update_cities = Callback::new({
            let parameters = parameters.clone();
            move |cities: Vec<String>| {
                parameters.update(|p| {
                    p.cities = cities;
                    Self::save_to_storage(p);
                });
            }
        });
        
        let update_zip_codes = Callback::new({
            let parameters = parameters.clone();
            move |zip_codes: Vec<String>| {
                parameters.update(|p| {
                    p.zip_codes = zip_codes;
                    Self::save_to_storage(p);
                });
            }
        });
        
        let update_pool_type = Callback::new({
            let parameters = parameters.clone();
            move |pool_type: PoolType| {
                parameters.update(|p| {
                    p.pool_type = pool_type;
                    Self::save_to_storage(p);
                });
            }
        });
        
        let update_server_region = Callback::new({
            let parameters = parameters.clone();
            move |server_region: ProxyRegion| {
                parameters.update(|p| {
                    p.server_region = server_region;
                    Self::save_to_storage(p);
                });
            }
        });
        
        let update_protocol = Callback::new({
            let parameters = parameters.clone();
            move |protocol: String| {
                parameters.update(|p| {
                    p.protocol = protocol;
                    Self::save_to_storage(p);
                });
            }
        });
        
        let update_proxy_count = Callback::new({
            let parameters = parameters.clone();
            move |proxy_count: u32| {
                parameters.update(|p| {
                    p.proxy_count = proxy_count;
                    Self::save_to_storage(p);
                });
            }
        });
        
        let update_proxy_type = Callback::new({
            let parameters = parameters.clone();
            move |proxy_type: ProxyType| {
                parameters.update(|p| {
                    p.proxy_type = proxy_type;
                    Self::save_to_storage(p);
                });
            }
        });
        
        let update_anonymity = Callback::new({
            let parameters = parameters.clone();
            move |anonymity: bool| {
                parameters.update(|p| {
                    p.anonymity = anonymity;
                    Self::save_to_storage(p);
                });
            }
        });
        
        let update_asn_include = Callback::new({
            let parameters = parameters.clone();
            move |asn_include: Vec<String>| {
                parameters.update(|p| {
                    p.asn_include = asn_include;
                    Self::save_to_storage(p);
                });
            }
        });
        
        let update_asn_exclude = Callback::new({
            let parameters = parameters.clone();
            move |asn_exclude: Vec<String>| {
                parameters.update(|p| {
                    p.asn_exclude = asn_exclude;
                    Self::save_to_storage(p);
                });
            }
        });
        
        let update_format = Callback::new({
            let parameters = parameters.clone();
            move |format: ProxyFormat| {
                parameters.update(|p| {
                    p.format = format;
                    Self::save_to_storage(p);
                });
            }
        });

        let reset_to_defaults = Callback::new({
            let parameters = parameters.clone();
            move |_| {
                parameters.set(ProxyParameters::default());
                Self::clear_storage();
            }
        });

        Self {
            parameters,
            update_countries,
            update_states,
            update_cities,
            update_zip_codes,
            update_pool_type,
            update_server_region,
            update_protocol,
            update_proxy_count,
            update_proxy_type,
            update_anonymity,
            update_asn_include,
            update_asn_exclude,
            update_format,
            reset_to_defaults,
        }
    }
}

#[component]
pub fn ProxyParamsProvider(children: Children) -> impl IntoView {
    let context = ProxyParamsContext::new();
    
    view! {
        <Provider value=context>
            {children()}
        </Provider>
    }
}

pub fn use_proxy_params() -> ProxyParamsContext {
    use_context::<ProxyParamsContext>()
        .expect("ProxyParamsProvider must be used within ProxyParamsProvider")
}
