use ratatui::{
    style::{Color, Modifier, Style},
    text::{Line, Span},
};

use fido_types::{ActivityItem, ActivityKind, ActivityState};

use super::theme::ThemeColors;

// Layout constants
pub const BORDER_PADDING: u16 = 4; // Total horizontal padding from borders (2 per side)

/// Format timestamp for display
pub fn format_timestamp(timestamp: &chrono::DateTime<chrono::Utc>) -> String {
    timestamp.format("%Y-%m-%d %H:%M").to_string()
}

/// Format post content with hashtag highlighting and text wrapping
#[allow(dead_code)]
pub fn format_post_content(
    content: &str,
    is_selected: bool,
    theme: &ThemeColors,
) -> Vec<Line<'static>> {
    format_post_content_with_width(content, is_selected, theme, 80)
}

/// Format post content with hashtag highlighting and text wrapping with specified width
pub fn format_post_content_with_width(
    content: &str,
    is_selected: bool,
    theme: &ThemeColors,
    max_width: usize,
) -> Vec<Line<'static>> {
    let mut lines = vec![];
    let wrap_width = max_width.saturating_sub(4);

    for line in content.lines() {
        let wrapped = textwrap::wrap(line, wrap_width);

        for wrapped_line in wrapped {
            let mut spans = vec![Span::raw("  ")]; // Indent

            let line_str = wrapped_line.to_string();
            let mut current_word = String::new();
            let mut whitespace_buffer = String::new();

            for ch in line_str.chars() {
                if ch.is_whitespace() {
                    if !current_word.is_empty() {
                        push_styled_word(&mut spans, &current_word, is_selected, theme);
                        current_word.clear();
                    }
                    whitespace_buffer.push(ch);
                } else {
                    if !whitespace_buffer.is_empty() {
                        spans.push(Span::raw(std::mem::take(&mut whitespace_buffer)));
                    }
                    current_word.push(ch);
                }
            }

            if !current_word.is_empty() {
                push_styled_word(&mut spans, &current_word, is_selected, theme);
            }
            if !whitespace_buffer.is_empty() {
                spans.push(Span::raw(whitespace_buffer));
            }

            lines.push(Line::from(spans));
        }
    }

    lines
}

/// Push a styled word to spans with appropriate formatting
fn push_styled_word(
    spans: &mut Vec<Span<'static>>,
    word: &str,
    is_selected: bool,
    theme: &ThemeColors,
) {
    let (color, should_bold) = if word.starts_with('#') {
        (
            if is_selected {
                theme.accent
            } else {
                theme.secondary
            },
            true,
        )
    } else if word.starts_with('@') {
        (theme.primary, true)
    } else {
        (theme.text, is_selected)
    };

    let mut style = Style::default().fg(color);
    if should_bold {
        style = style.add_modifier(Modifier::BOLD);
    }

    spans.push(Span::styled(word.to_string(), style));
}

/// Format post content for input box (no indent, simpler formatting)
#[allow(dead_code)]
pub fn format_post_content_for_input(content: &str) -> Vec<Line<'static>> {
    content
        .lines()
        .map(|line| Line::from(line.to_string()))
        .collect()
}

/// Text for one row of the repo-activity feed, e.g.
/// `⊙ #7 Fix login · issue opened by alice` or
/// `⇄ #9 Dark mode · merged · bob`.
pub fn activity_line_text(item: &ActivityItem) -> String {
    match item.kind {
        ActivityKind::Issue => {
            let mut line = format!(
                "⊙ #{} {} · issue opened by {}",
                item.number, item.title, item.author_login
            );
            if item.state == ActivityState::Closed {
                line.push_str(" · closed");
            }
            line
        }
        ActivityKind::PullRequest => {
            let status = match item.state {
                ActivityState::Merged => "merged",
                ActivityState::Open => "open",
                ActivityState::Closed => "closed",
            };
            format!(
                "⇄ #{} {} · {} · {}",
                item.number, item.title, status, item.author_login
            )
        }
    }
}

/// Color for the activity row's leading glyph, based on its state.
pub fn activity_glyph_color(item: &ActivityItem, theme: &ThemeColors) -> Color {
    match item.state {
        ActivityState::Open => theme.success,
        ActivityState::Closed => theme.error,
        ActivityState::Merged => Color::Magenta,
    }
}

/// Format bio content with wrapping
#[allow(dead_code)]
pub fn format_bio_content_with_width(
    content: &str,
    max_width: usize,
    theme: &ThemeColors,
) -> Vec<Line<'static>> {
    let mut lines = vec![];

    for line in content.lines() {
        let wrapped = textwrap::wrap(line, max_width);
        for wrapped_line in wrapped {
            lines.push(Line::from(Span::styled(
                wrapped_line.to_string(),
                Style::default().fg(theme.text),
            )));
        }
    }

    if lines.is_empty() {
        lines.push(Line::from(""));
    }

    lines
}

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

    fn activity_item(
        kind: ActivityKind,
        state: ActivityState,
        number: i64,
        title: &str,
        author_login: &str,
    ) -> ActivityItem {
        ActivityItem {
            github_id: 1,
            kind,
            number,
            title: title.to_string(),
            author_login: author_login.to_string(),
            state,
            created_at: chrono::Utc::now(),
            html_url: "https://github.com/owner/repo/issues/1".to_string(),
        }
    }

    #[test]
    fn activity_line_formats_issue_and_merged_pr() {
        let issue = activity_item(
            ActivityKind::Issue,
            ActivityState::Open,
            7,
            "Fix login",
            "alice",
        );
        let line = activity_line_text(&issue);
        assert_eq!(line, "⊙ #7 Fix login · issue opened by alice");

        let pr = activity_item(
            ActivityKind::PullRequest,
            ActivityState::Merged,
            9,
            "Dark mode",
            "bob",
        );
        assert_eq!(activity_line_text(&pr), "⇄ #9 Dark mode · merged · bob");
    }

    #[test]
    fn activity_line_appends_closed_for_issues() {
        let issue = activity_item(
            ActivityKind::Issue,
            ActivityState::Closed,
            3,
            "Old bug",
            "carol",
        );
        assert_eq!(
            activity_line_text(&issue),
            "⊙ #3 Old bug · issue opened by carol · closed"
        );
    }
}
