use crate::countries::country_utils::get_flag_tooltip;
use crate::countries::flags_pictures::ICONS_SIZE_BIG;
use crate::gui::components::header::get_button_settings;
use crate::gui::components::tab::get_pages_tabs;
use crate::gui::components::types::my_modal::MyModal;
use crate::gui::pages::overview_page::item_bar;
use crate::gui::pages::types::settings_page::SettingsPage;
use crate::gui::styles::container::ContainerType;
use crate::gui::styles::rule::RuleType;
use crate::gui::styles::scrollbar::ScrollbarType;
use crate::gui::styles::style_constants::{FONT_SIZE_FOOTER, TOOLTIP_DELAY};
use crate::gui::styles::text::TextType;
use crate::gui::types::message::Message;
use crate::gui::types::settings::Settings;
use crate::networking::types::data_info::DataInfo;
use crate::networking::types::data_info_host::DataInfoHost;
use crate::networking::types::data_representation::DataRepr;
use crate::networking::types::host::Host;
use crate::networking::types::program_lookup::ProgramLookup;
use crate::networking::types::service::Service;
use crate::notifications::types::logged_notification::{
    BlacklistedTransmitted, DataThresholdExceeded, FavoriteTransmitted, LoggedNotification,
};
use crate::report::types::sort_type::SortType;
use crate::translations::translations::{
    clear_all_translation, favorite_transmitted_translation, no_notifications_received_translation,
    no_notifications_set_translation, only_last_30_translation, per_second_translation,
    threshold_translation,
};
use crate::translations::translations_5::blacklisted_transmitted_translation;
use crate::utils::types::icon::Icon;
use crate::{Language, RunningPage, Sniffer, StyleType};
use iced::Length::FillPortion;
use iced::widget::scrollable::Direction;
use iced::widget::text::LineHeight;
use iced::widget::tooltip::Position;
use iced::widget::{Column, Container, Row, Scrollable, Text, Tooltip};
use iced::widget::{Space, button};
use iced::{Alignment, Element, Length, Padding};
use std::cmp::max;

/// Computes the body of gui notifications page
pub fn notifications_page(sniffer: &Sniffer) -> Container<'_, Message, StyleType> {
    let Settings {
        language,
        ref notifications,
        ..
    } = sniffer.conf.settings;

    let mut tab_and_body = Column::new()
        .align_x(Alignment::Center)
        .height(Length::Fill);

    let tabs = get_pages_tabs(
        RunningPage::Notifications,
        language,
        sniffer.unread_notifications,
    );

    tab_and_body = tab_and_body.push(tabs);

    if notifications.data_notification.threshold.is_none()
        && !notifications.favorite_notification.is_active
        && !notifications.ip_blacklist_notification.is_active
        && sniffer.logged_notifications.is_empty()
    {
        let body = body_no_notifications_set(language);
        tab_and_body = tab_and_body.push(body);
    } else if sniffer.logged_notifications.is_empty() {
        let body = body_no_notifications_received(language, &sniffer.dots_pulse.0);
        tab_and_body = tab_and_body.push(body);
    } else {
        let logged_notifications = logged_notifications(sniffer);
        let body_row = Row::new()
            .spacing(10)
            .padding(Padding::new(10.0).bottom(0))
            .push(
                Container::new(if sniffer.logged_notifications.len() < 30 {
                    Text::new("")
                } else {
                    Text::new(only_last_30_translation(language))
                })
                .width(150)
                .height(Length::Fill)
                .align_x(Alignment::Center)
                .align_y(Alignment::Center),
            )
            .push(Scrollable::with_direction(
                logged_notifications,
                Direction::Vertical(ScrollbarType::properties()),
            ))
            .push(
                Container::new(get_button_clear_all(language))
                    .width(150)
                    .height(Length::Fill)
                    .align_x(Alignment::Center)
                    .align_y(Alignment::Center),
            );
        tab_and_body = tab_and_body.push(body_row);
    }

    Container::new(Column::new().push(tab_and_body)).height(Length::Fill)
}

fn body_no_notifications_set<'a>(language: Language) -> Column<'a, Message, StyleType> {
    Column::new()
        .padding(5)
        .spacing(5)
        .align_x(Alignment::Center)
        .width(Length::Fill)
        .push(Space::new().height(Length::Fill))
        .push(no_notifications_set_translation(language).align_x(Alignment::Center))
        .push(get_button_settings(language, SettingsPage::Notifications))
        .push(Space::new().height(FillPortion(2)))
}

fn body_no_notifications_received(
    language: Language,
    dots: &str,
) -> Column<'_, Message, StyleType> {
    Column::new()
        .padding(5)
        .spacing(5)
        .align_x(Alignment::Center)
        .width(Length::Fill)
        .push(Space::new().height(Length::Fill))
        .push(no_notifications_received_translation(language).align_x(Alignment::Center))
        .push(Text::new(dots).size(50))
        .push(Space::new().height(FillPortion(2)))
}

fn data_notification_log<'a>(
    logged_notification: &DataThresholdExceeded,
    first_entry_data_info: DataInfo,
    language: Language,
) -> Container<'a, Message, StyleType> {
    let data_info = logged_notification.data_info;
    let data_repr = logged_notification.data_repr;
    let threshold_bar = item_bar(
        Space::new().width(ICONS_SIZE_BIG),
        String::new(),
        &data_info,
        data_repr,
        first_entry_data_info,
    );

    let data_string = data_repr.formatted_string(logged_notification.threshold.into());
    let icon = if data_repr == DataRepr::Packets {
        Icon::PacketsThreshold
    } else {
        Icon::BytesThreshold
    }
    .to_text()
    .size(80)
    .line_height(LineHeight::Relative(1.0));
    let threshold_str = format!(
        "{}: {data_string} {}",
        threshold_translation(language),
        per_second_translation(language)
    );
    let content = Row::new()
        .align_y(Alignment::Center)
        .spacing(30)
        .push(icon)
        .push(
            Column::new()
                .spacing(7)
                .width(250)
                .push(
                    Row::new()
                        .spacing(8)
                        .push(Icon::Clock.to_text())
                        .push(Text::new(logged_notification.timestamp.clone())),
                )
                .push(
                    Text::new(data_repr.data_exceeded_translation(language).to_string())
                        .class(TextType::Title),
                )
                .push(
                    Text::new(threshold_str)
                        .class(TextType::Subtitle)
                        .size(FONT_SIZE_FOOTER),
                ),
        )
        .push(threshold_bar);
    let content_and_extra = Column::new()
        .spacing(10)
        .push(content)
        .push(button_expand(
            logged_notification.id,
            logged_notification.is_expanded,
        ))
        .push(data_notification_extra(logged_notification, language));
    Container::new(content_and_extra)
        .width(Length::Fill)
        .padding(15)
        .class(ContainerType::BorderedRound)
}

fn favorite_notification_log<'a>(
    logged_notification: &'a FavoriteTransmitted,
    first_entry_data_info: DataInfo,
    data_repr: DataRepr,
    language: Language,
    program_lookup: Option<&'a ProgramLookup>,
) -> Container<'a, Message, StyleType> {
    let favorite = &logged_notification.favorite;
    let icon = favorite.icon(language, program_lookup, true, 1.0);
    let item_bar = item_bar(
        icon,
        favorite.to_entry_string(),
        &favorite.data_info(),
        data_repr,
        first_entry_data_info,
    );

    let content = Row::new()
        .spacing(30)
        .align_y(Alignment::Center)
        .push(
            Icon::StarEmpty
                .to_text()
                .size(80)
                .line_height(LineHeight::Relative(1.0)),
        )
        .push(
            Column::new()
                .width(250)
                .spacing(7)
                .push(
                    Row::new()
                        .spacing(8)
                        .push(Icon::Clock.to_text())
                        .push(Text::new(logged_notification.timestamp.clone())),
                )
                .push(Text::new(favorite_transmitted_translation(language)).class(TextType::Title)),
        )
        .push(item_bar);

    Container::new(content)
        .width(Length::Fill)
        .padding(15)
        .class(ContainerType::BorderedRound)
}

fn blacklisted_notification_log<'a>(
    logged_notification: &BlacklistedTransmitted,
    first_entry_data_info: DataInfo,
    data_repr: DataRepr,
    language: Language,
) -> Container<'a, Message, StyleType> {
    let host = &logged_notification.host;
    let data_info_host = logged_notification.data_info_host;
    let icon = get_flag_tooltip(host.country, &data_info_host, language, false, 1.0);
    let blacklisted_bar = item_bar(
        icon,
        host.to_blacklist_string(logged_notification.ip),
        &data_info_host.data_info,
        data_repr,
        first_entry_data_info,
    );

    let content = Row::new()
        .spacing(30)
        .align_y(Alignment::Center)
        .push(
            Icon::Forbidden
                .to_text()
                .size(80)
                .line_height(LineHeight::Relative(1.0)),
        )
        .push(
            Column::new()
                .width(250)
                .spacing(7)
                .push(
                    Row::new()
                        .spacing(8)
                        .push(Icon::Clock.to_text())
                        .push(Text::new(logged_notification.timestamp.clone())),
                )
                .push(
                    Text::new(blacklisted_transmitted_translation(language)).class(TextType::Title),
                ),
        )
        .push(blacklisted_bar);

    Container::new(content)
        .width(Length::Fill)
        .padding(15)
        .class(ContainerType::BorderedRound)
}

fn get_button_clear_all<'a>(language: Language) -> Tooltip<'a, Message, StyleType> {
    let content = button(
        Icon::Bin
            .to_text()
            .size(20)
            .align_x(Alignment::Center)
            .align_y(Alignment::Center),
    )
    .padding(10)
    .height(50)
    .width(75)
    .on_press(Message::ShowModal(MyModal::ClearAll));

    Tooltip::new(
        content,
        Text::new(clear_all_translation(language)),
        Position::Top,
    )
    .gap(5)
    .class(ContainerType::Tooltip)
    .delay(TOOLTIP_DELAY)
}

fn logged_notifications(sniffer: &Sniffer) -> Column<'_, Message, StyleType> {
    let Settings { language, .. } = sniffer.conf.settings;
    let data_repr = sniffer.conf.data_repr;
    let mut ret_val = Column::new()
        .padding(Padding::ZERO.right(15).bottom(10))
        .spacing(10)
        .align_x(Alignment::Center);

    let first_entry_data_info = sniffer
        .logged_notifications
        .notifications()
        .iter()
        .map(LoggedNotification::data_info)
        .max_by(|d1, d2| d1.compare(d2, SortType::Ascending, data_repr))
        .unwrap_or_default();

    for logged_notification in sniffer.logged_notifications.notifications() {
        ret_val = ret_val.push(match logged_notification {
            LoggedNotification::DataThresholdExceeded(data_threshold_exceeded) => {
                data_notification_log(data_threshold_exceeded, first_entry_data_info, language)
            }
            LoggedNotification::FavoriteTransmitted(favorite_transmitted) => {
                favorite_notification_log(
                    favorite_transmitted,
                    first_entry_data_info,
                    data_repr,
                    language,
                    sniffer.program_lookup.as_ref(),
                )
            }
            LoggedNotification::BlacklistedTransmitted(blacklisted_transmitted) => {
                blacklisted_notification_log(
                    blacklisted_transmitted,
                    first_entry_data_info,
                    data_repr,
                    language,
                )
            }
        });
    }
    ret_val
}

fn button_expand<'a>(
    notification_id: usize,
    is_expanded: bool,
) -> Container<'a, Message, StyleType> {
    let button = button(
        if is_expanded {
            Icon::SortAscending
        } else {
            Icon::SortDescending
        }
        .to_text()
        .size(11)
        .align_x(Alignment::Center)
        .align_y(Alignment::Center),
    )
    .padding(Padding::ZERO.top(if is_expanded { 0 } else { 2 }))
    .width(25)
    .height(25)
    .on_press(Message::ExpandNotification(notification_id, !is_expanded));

    Container::new(button)
        .padding(Padding::ZERO.left(427))
        .align_y(Alignment::Center)
}

fn data_notification_extra<'a>(
    logged_notification: &DataThresholdExceeded,
    language: Language,
) -> Option<Row<'a, Message, StyleType>> {
    let max_entries = max(
        logged_notification.hosts.len(),
        logged_notification.services.len(),
    );
    if !logged_notification.is_expanded || max_entries == 0 {
        return None;
    }
    let spacing = 10.0;
    #[allow(clippy::cast_precision_loss)]
    let height = (ICONS_SIZE_BIG + spacing) * max_entries as f32;

    let mut hosts_col = Column::new().spacing(spacing).width(Length::FillPortion(5));
    let first_data_info = logged_notification
        .hosts
        .first()
        .unwrap_or(&(Host::default(), DataInfoHost::default()))
        .1
        .data_info;
    for (host, data_info_host) in &logged_notification.hosts {
        let icon = get_flag_tooltip(host.country, data_info_host, language, false, 1.0);
        let host_bar = item_bar(
            icon,
            host.to_entry_string(),
            &data_info_host.data_info,
            logged_notification.data_repr,
            first_data_info,
        );
        hosts_col = hosts_col.push(host_bar);
    }

    let mut services_col = Column::new().spacing(spacing).width(Length::FillPortion(2));
    let first_data_info_service = logged_notification
        .services
        .first()
        .unwrap_or(&(Service::default(), DataInfo::default()))
        .1;
    for (service, data_info) in &logged_notification.services {
        let service_bar = item_bar(
            None::<Element<Message, StyleType>>,
            service.to_string(),
            data_info,
            logged_notification.data_repr,
            first_data_info_service,
        );
        services_col = services_col.push(service_bar);
    }

    Some(
        Row::new()
            .push(hosts_col)
            .push(Container::new(RuleType::Standard.vertical(30)).height(height))
            .push(services_col),
    )
}
