use super::*;
use std::io::{self, Write};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Mutex;

pub fn print_line<T: fmt::Display>(line: T) {
    let to_print = format!("{line}");
    if to_print.is_empty() {
        return;
    }
    print_wasm!("{to_print}");
    io::stdout().flush().unwrap();
}

pub fn get_input<T: fmt::Display>(q: T, io_reader: &IoReader) -> String {
    print_line(q);
    io_reader.read_line()
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CustomDebug<T> {
    item: T,
    debug_message_func: Arc<fn(&T) -> String>,
}

impl<T> CustomDebug<T> {
    pub fn new(item: T, debug_message_func: fn(&T) -> String) -> Self {
        Self {
            item,
            debug_message_func: debug_message_func.into(),
        }
    }

    pub fn get_debug_message_func(&self) -> &fn(&T) -> String {
        &self.debug_message_func
    }

    pub fn get_debug_message(&self) -> String {
        (self.debug_message_func)(&self.item)
    }

    pub fn into_inner(&self) -> &T {
        &self.item
    }

    pub fn into_inner_mut(&mut self) -> &mut T {
        &mut self.item
    }
}

impl<T: Debug> Debug for CustomDebug<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let debug_message = self.get_debug_message();
        write!(f, "{}", debug_message)
    }
}

impl<T> Deref for CustomDebug<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.item
    }
}

impl<T> DerefMut for CustomDebug<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.item
    }
}

impl<T: Debug> From<T> for CustomDebug<T> {
    fn from(value: T) -> Self {
        Self::new(value, |item| format!("{item:?}"))
    }
}

#[derive(Clone, Debug)]
pub struct IoReader {
    sender: Sender<String>,
    receiver: Arc<Mutex<Receiver<String>>>,
}

impl IoReader {
    pub fn new() -> Self {
        let (sender, receiver) = channel();
        Self {
            sender,
            receiver: Mutex::new(receiver).into(),
        }
    }

    pub fn start_reader_in_parallel(&self) -> thread::JoinHandle<()> {
        let sender = self.sender.clone();
        thread::spawn(move || loop {
            let mut user_input = String::new();
            std::io::stdin()
                .read_line(&mut user_input)
                .expect("Failed to read line!");
            let _ = sender.send(user_input);
        })
    }

    pub fn read_line_once(&self) -> Option<String> {
        self.receiver
            .lock()
            .unwrap()
            .recv_timeout(COMMUNICATION_CHECK_INTERVAL)
            .ok()
    }

    pub fn read_line(&self) -> String {
        loop {
            if let Some(input) = self.read_line_once() {
                return input;
            }
        }
    }
}

impl Default for IoReader {
    fn default() -> Self {
        Self::new()
    }
}

const IO_READER_SERDE_STR: &str = "IoReader";

#[cfg(feature = "serde")]
impl Serialize for IoReader {
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        IO_READER_SERDE_STR.serialize(serializer)
    }
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for IoReader {
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let deserialized = <&str>::deserialize(deserializer)?;
        if deserialized != IO_READER_SERDE_STR {
            return Err(serde::de::Error::invalid_value(
                serde::de::Unexpected::Str(deserialized),
                &IO_READER_SERDE_STR,
            ));
        }
        Ok(Self::new())
    }
}
