use poise::{
    serenity_prelude::{
        CreateActionRow, CreateEmbed, CreateEmbedFooter, CreateSelectMenu, CreateSelectMenuKind,
        CreateSelectMenuOption,
    },
    CreateReply,
};

use crate::{
    component_models::{
        pager::{Pager, TodoPager},
        ComponentDataModel, TodoSelector,
    },
    consts::{EMBED_DESCRIPTION_MAX_LENGTH, SELECT_MAX_ENTRIES, THEME_COLOR},
    Context, Error,
};

pub mod channel;
pub mod guild;
pub mod user;

/// Manage todo lists
#[poise::command(slash_command, default_member_permissions = "MANAGE_GUILD")]
pub async fn todo(_ctx: Context<'_>) -> Result<(), Error> {
    Ok(())
}

pub fn max_todo_page(todo_values: &[(usize, String)]) -> usize {
    let mut rows = 0;
    let mut char_count = 0;

    todo_values.iter().enumerate().map(|(c, (_, v))| format!("{}: {}", c, v)).fold(
        1,
        |mut pages, text| {
            rows += 1;
            char_count += text.len();

            if char_count > EMBED_DESCRIPTION_MAX_LENGTH || rows > SELECT_MAX_ENTRIES {
                rows = 1;
                char_count = text.len();
                pages += 1;
            }

            pages
        },
    )
}

pub fn show_todo_page(
    todo_values: &[(usize, String)],
    page: usize,
    user_id: Option<u64>,
    channel_id: Option<u64>,
    guild_id: Option<u64>,
) -> CreateReply {
    let pager = TodoPager::new(page, user_id, channel_id, guild_id);

    let pages = max_todo_page(todo_values);
    let mut page = page;
    if page >= pages {
        page = pages - 1;
    }

    let mut char_count = 0;
    let mut rows = 0;
    let mut skipped_rows = 0;
    let mut skipped_char_count = 0;
    let mut first_num = 0;

    let mut skipped_pages = 0;

    let (todo_ids, display_vec): (Vec<usize>, Vec<String>) = todo_values
        .iter()
        .enumerate()
        .map(|(c, (i, v))| (i, format!("`{}`: {}", c + 1, v)))
        .skip_while(|(_, p)| {
            first_num += 1;
            skipped_rows += 1;
            skipped_char_count += p.len();

            if skipped_char_count > EMBED_DESCRIPTION_MAX_LENGTH
                || skipped_rows > SELECT_MAX_ENTRIES
            {
                skipped_rows = 1;
                skipped_char_count = p.len();
                skipped_pages += 1;
            }

            skipped_pages < page
        })
        .take_while(|(_, p)| {
            rows += 1;
            char_count += p.len();

            char_count < EMBED_DESCRIPTION_MAX_LENGTH && rows <= SELECT_MAX_ENTRIES
        })
        .unzip();

    let display = display_vec.join("\n");

    let title = if user_id.is_some() {
        "Your"
    } else if channel_id.is_some() {
        "Channel"
    } else {
        "Server"
    };

    if todo_ids.is_empty() {
        CreateReply::default().embed(
            CreateEmbed::new()
                .title(format!("{} Todo List", title))
                .description("Todo List Empty!")
                .color(*THEME_COLOR)
                .footer(CreateEmbedFooter::new(format!("Page {} of {}", page + 1, pages))),
        )
    } else {
        let todo_selector =
            ComponentDataModel::TodoSelector(TodoSelector { page, user_id, channel_id, guild_id });

        CreateReply::default()
            .embed(
                CreateEmbed::new()
                    .title(format!("{} Todo List", title))
                    .description(display)
                    .color(*THEME_COLOR)
                    .footer(CreateEmbedFooter::new(format!("Page {} of {}", page + 1, pages))),
            )
            .components(vec![
                pager.create_button_row(pages),
                CreateActionRow::SelectMenu(CreateSelectMenu::new(
                    todo_selector.to_custom_id(),
                    CreateSelectMenuKind::String {
                        options: todo_ids
                            .iter()
                            .zip(&display_vec)
                            .enumerate()
                            .map(|(count, (id, disp))| {
                                let c = disp.split_once(' ').unwrap_or(("", "")).1;
                                let description = if c.len() > 100 {
                                    format!("{}...", c.chars().take(97).collect::<String>())
                                } else {
                                    c.to_string()
                                };

                                CreateSelectMenuOption::new(
                                    format!("Mark {} complete", count + first_num),
                                    id.to_string(),
                                )
                                .description(description)
                            })
                            .collect(),
                    },
                )),
            ])
    }
}
