use std::fmt;

/// Which list the sidebar is currently showing.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SidebarView {
    Posts,
    Pages,
    Media,
    Scripts,
    Templates,
    Tags,
    Chat,
    Import,
    Git,
    Settings,
}

impl fmt::Display for SidebarView {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let key = self.i18n_key();
        f.write_str(key)
    }
}

impl SidebarView {
    pub fn as_str(self) -> &'static str {
        match self {
            Self::Posts => "posts",
            Self::Pages => "pages",
            Self::Media => "media",
            Self::Scripts => "scripts",
            Self::Templates => "templates",
            Self::Tags => "tags",
            Self::Chat => "chat",
            Self::Import => "import",
            Self::Git => "git",
            Self::Settings => "settings",
        }
    }

    pub fn from_persisted(value: &str) -> Option<Self> {
        Some(match value {
            "posts" => Self::Posts,
            "pages" => Self::Pages,
            "media" => Self::Media,
            "scripts" => Self::Scripts,
            "templates" => Self::Templates,
            "tags" => Self::Tags,
            "chat" => Self::Chat,
            "import" => Self::Import,
            "git" => Self::Git,
            "settings" => Self::Settings,
            _ => return None,
        })
    }

    /// Returns the `activity.*` i18n key for this sidebar view.
    pub fn i18n_key(&self) -> &'static str {
        match self {
            Self::Posts => "activity.posts",
            Self::Pages => "activity.pages",
            Self::Media => "activity.media",
            Self::Scripts => "activity.scripts",
            Self::Templates => "activity.templates",
            Self::Tags => "activity.tags",
            Self::Chat => "activity.aiAssistant",
            Self::Import => "activity.import",
            Self::Git => "activity.sourceControl",
            Self::Settings => "common.settings",
        }
    }
}

/// Which tab is selected in the bottom panel.
///
/// Per layout.allium: tasks, output, post_links, git_log.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PanelTab {
    Tasks,
    Output,
    PostLinks,
    GitLog,
}

impl PanelTab {
    pub fn as_str(self) -> &'static str {
        match self {
            Self::Tasks => "tasks",
            Self::Output => "output",
            Self::PostLinks => "post_links",
            Self::GitLog => "git_log",
        }
    }

    pub fn from_persisted(value: &str) -> Option<Self> {
        Some(match value {
            "tasks" => Self::Tasks,
            "output" => Self::Output,
            "post_links" => Self::PostLinks,
            "git_log" => Self::GitLog,
            _ => return None,
        })
    }
}

/// A snapshot of a running or completed task shown in the panel.
#[derive(Debug, Clone)]
pub struct TaskSnapshot {
    pub id: u64,
    pub source: TaskSource,
    pub label: String,
    pub group_id: Option<String>,
    pub group_name: Option<String>,
    pub status: bds_core::engine::task::TaskStatus,
    pub progress: Option<f32>,
    pub message: Option<String>,
    pub cancellation_requested: bool,
    pub is_cancellable: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TaskSource {
    Local,
    Remote,
}

/// A single line of output shown in the panel.
#[derive(Debug, Clone)]
pub struct OutputEntry {
    pub timestamp: i64,
    pub text: String,
}

/// Determine the next `(SidebarView, sidebar_visible)` after a user clicks
/// an activity-bar icon.
///
/// * Same icon + visible  -> toggle sidebar off
/// * Same icon + hidden   -> toggle sidebar on
/// * Different icon       -> switch view and ensure visible
pub fn handle_activity_click(
    current_view: SidebarView,
    sidebar_visible: bool,
    clicked: SidebarView,
) -> (SidebarView, bool) {
    if clicked == current_view {
        (current_view, !sidebar_visible)
    } else {
        (clicked, true)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn toggle_off_when_same_and_visible() {
        let (view, visible) = handle_activity_click(SidebarView::Posts, true, SidebarView::Posts);
        assert_eq!(view, SidebarView::Posts);
        assert!(!visible);
    }

    #[test]
    fn toggle_on_when_same_and_hidden() {
        let (view, visible) = handle_activity_click(SidebarView::Posts, false, SidebarView::Posts);
        assert_eq!(view, SidebarView::Posts);
        assert!(visible);
    }

    #[test]
    fn switch_view_when_different() {
        let (view, visible) = handle_activity_click(SidebarView::Posts, true, SidebarView::Media);
        assert_eq!(view, SidebarView::Media);
        assert!(visible);
    }

    #[test]
    fn switch_view_when_different_and_hidden() {
        let (view, visible) =
            handle_activity_click(SidebarView::Posts, false, SidebarView::Settings);
        assert_eq!(view, SidebarView::Settings);
        assert!(visible);
    }

    #[test]
    fn display_returns_i18n_key() {
        assert_eq!(SidebarView::Posts.to_string(), "activity.posts");
        assert_eq!(SidebarView::Settings.to_string(), "common.settings");
    }

    #[test]
    fn persisted_navigation_names_round_trip() {
        for view in [
            SidebarView::Posts,
            SidebarView::Pages,
            SidebarView::Media,
            SidebarView::Scripts,
            SidebarView::Templates,
            SidebarView::Tags,
            SidebarView::Chat,
            SidebarView::Import,
            SidebarView::Git,
            SidebarView::Settings,
        ] {
            assert_eq!(SidebarView::from_persisted(view.as_str()), Some(view));
        }
        for tab in [
            PanelTab::Tasks,
            PanelTab::Output,
            PanelTab::PostLinks,
            PanelTab::GitLog,
        ] {
            assert_eq!(PanelTab::from_persisted(tab.as_str()), Some(tab));
        }
        assert_eq!(SidebarView::from_persisted("unknown"), None);
        assert_eq!(PanelTab::from_persisted("unknown"), None);
    }
}
