//! Topics List TUI with ratatui
//!
//! Provides a 3-panel interface for exploring Redis topics:
//! - Left: Topics list (selectable, scrollable)
//! - Right: Live messages from selected topic
//! - Footer: Instructions and links

use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use ratatui::{
    layout::{Constraint, Direction, Layout},
    style::{Color, Modifier, Style},
    text::{Line, Span},
    widgets::{Block, Borders, List, ListItem, ListState, Paragraph, Wrap},
    Frame,
};
use serde_json::Value;
use std::sync::{Arc, Mutex};

/// Message from a topic
#[derive(Clone, Debug)]
pub struct TopicMessage {
    pub entry_id: String,  // Redis stream entry ID (e.g., "1234567890123-0")
    pub timestamp: String, // Formatted display time (e.g., "14:32:45")
    pub payload: Value,
}

/// Shared buffer for collecting messages from a topic
#[derive(Clone)]
pub struct MessageBuffer {
    messages: Arc<Mutex<Vec<TopicMessage>>>,
    max_size: usize,
}

impl MessageBuffer {
    /// Create a new message buffer
    pub fn new(max_size: usize) -> Self {
        Self {
            messages: Arc::new(Mutex::new(Vec::new())),
            max_size,
        }
    }

    /// Add a message
    pub fn push(&self, message: TopicMessage) {
        let mut messages = self.messages.lock().unwrap();
        messages.push(message);

        // Keep only last N messages
        if messages.len() > self.max_size {
            let excess = messages.len() - self.max_size;
            messages.drain(0..excess);
        }
    }

    /// Get all current messages
    pub fn get_messages(&self) -> Vec<TopicMessage> {
        self.messages.lock().unwrap().clone()
    }

    /// Clear all messages
    pub fn clear(&self) {
        self.messages.lock().unwrap().clear();
    }
}

/// TUI for topics list and monitoring
pub struct TopicsListTui {
    topics: Vec<String>,
    selected_index: usize,
    monitoring_topic: Option<String>,
    message_buffer: MessageBuffer,
    message_scroll_offset: usize,
    auto_scroll: bool, // True = show newest messages (scroll to bottom)
    should_quit: bool,
}

impl TopicsListTui {
    /// Create a new topics list TUI
    pub fn new(topics: Vec<String>) -> Self {
        Self {
            topics,
            selected_index: 0,
            monitoring_topic: None,
            message_buffer: MessageBuffer::new(1000),
            message_scroll_offset: 0,
            auto_scroll: true, // Start with auto-scroll enabled
            should_quit: false,
        }
    }

    /// Get the currently selected topic
    pub fn selected_topic(&self) -> Option<&str> {
        self.topics.get(self.selected_index).map(|s| s.as_str())
    }

    /// Get the currently monitored topic
    pub fn monitoring_topic(&self) -> Option<&str> {
        self.monitoring_topic.as_deref()
    }

    /// Start monitoring the selected topic
    pub fn start_monitoring(&mut self) {
        if let Some(topic) = self.selected_topic() {
            self.monitoring_topic = Some(topic.to_string());
            self.message_buffer.clear();
            self.message_scroll_offset = 0;
            self.auto_scroll = true; // Reset to auto-scroll for new topic
        }
    }

    /// Stop monitoring
    pub fn stop_monitoring(&mut self) {
        self.monitoring_topic = None;
    }

    /// Get message buffer for background monitoring
    pub fn message_buffer(&self) -> MessageBuffer {
        self.message_buffer.clone()
    }

    /// Check if should quit
    pub fn should_quit(&self) -> bool {
        self.should_quit
    }

    /// Update topics list with newly discovered topics
    pub fn update_topics(&mut self, new_topics: Vec<String>) {
        // Keep current selection if possible
        let currently_selected = self.selected_topic().map(|s| s.to_string());

        // Update topics list
        self.topics = new_topics;

        // Try to restore selection
        if let Some(selected) = currently_selected {
            if let Some(index) = self.topics.iter().position(|t| t == &selected) {
                self.selected_index = index;
            } else {
                // Selected topic no longer exists, reset to first
                self.selected_index = 0;
            }
        } else {
            // Ensure index is still valid
            if self.selected_index >= self.topics.len() {
                self.selected_index = self.topics.len().saturating_sub(1);
            }
        }
    }

    /// Draw the TUI (single frame)
    pub fn draw(&mut self, f: &mut Frame) {
        // Split terminal vertically: content area + footer
        let vertical_chunks = Layout::default()
            .direction(Direction::Vertical)
            .constraints([
                Constraint::Min(10),   // Main content area
                Constraint::Length(3), // Footer
            ])
            .split(f.area());

        // Split main content horizontally: topics list + messages
        let horizontal_chunks = Layout::default()
            .direction(Direction::Horizontal)
            .constraints([
                Constraint::Percentage(40), // Topics list
                Constraint::Percentage(60), // Messages
            ])
            .split(vertical_chunks[0]);

        // Draw panels
        self.draw_topics_panel(f, horizontal_chunks[0]);
        self.draw_messages_panel(f, horizontal_chunks[1]);
        self.draw_footer(f, vertical_chunks[1]);
    }

    /// Draw topics list panel
    fn draw_topics_panel(&mut self, f: &mut Frame, area: ratatui::layout::Rect) {
        let items: Vec<ListItem> = self
            .topics
            .iter()
            .enumerate()
            .map(|(i, topic)| {
                let is_selected = i == self.selected_index;
                let is_monitoring = self.monitoring_topic.as_ref().map(|t| t == topic).unwrap_or(false);

                let (icon, style) = if is_monitoring {
                    ("🔴", Style::default().fg(Color::Red).add_modifier(Modifier::BOLD))
                } else if is_selected {
                    ("▶ ", Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD))
                } else {
                    ("  ", Style::default().fg(Color::White))
                };

                let formatted = format!("{} {}", icon, topic);
                ListItem::new(formatted).style(style)
            })
            .collect();

        let title = format!(" Topics ({}) ", self.topics.len());
        let list = List::new(items).block(
            Block::default()
                .borders(Borders::ALL)
                .title(title)
                .border_style(Style::default().fg(Color::Cyan)),
        );

        // Create list state for highlighting
        let mut state = ListState::default();
        state.select(Some(self.selected_index));

        f.render_stateful_widget(list, area, &mut state);
    }

    /// Draw messages panel
    fn draw_messages_panel(&self, f: &mut Frame, area: ratatui::layout::Rect) {
        let messages = self.message_buffer.get_messages();

        if let Some(topic) = &self.monitoring_topic {
            // Calculate how many messages fit in the display area
            let available_height = area.height.saturating_sub(2) as usize; // Subtract borders

            // Determine which messages to show
            let messages_to_show: Vec<ListItem> = if self.auto_scroll {
                // Show the newest messages (from the end)
                messages
                    .iter()
                    .rev()
                    .take(available_height)
                    .rev()
                    .map(|msg| {
                        let payload_str =
                            serde_json::to_string_pretty(&msg.payload).unwrap_or_else(|_| msg.payload.to_string());

                        let formatted = format!("[{}] {}", msg.timestamp, payload_str);
                        ListItem::new(formatted).style(Style::default().fg(Color::White))
                    })
                    .collect()
            } else {
                // Manual scroll mode - show from offset
                messages
                    .iter()
                    .skip(self.message_scroll_offset)
                    .take(available_height)
                    .map(|msg| {
                        let payload_str =
                            serde_json::to_string_pretty(&msg.payload).unwrap_or_else(|_| msg.payload.to_string());

                        let formatted = format!("[{}] {}", msg.timestamp, payload_str);
                        ListItem::new(formatted).style(Style::default().fg(Color::White))
                    })
                    .collect()
            };

            let scroll_indicator = if self.auto_scroll {
                " [Auto-scroll] "
            } else {
                " [Manual] "
            };
            let title = format!(" Messages from {} ({}) {} ", topic, messages.len(), scroll_indicator);
            let list = List::new(messages_to_show).block(
                Block::default()
                    .borders(Borders::ALL)
                    .title(title)
                    .border_style(Style::default().fg(Color::Yellow)),
            );

            f.render_widget(list, area);
        } else {
            // Show instructions
            let text = vec![
                Line::from(vec![Span::styled(
                    "📋 TOPICS MONITOR",
                    Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD),
                )]),
                Line::from(""),
                Line::from("Select a topic from the list and press"),
                Line::from("Enter to start monitoring."),
                Line::from(""),
                Line::from("Messages will appear here in real-time."),
                Line::from(""),
                Line::from(vec![Span::styled(
                    "Instructions:",
                    Style::default().add_modifier(Modifier::BOLD),
                )]),
                Line::from("  ↑/↓       Navigate topics"),
                Line::from("  Enter     Start/stop monitoring"),
                Line::from("  j/k       Scroll messages"),
                Line::from("  g/G       Jump to top/bottom"),
                Line::from("  Q/ESC     Exit"),
            ];

            let paragraph = Paragraph::new(text)
                .block(
                    Block::default()
                        .borders(Borders::ALL)
                        .title(" Messages ")
                        .border_style(Style::default().fg(Color::Yellow)),
                )
                .wrap(Wrap { trim: true });

            f.render_widget(paragraph, area);
        }
    }

    /// Draw footer with links
    fn draw_footer(&self, f: &mut Frame, area: ratatui::layout::Rect) {
        let footer_text = vec![Line::from(vec![
            Span::raw("  "),
            Span::styled("↑/↓:", Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD)),
            Span::raw(" Navigate  "),
            Span::styled("j/k:", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)),
            Span::raw(" Scroll  "),
            Span::styled("g/G:", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)),
            Span::raw(" Top/Bottom  "),
            Span::styled("Enter:", Style::default().fg(Color::Green).add_modifier(Modifier::BOLD)),
            Span::raw(" Monitor  "),
            Span::styled("Q/ESC:", Style::default().fg(Color::Red).add_modifier(Modifier::BOLD)),
            Span::raw(" Exit"),
        ])];

        let footer = Paragraph::new(footer_text).block(
            Block::default()
                .borders(Borders::ALL)
                .border_style(Style::default().fg(Color::DarkGray)),
        );

        f.render_widget(footer, area);
    }

    /// Handle keyboard input
    pub fn handle_key(&mut self, key: KeyEvent) {
        match key.code {
            // Exit
            KeyCode::Char('q') | KeyCode::Esc => {
                self.should_quit = true;
            }
            KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => {
                self.should_quit = true;
            }

            // Navigate topics
            KeyCode::Up => {
                if self.selected_index > 0 {
                    self.selected_index -= 1;
                }
            }
            KeyCode::Down => {
                if self.selected_index < self.topics.len().saturating_sub(1) {
                    self.selected_index += 1;
                }
            }

            // Start/stop monitoring
            KeyCode::Enter => {
                if self.monitoring_topic.is_some() {
                    self.stop_monitoring();
                } else {
                    self.start_monitoring();
                }
            }

            // Scroll messages (PgUp/PgDn, Ctrl+U/D, or j/k for laptops)
            KeyCode::PageUp | KeyCode::Char('u') if key.modifiers.contains(KeyModifiers::CONTROL) => {
                self.auto_scroll = false; // Disable auto-scroll
                self.message_scroll_offset = self.message_scroll_offset.saturating_sub(10);
            }
            KeyCode::PageDown | KeyCode::Char('d') if key.modifiers.contains(KeyModifiers::CONTROL) => {
                let messages = self.message_buffer.get_messages();
                let new_offset = (self.message_scroll_offset + 10).min(messages.len().saturating_sub(1));

                // If we're at the end, re-enable auto-scroll
                if new_offset >= messages.len().saturating_sub(1) {
                    self.auto_scroll = true;
                } else {
                    self.auto_scroll = false;
                    self.message_scroll_offset = new_offset;
                }
            }
            KeyCode::Char('k') => {
                self.auto_scroll = false; // Disable auto-scroll
                self.message_scroll_offset = self.message_scroll_offset.saturating_sub(1);
            }
            KeyCode::Char('j') => {
                let messages = self.message_buffer.get_messages();
                let new_offset = (self.message_scroll_offset + 1).min(messages.len().saturating_sub(1));

                // If we're at the end, re-enable auto-scroll
                if new_offset >= messages.len().saturating_sub(1) {
                    self.auto_scroll = true;
                } else {
                    self.auto_scroll = false;
                    self.message_scroll_offset = new_offset;
                }
            }
            // 'G' to jump to end (newest messages) and enable auto-scroll
            KeyCode::Char('G') => {
                self.auto_scroll = true;
                self.message_scroll_offset = 0;
            }
            // 'g' to jump to beginning (oldest messages)
            KeyCode::Char('g') => {
                self.auto_scroll = false;
                self.message_scroll_offset = 0;
            }

            _ => {}
        }
    }
}
