use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Clear, Paragraph, Widget};

use crate::lookup::ix::CacheStatus;
use crate::prefs::DisplayMode;
use crate::tui::theme::Theme;

/// Settings state for the modal
#[derive(Default, Clone)]
pub struct SettingsState {
    /// 0 = theme section, 1 = display mode section, 2 = PeeringDB section
    pub selected_section: usize,
    /// Scroll offset for theme list
    pub theme_scroll: usize,
    /// Selected theme index
    pub theme_index: usize,
    /// Display mode for column widths (auto/compact/wide)
    pub display_mode: DisplayMode,
    /// PeeringDB API key input value
    pub api_key: String,
    /// Cursor position in API key input
    pub api_key_cursor: usize,
}

impl SettingsState {
    pub fn new(theme_index: usize, display_mode: DisplayMode, api_key: Option<String>) -> Self {
        let api_key = api_key.unwrap_or_default();
        let cursor = api_key.len();
        Self {
            selected_section: 0,
            theme_scroll: 0,
            theme_index,
            display_mode,
            api_key,
            api_key_cursor: cursor,
        }
    }

    /// Insert a character at the cursor position
    pub fn handle_char(&mut self, c: char) {
        self.api_key.insert(self.api_key_cursor, c);
        self.api_key_cursor += 1;
    }

    /// Delete the character before the cursor (backspace)
    pub fn handle_backspace(&mut self) {
        if self.api_key_cursor > 0 {
            self.api_key_cursor -= 1;
            self.api_key.remove(self.api_key_cursor);
        }
    }

    /// Delete the character at the cursor position (delete key)
    pub fn handle_delete(&mut self) {
        if self.api_key_cursor < self.api_key.len() {
            self.api_key.remove(self.api_key_cursor);
        }
    }

    /// Move cursor left
    pub fn move_cursor_left(&mut self) {
        if self.api_key_cursor > 0 {
            self.api_key_cursor -= 1;
        }
    }

    /// Move cursor right
    pub fn move_cursor_right(&mut self) {
        if self.api_key_cursor < self.api_key.len() {
            self.api_key_cursor += 1;
        }
    }

    /// Move selection up within current section
    pub fn move_up(&mut self, _theme_count: usize) {
        if self.selected_section == 0 {
            // Theme section
            if self.theme_index > 0 {
                self.theme_index -= 1;
                // Adjust scroll if needed
                if self.theme_index < self.theme_scroll {
                    self.theme_scroll = self.theme_index;
                }
            }
        }
        // Display mode section has no up/down navigation
    }

    /// Move selection down within current section
    pub fn move_down(&mut self, theme_count: usize) {
        if self.selected_section == 0 {
            // Theme section
            if self.theme_index < theme_count - 1 {
                self.theme_index += 1;
                // Adjust scroll if needed (show 5 themes at once)
                let visible_themes = 5;
                if self.theme_index >= self.theme_scroll + visible_themes {
                    self.theme_scroll = self.theme_index - visible_themes + 1;
                }
            }
        }
        // Display mode section has no up/down navigation
    }

    /// Switch between sections (0=Theme, 1=Display Mode, 2=PeeringDB)
    pub fn next_section(&mut self, ix_enabled: bool) {
        let num_sections = if ix_enabled { 3 } else { 2 };
        self.selected_section = (self.selected_section + 1) % num_sections;
    }

    /// Select current theme (when in theme section) or cycle display mode
    pub fn select(&mut self) {
        if self.selected_section == 1 {
            self.display_mode = self.display_mode.next();
        }
        // Theme is already selected by navigation
    }
}

/// Settings modal view
pub struct SettingsView<'a> {
    theme: &'a Theme,
    state: &'a SettingsState,
    theme_names: &'a [&'static str],
    cache_status: Option<CacheStatus>,
    ix_enabled: bool,
}

impl<'a> SettingsView<'a> {
    pub fn new(
        theme: &'a Theme,
        state: &'a SettingsState,
        theme_names: &'a [&'static str],
        cache_status: Option<CacheStatus>,
        ix_enabled: bool,
    ) -> Self {
        Self {
            theme,
            state,
            theme_names,
            cache_status,
            ix_enabled,
        }
    }

    /// Format the cache age as a human-readable string
    fn format_cache_age(fetched_at: u64) -> String {
        use std::time::SystemTime;
        let now = SystemTime::now()
            .duration_since(SystemTime::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();
        let age_secs = now.saturating_sub(fetched_at);

        if age_secs < 60 {
            "just now".to_string()
        } else if age_secs < 3600 {
            format!("{}m ago", age_secs / 60)
        } else if age_secs < 86400 {
            format!("{}h ago", age_secs / 3600)
        } else {
            format!("{}d ago", age_secs / 86400)
        }
    }
}

impl Widget for SettingsView<'_> {
    fn render(self, area: Rect, buf: &mut Buffer) {
        // Calculate centered popup area (taller if IX is enabled)
        let popup_width = 44.min(area.width.saturating_sub(4));
        let base_height = if self.ix_enabled { 23 } else { 17 };
        let popup_height = base_height.min(area.height.saturating_sub(4));
        let popup_x = (area.width - popup_width) / 2 + area.x;
        let popup_y = (area.height - popup_height) / 2 + area.y;
        let popup_area = Rect::new(popup_x, popup_y, popup_width, popup_height);

        // Clear the popup area
        Clear.render(popup_area, buf);

        let block = Block::default()
            .title(" Settings ")
            .borders(Borders::ALL)
            .border_style(Style::default().fg(self.theme.border));

        let inner = block.inner(popup_area);
        block.render(popup_area, buf);

        let mut lines = Vec::new();

        // Theme section header
        let theme_header_style = if self.state.selected_section == 0 {
            Style::default()
                .fg(self.theme.header)
                .add_modifier(Modifier::BOLD)
        } else {
            Style::default().fg(self.theme.text_dim)
        };
        lines.push(Line::from(vec![Span::styled(
            "  Theme",
            theme_header_style,
        )]));

        // Show visible themes (5 at a time)
        let visible_themes = 5.min(self.theme_names.len());
        let start = self.state.theme_scroll;
        let end = (start + visible_themes).min(self.theme_names.len());

        // Scroll indicator (up)
        if start > 0 {
            lines.push(Line::from(vec![Span::styled(
                "    \u{25b2} more",
                Style::default().fg(self.theme.text_dim),
            )]));
        } else {
            lines.push(Line::from(""));
        }

        // Theme list
        for (i, name) in self.theme_names[start..end].iter().enumerate() {
            let idx = start + i;
            let is_selected = idx == self.state.theme_index;
            let bullet = if is_selected { "\u{25cf}" } else { "\u{25cb}" };
            let style = if is_selected && self.state.selected_section == 0 {
                Style::default()
                    .fg(self.theme.shortcut)
                    .add_modifier(Modifier::BOLD)
            } else if is_selected {
                Style::default().fg(self.theme.text)
            } else {
                Style::default().fg(self.theme.text_dim)
            };
            lines.push(Line::from(vec![Span::styled(
                format!("    {} {}", bullet, name),
                style,
            )]));
        }

        // Scroll indicator (down)
        if end < self.theme_names.len() {
            lines.push(Line::from(vec![Span::styled(
                "    \u{25bc} more",
                Style::default().fg(self.theme.text_dim),
            )]));
        } else {
            lines.push(Line::from(""));
        }

        lines.push(Line::from(""));

        // Display mode section header
        let display_header_style = if self.state.selected_section == 1 {
            Style::default()
                .fg(self.theme.header)
                .add_modifier(Modifier::BOLD)
        } else {
            Style::default().fg(self.theme.text_dim)
        };
        lines.push(Line::from(vec![Span::styled(
            "  Display Mode",
            display_header_style,
        )]));

        // Display mode selector
        let mode_text = format!(
            "    [{}]  (Enter to cycle)",
            self.state.display_mode.label()
        );
        let mode_style = if self.state.selected_section == 1 {
            Style::default()
                .fg(self.theme.shortcut)
                .add_modifier(Modifier::BOLD)
        } else {
            Style::default().fg(self.theme.text_dim)
        };
        lines.push(Line::from(vec![Span::styled(mode_text, mode_style)]));

        // Mode description
        let desc = match self.state.display_mode {
            DisplayMode::Auto => "fit columns to content",
            DisplayMode::Compact => "minimal column widths",
            DisplayMode::Wide => "generous column widths",
        };
        lines.push(Line::from(vec![Span::styled(
            format!("    {}", desc),
            Style::default().fg(self.theme.text_dim),
        )]));

        // PeeringDB section (only if IX detection is enabled)
        if self.ix_enabled {
            lines.push(Line::from(""));

            // PeeringDB section header
            let pdb_header_style = if self.state.selected_section == 2 {
                Style::default()
                    .fg(self.theme.header)
                    .add_modifier(Modifier::BOLD)
            } else {
                Style::default().fg(self.theme.text_dim)
            };
            lines.push(Line::from(vec![Span::styled(
                "  PeeringDB (IX Detection)",
                pdb_header_style,
            )]));

            // API key input
            let api_key_style = if self.state.selected_section == 2 {
                Style::default().fg(self.theme.text)
            } else {
                Style::default().fg(self.theme.text_dim)
            };

            // Build the API key display with cursor
            let label = "    API Key: ";
            let display_key = if self.state.api_key.is_empty() {
                "(not set)".to_string()
            } else {
                // Show the key with cursor indicator when section is selected
                if self.state.selected_section == 2 {
                    let (before, after) = self.state.api_key.split_at(self.state.api_key_cursor);
                    format!("{}\u{2502}{}", before, after)
                } else {
                    self.state.api_key.clone()
                }
            };
            lines.push(Line::from(vec![
                Span::styled(label, api_key_style),
                Span::styled(
                    display_key,
                    if self.state.selected_section == 2 {
                        Style::default()
                            .fg(self.theme.shortcut)
                            .add_modifier(Modifier::BOLD)
                    } else {
                        api_key_style
                    },
                ),
            ]));

            // Cache status
            if let Some(ref status) = self.cache_status {
                let status_text = if status.refreshing {
                    "    Cache: Refreshing...".to_string()
                } else if !status.loaded && status.prefix_count == 0 {
                    "    Cache: Not loaded".to_string()
                } else {
                    let age_str = status
                        .fetched_at
                        .map(Self::format_cache_age)
                        .unwrap_or_else(|| "unknown".to_string());
                    let status_indicator = if status.expired { " (expired)" } else { "" };
                    format!(
                        "    Cache: {} prefixes, {}{}",
                        status.prefix_count, age_str, status_indicator
                    )
                };
                lines.push(Line::from(vec![Span::styled(
                    status_text,
                    Style::default().fg(self.theme.text_dim),
                )]));

                // Refresh hint when in PeeringDB section
                if self.state.selected_section == 2 && !status.refreshing {
                    lines.push(Line::from(vec![Span::styled(
                        "    Press Ctrl+R to refresh cache",
                        Style::default().fg(self.theme.text_dim),
                    )]));
                } else {
                    lines.push(Line::from(""));
                }
            }
        }

        lines.push(Line::from(""));

        // Footer with keybindings
        lines.push(Line::from(vec![Span::styled(
            "  \u{2191}\u{2193} navigate  Tab section  Enter select",
            Style::default().fg(self.theme.text_dim),
        )]));
        lines.push(Line::from(vec![Span::styled(
            "  Esc close",
            Style::default().fg(self.theme.text_dim),
        )]));

        let paragraph = Paragraph::new(lines);
        paragraph.render(inner, buf);
    }
}

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

    #[test]
    fn test_settings_state_new() {
        let state = SettingsState::new(2, DisplayMode::Auto, Some("test_key".to_string()));
        assert_eq!(state.theme_index, 2);
        assert_eq!(state.display_mode, DisplayMode::Auto);
        assert_eq!(state.api_key, "test_key");
        assert_eq!(state.api_key_cursor, 8); // "test_key".len()
        assert_eq!(state.selected_section, 0);
        assert_eq!(state.theme_scroll, 0);
    }

    #[test]
    fn test_settings_state_new_no_api_key() {
        let state = SettingsState::new(0, DisplayMode::Wide, None);
        assert_eq!(state.theme_index, 0);
        assert_eq!(state.display_mode, DisplayMode::Wide);
        assert_eq!(state.api_key, "");
        assert_eq!(state.api_key_cursor, 0);
    }

    #[test]
    fn test_settings_state_select_cycles_display_mode() {
        let mut state = SettingsState::new(0, DisplayMode::Auto, None);

        // Section 0 (theme) - select does nothing to display_mode
        state.selected_section = 0;
        state.select();
        assert_eq!(state.display_mode, DisplayMode::Auto);

        // Section 1 (display mode) - select cycles
        state.selected_section = 1;
        state.select();
        assert_eq!(state.display_mode, DisplayMode::Compact);

        state.select();
        assert_eq!(state.display_mode, DisplayMode::Wide);

        state.select();
        assert_eq!(state.display_mode, DisplayMode::Auto);
    }

    #[test]
    fn test_settings_state_next_section() {
        let mut state = SettingsState::new(0, DisplayMode::Auto, None);

        // Without IX enabled (2 sections)
        assert_eq!(state.selected_section, 0);
        state.next_section(false);
        assert_eq!(state.selected_section, 1);
        state.next_section(false);
        assert_eq!(state.selected_section, 0); // Wraps

        // With IX enabled (3 sections)
        state.selected_section = 0;
        state.next_section(true);
        assert_eq!(state.selected_section, 1);
        state.next_section(true);
        assert_eq!(state.selected_section, 2);
        state.next_section(true);
        assert_eq!(state.selected_section, 0); // Wraps
    }

    #[test]
    fn test_settings_state_theme_navigation() {
        let mut state = SettingsState::new(5, DisplayMode::Auto, None);
        state.selected_section = 0;

        // Move up
        state.move_up(11);
        assert_eq!(state.theme_index, 4);

        // Move up at 0 stays at 0
        state.theme_index = 0;
        state.move_up(11);
        assert_eq!(state.theme_index, 0);

        // Move down
        state.theme_index = 5;
        state.move_down(11);
        assert_eq!(state.theme_index, 6);

        // Move down at max stays at max
        state.theme_index = 10;
        state.move_down(11);
        assert_eq!(state.theme_index, 10);
    }

    #[test]
    fn test_settings_state_api_key_input() {
        let mut state = SettingsState::new(0, DisplayMode::Auto, None);

        // Type characters
        state.handle_char('a');
        state.handle_char('b');
        state.handle_char('c');
        assert_eq!(state.api_key, "abc");
        assert_eq!(state.api_key_cursor, 3);

        // Backspace
        state.handle_backspace();
        assert_eq!(state.api_key, "ab");
        assert_eq!(state.api_key_cursor, 2);

        // Backspace at empty string
        state.api_key = String::new();
        state.api_key_cursor = 0;
        state.handle_backspace();
        assert_eq!(state.api_key, "");
        assert_eq!(state.api_key_cursor, 0);
    }

    #[test]
    fn test_settings_state_cursor_movement() {
        let mut state = SettingsState::new(0, DisplayMode::Auto, Some("hello".to_string()));
        assert_eq!(state.api_key_cursor, 5);

        // Move left
        state.move_cursor_left();
        assert_eq!(state.api_key_cursor, 4);

        // Move left to beginning
        state.api_key_cursor = 0;
        state.move_cursor_left();
        assert_eq!(state.api_key_cursor, 0); // Stays at 0

        // Move right
        state.api_key_cursor = 2;
        state.move_cursor_right();
        assert_eq!(state.api_key_cursor, 3);

        // Move right at end
        state.api_key_cursor = 5;
        state.move_cursor_right();
        assert_eq!(state.api_key_cursor, 5); // Stays at end
    }

    #[test]
    fn test_settings_state_handle_delete() {
        let mut state = SettingsState::new(0, DisplayMode::Auto, Some("hello".to_string()));
        state.api_key_cursor = 2; // Position at 'l'

        state.handle_delete();
        assert_eq!(state.api_key, "helo"); // Deleted 'l' at position 2
        assert_eq!(state.api_key_cursor, 2); // Cursor stays

        // Delete at end does nothing
        state.api_key_cursor = 4;
        state.handle_delete();
        assert_eq!(state.api_key, "helo");
    }

    #[test]
    fn test_settings_state_default() {
        let state = SettingsState::default();
        assert_eq!(state.theme_index, 0);
        assert_eq!(state.display_mode, DisplayMode::Auto);
        assert_eq!(state.api_key, "");
        assert_eq!(state.selected_section, 0);
    }
}
