// todo split pager out into a single struct
use chrono_tz::Tz;
use poise::serenity_prelude::{ButtonStyle, CreateActionRow, CreateButton};
use serde::{Deserialize, Serialize};
use serde_repr::*;

use crate::{commands::look::LookFlags, component_models::ComponentDataModel};

pub trait Pager {
    fn next_page(&self, max_pages: usize) -> usize;

    fn create_button_row(&self, max_pages: usize) -> CreateActionRow;
}

#[derive(Serialize_repr, Deserialize_repr)]
#[repr(u8)]
enum PageAction {
    First = 0,
    Previous = 1,
    Refresh = 2,
    Next = 3,
    Last = 4,
}

#[derive(Serialize, Deserialize)]
pub struct LookPager {
    pub flags: LookFlags,
    pub page: usize,
    action: PageAction,
    pub timezone: Tz,
}

impl Pager for LookPager {
    fn next_page(&self, max_pages: usize) -> usize {
        match self.action {
            PageAction::First => 0,
            PageAction::Previous => 0.max(self.page - 1),
            PageAction::Refresh => self.page,
            PageAction::Next => (max_pages - 1).min(self.page + 1),
            PageAction::Last => max_pages - 1,
        }
    }

    fn create_button_row(&self, max_pages: usize) -> CreateActionRow {
        let next_page = self.next_page(max_pages);

        let (page_first, page_prev, page_refresh, page_next, page_last) =
            LookPager::buttons(self.flags, next_page, self.timezone);

        CreateActionRow::Buttons(vec![
            CreateButton::new(page_first.to_custom_id())
                .label("⏮️")
                .style(ButtonStyle::Primary)
                .disabled(next_page == 0),
            CreateButton::new(page_prev.to_custom_id())
                .label("◀️")
                .style(ButtonStyle::Secondary)
                .disabled(next_page == 0),
            CreateButton::new(page_refresh.to_custom_id())
                .label("🔁")
                .style(ButtonStyle::Secondary),
            CreateButton::new(page_next.to_custom_id())
                .label("▶️")
                .style(ButtonStyle::Secondary)
                .disabled(next_page + 1 == max_pages),
            CreateButton::new(page_last.to_custom_id())
                .label("⏭️")
                .style(ButtonStyle::Primary)
                .disabled(next_page + 1 == max_pages),
        ])
    }
}

impl LookPager {
    pub fn new(flags: LookFlags, timezone: Tz) -> Self {
        Self { flags, page: 0, action: PageAction::First, timezone }
    }

    pub fn buttons(
        flags: LookFlags,
        page: usize,
        timezone: Tz,
    ) -> (
        ComponentDataModel,
        ComponentDataModel,
        ComponentDataModel,
        ComponentDataModel,
        ComponentDataModel,
    ) {
        (
            ComponentDataModel::LookPager(LookPager {
                flags,
                page,
                action: PageAction::First,
                timezone,
            }),
            ComponentDataModel::LookPager(LookPager {
                flags,
                page,
                action: PageAction::Previous,
                timezone,
            }),
            ComponentDataModel::LookPager(LookPager {
                flags,
                page,
                action: PageAction::Refresh,
                timezone,
            }),
            ComponentDataModel::LookPager(LookPager {
                flags,
                page,
                action: PageAction::Next,
                timezone,
            }),
            ComponentDataModel::LookPager(LookPager {
                flags,
                page,
                action: PageAction::Last,
                timezone,
            }),
        )
    }
}

#[derive(Serialize, Deserialize)]
pub struct DelPager {
    pub page: usize,
    action: PageAction,
    pub timezone: Tz,
}

impl Pager for DelPager {
    fn next_page(&self, max_pages: usize) -> usize {
        match self.action {
            PageAction::First => 0,
            PageAction::Previous => 0.max(self.page - 1),
            PageAction::Refresh => self.page,
            PageAction::Next => (max_pages - 1).min(self.page + 1),
            PageAction::Last => max_pages - 1,
        }
    }

    fn create_button_row(&self, max_pages: usize) -> CreateActionRow {
        let next_page = self.next_page(max_pages);

        let (page_first, page_prev, page_refresh, page_next, page_last) =
            DelPager::buttons(next_page, self.timezone);

        CreateActionRow::Buttons(vec![
            CreateButton::new(page_first.to_custom_id())
                .label("⏮️")
                .style(ButtonStyle::Primary)
                .disabled(next_page == 0),
            CreateButton::new(page_prev.to_custom_id())
                .label("◀️")
                .style(ButtonStyle::Secondary)
                .disabled(next_page == 0),
            CreateButton::new(page_refresh.to_custom_id())
                .label("🔁")
                .style(ButtonStyle::Secondary),
            CreateButton::new(page_next.to_custom_id())
                .label("▶️")
                .style(ButtonStyle::Secondary)
                .disabled(next_page + 1 == max_pages),
            CreateButton::new(page_last.to_custom_id())
                .label("⏭️")
                .style(ButtonStyle::Primary)
                .disabled(next_page + 1 == max_pages),
        ])
    }
}

impl DelPager {
    pub fn new(page: usize, timezone: Tz) -> Self {
        Self { page, action: PageAction::Refresh, timezone }
    }

    pub fn buttons(
        page: usize,
        timezone: Tz,
    ) -> (
        ComponentDataModel,
        ComponentDataModel,
        ComponentDataModel,
        ComponentDataModel,
        ComponentDataModel,
    ) {
        (
            ComponentDataModel::DelPager(DelPager { page, action: PageAction::First, timezone }),
            ComponentDataModel::DelPager(DelPager { page, action: PageAction::Previous, timezone }),
            ComponentDataModel::DelPager(DelPager { page, action: PageAction::Refresh, timezone }),
            ComponentDataModel::DelPager(DelPager { page, action: PageAction::Next, timezone }),
            ComponentDataModel::DelPager(DelPager { page, action: PageAction::Last, timezone }),
        )
    }
}

#[derive(Deserialize, Serialize)]
pub struct TodoPager {
    pub page: usize,
    action: PageAction,
    pub user_id: Option<u64>,
    pub channel_id: Option<u64>,
    pub guild_id: Option<u64>,
}

impl Pager for TodoPager {
    fn next_page(&self, max_pages: usize) -> usize {
        match self.action {
            PageAction::First => 0,
            PageAction::Previous => 0.max(self.page - 1),
            PageAction::Refresh => self.page,
            PageAction::Next => (max_pages - 1).min(self.page + 1),
            PageAction::Last => max_pages - 1,
        }
    }

    fn create_button_row(&self, max_pages: usize) -> CreateActionRow {
        let next_page = self.next_page(max_pages);

        let (page_first, page_prev, page_refresh, page_next, page_last) =
            TodoPager::buttons(next_page, self.user_id, self.channel_id, self.guild_id);

        CreateActionRow::Buttons(vec![
            CreateButton::new(page_first.to_custom_id())
                .label("⏮️")
                .style(ButtonStyle::Primary)
                .disabled(next_page == 0),
            CreateButton::new(page_prev.to_custom_id())
                .label("◀️")
                .style(ButtonStyle::Secondary)
                .disabled(next_page == 0),
            CreateButton::new(page_refresh.to_custom_id())
                .label("🔁")
                .style(ButtonStyle::Secondary),
            CreateButton::new(page_next.to_custom_id())
                .label("▶️")
                .style(ButtonStyle::Secondary)
                .disabled(next_page + 1 == max_pages),
            CreateButton::new(page_last.to_custom_id())
                .label("⏭️")
                .style(ButtonStyle::Primary)
                .disabled(next_page + 1 == max_pages),
        ])
    }
}

impl TodoPager {
    pub fn new(
        page: usize,
        user_id: Option<u64>,
        channel_id: Option<u64>,
        guild_id: Option<u64>,
    ) -> Self {
        Self { page, action: PageAction::Refresh, user_id, channel_id, guild_id }
    }

    pub fn buttons(
        page: usize,
        user_id: Option<u64>,
        channel_id: Option<u64>,
        guild_id: Option<u64>,
    ) -> (
        ComponentDataModel,
        ComponentDataModel,
        ComponentDataModel,
        ComponentDataModel,
        ComponentDataModel,
    ) {
        (
            ComponentDataModel::TodoPager(TodoPager {
                page,
                action: PageAction::First,
                user_id,
                channel_id,
                guild_id,
            }),
            ComponentDataModel::TodoPager(TodoPager {
                page,
                action: PageAction::Previous,
                user_id,
                channel_id,
                guild_id,
            }),
            ComponentDataModel::TodoPager(TodoPager {
                page,
                action: PageAction::Refresh,
                user_id,
                channel_id,
                guild_id,
            }),
            ComponentDataModel::TodoPager(TodoPager {
                page,
                action: PageAction::Next,
                user_id,
                channel_id,
                guild_id,
            }),
            ComponentDataModel::TodoPager(TodoPager {
                page,
                action: PageAction::Last,
                user_id,
                channel_id,
                guild_id,
            }),
        )
    }
}

#[derive(Serialize, Deserialize)]
pub struct MacroPager {
    pub page: usize,
    action: PageAction,
}

impl Pager for MacroPager {
    fn next_page(&self, max_pages: usize) -> usize {
        match self.action {
            PageAction::First => 0,
            PageAction::Previous => 0.max(self.page - 1),
            PageAction::Refresh => self.page,
            PageAction::Next => (max_pages - 1).min(self.page + 1),
            PageAction::Last => max_pages - 1,
        }
    }

    fn create_button_row(&self, max_pages: usize) -> CreateActionRow {
        let next_page = self.next_page(max_pages);

        let (page_first, page_prev, page_refresh, page_next, page_last) =
            MacroPager::buttons(next_page);

        CreateActionRow::Buttons(vec![
            CreateButton::new(page_first.to_custom_id())
                .label("⏮️")
                .style(ButtonStyle::Primary)
                .disabled(next_page == 0),
            CreateButton::new(page_prev.to_custom_id())
                .label("◀️")
                .style(ButtonStyle::Secondary)
                .disabled(next_page == 0),
            CreateButton::new(page_refresh.to_custom_id())
                .label("🔁")
                .style(ButtonStyle::Secondary),
            CreateButton::new(page_next.to_custom_id())
                .label("▶️")
                .style(ButtonStyle::Secondary)
                .disabled(next_page + 1 == max_pages),
            CreateButton::new(page_last.to_custom_id())
                .label("⏭️")
                .style(ButtonStyle::Primary)
                .disabled(next_page + 1 == max_pages),
        ])
    }
}

impl MacroPager {
    pub fn new(page: usize) -> Self {
        Self { page, action: PageAction::Refresh }
    }

    pub fn buttons(
        page: usize,
    ) -> (
        ComponentDataModel,
        ComponentDataModel,
        ComponentDataModel,
        ComponentDataModel,
        ComponentDataModel,
    ) {
        (
            ComponentDataModel::MacroPager(MacroPager { page, action: PageAction::First }),
            ComponentDataModel::MacroPager(MacroPager { page, action: PageAction::Previous }),
            ComponentDataModel::MacroPager(MacroPager { page, action: PageAction::Refresh }),
            ComponentDataModel::MacroPager(MacroPager { page, action: PageAction::Next }),
            ComponentDataModel::MacroPager(MacroPager { page, action: PageAction::Last }),
        )
    }
}
