use client_shared::{API_CONNECTION_TIMEOUT, message::Message, persistence::Appdata, utils::{ConnectionError, rx_messages, tx_message}};
use cursive::{views::TextArea, Cursive};
use utils::hash::Hashable as _;

use crate::{get_appdata, ui};


// TODO (low): Create proper user objects. Related: add a way to verify a user.
pub fn on_user_click(siv: &mut Cursive, user: &str) {
    let language = get_appdata(siv).persistent_data.language;
    ui::alert(siv, ui::Labels::User.localize(language), user.into());
}

pub fn on_message_click(siv: &mut Cursive, message_id: &str) {
    let appdata = get_appdata(siv);
    let language = appdata.persistent_data.language;
    let message = appdata.messages.get(message_id);

    if let Some(message) = message {
        ui::copyable(
            siv,
            ui::Labels::Message.localize(appdata.persistent_data.language),
            format!(
                "{}: {}\n{}: {}\n{}: {}\n{}: {}",
                ui::Labels::Time.localize(language), message.time,
                ui::Labels::Channel.localize(language), message.channel,
                ui::Labels::Sender.localize(language), message.sender,
                ui::Labels::Content.localize(language), message.content
            ),
        );
    }
}

// TODO: Sending in progress pop-up for slow connections. Currently just hangs the application.
pub fn on_input_submit(siv: &mut Cursive, input_field_id: &str) {
    let text = siv
        .call_on_name(input_field_id, |view: &mut TextArea| {
            view.get_content().to_string()
        })
        .expect("Failed to retrieve input field content.");

    let appdata = get_appdata(siv);
    let language = appdata.persistent_data.language;
    let channel = appdata.persistent_data.current_channel;

    let message = Message::new(&appdata.persistent_data.username, &text, &channel);
    if message.is_valid() {
        // NOTE:
        // If an error was shown during send, it's likely that loading will fail too
        // so we don't need to show it again
        let mut error_dialogue_shown = false;

        match send_message(siv, message) {
            Ok(_) => clear_input_field(siv),
            Err(e) => {
                error_dialogue_shown = true;
                ui::error(siv, ui::Labels::FailedToSendMessage(e).localize(language))
            }
        };

        let res = load_messages(siv);
        if let Err(e) = res {
            if !error_dialogue_shown {
                ui::error(siv, ui::Labels::FailedToLoadMessages(e).localize(language));
            }
        } else {
            ui::alert(
                siv,
                ui::Labels::Success.localize(language),
                ui::Labels::SuccessfullySentMessage.localize(language),
            );
        }
    } else if !text.is_empty() {
        // Invalid message
        ui::error(siv, ui::Labels::InvalidMessage.localize(language));
    }

    ui::visual_update(siv);
}

pub fn clear_input_field(siv: &mut Cursive) {
    siv.call_on_name(ui::INPUT_FIELD_ID, |view: &mut TextArea| {
        view.set_content("");
    })
    .expect("Failed to clear input field.");
}

pub fn send_message(siv: &mut Cursive, mut message: Message) -> Result<(), ConnectionError> {
    message.sanitize();

    let appdata = get_appdata(siv);
    let url = appdata.persistent_data.api_endpoint;
    let password = appdata.persistent_data.api_password;

    tx_message(&url, &password, API_CONNECTION_TIMEOUT, message)
}

pub fn load_messages(siv: &mut Cursive) -> Result<(), ConnectionError> {
    let appdata = get_appdata(siv);
    let url = appdata.persistent_data.api_endpoint;
    let password = appdata.persistent_data.api_password;

    let messages = rx_messages(&url, &password, API_CONNECTION_TIMEOUT)?;

    siv.with_user_data(|appdata: &mut Appdata| {
        for message in messages {
            appdata.messages.insert(message.hash().to_string(), message);
        }
    });

    Ok(())
}
