use std::sync::Arc;

use bevy::prelude::Resource;
use thiserror::Error;

/// Abstracts platform-specific clipboard access for gameplay UI systems.
pub trait ClipboardBackend: Send + Sync + 'static {
    /// Write plain text to the active OS clipboard.
    fn set_text(&self, text: &str) -> Result<(), ClipboardError>;
}

/// Bevy resource that exposes the active clipboard backend.
#[derive(Resource, Clone)]
pub struct ClipboardBackendResource(pub Arc<dyn ClipboardBackend>);

/// Errors surfaced by platform clipboard backends.
#[derive(Debug, Error)]
pub enum ClipboardError {
    #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
    #[error(transparent)]
    Native(#[from] arboard::Error),
    #[cfg(target_os = "android")]
    #[error("android clipboard failed: {0}")]
    Android(String),
    #[cfg(all(target_arch = "wasm32", not(target_os = "android")))]
    #[error("clipboard backend unavailable on wasm32")]
    Unsupported,
}

/// Construct the default clipboard backend for the current platform.
pub fn default_clipboard_backend() -> Result<Arc<dyn ClipboardBackend>, ClipboardError> {
    #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
    {
        Ok(Arc::new(NativeClipboardBackend))
    }

    #[cfg(target_os = "android")]
    {
        Ok(Arc::new(AndroidClipboardBackend))
    }

    #[cfg(all(target_arch = "wasm32", not(target_os = "android")))]
    {
        Err(ClipboardError::Unsupported)
    }
}

/// `arboard`-backed clipboard bridge for desktop targets.
#[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
#[derive(Debug, Default, Clone, Copy)]
pub struct NativeClipboardBackend;

#[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
impl ClipboardBackend for NativeClipboardBackend {
    fn set_text(&self, text: &str) -> Result<(), ClipboardError> {
        let mut clipboard = arboard::Clipboard::new()?;
        clipboard.set_text(text.to_string())?;
        Ok(())
    }
}

/// JNI-backed clipboard bridge for Android targets.
#[cfg(target_os = "android")]
#[derive(Debug, Default, Clone, Copy)]
pub struct AndroidClipboardBackend;

#[cfg(target_os = "android")]
impl ClipboardBackend for AndroidClipboardBackend {
    fn set_text(&self, text: &str) -> Result<(), ClipboardError> {
        crate::android_clipboard::set_text(text).map_err(ClipboardError::Android)
    }
}
