use color_eyre::Result;
use crossterm::event::{poll, read, Event, KeyCode, KeyEvent, KeyEventKind};
use ratatui::{
    layout::{Constraint, Direction, Layout, Rect},
    style::{Color, Modifier, Style},
    text::{Line, Span},
    widgets::{Block, Borders, List, ListItem, ListState, Paragraph, Wrap},
    Frame,
};
use std::time::Duration;

#[derive(Debug, Clone)]
pub enum ShellAction {
    ListAvailableShells,
    ChangeDefaultShell,
    Back,
}

impl ShellAction {
    pub fn all() -> Vec<Self> {
        vec![
            Self::ListAvailableShells,
            Self::ChangeDefaultShell,
            Self::Back,
        ]
    }

    pub fn title(&self) -> &str {
        match self {
            Self::ListAvailableShells => "List Available Shells",
            Self::ChangeDefaultShell => "Change Default Shell",
            Self::Back => "Back to Main Menu",
        }
    }

    pub fn description(&self) -> &str {
        match self {
            Self::ListAvailableShells => {
                "Display all shells available on the system from /etc/shells"
            }
            Self::ChangeDefaultShell => "Change the default shell for the current user",
            Self::Back => "Return to the main menu",
        }
    }

    pub fn icon(&self) -> &str {
        match self {
            Self::ListAvailableShells => "󰒋 ", // nf-md-format_list_checks
            Self::ChangeDefaultShell => "󰒓 ",  // nf-md-account_edit
            Self::Back => "󰌍 ",                // nf-md-arrow_left
        }
    }
}

pub struct ShellManagementView {
    pub menu_state: ListState,
    pub actions: Vec<ShellAction>,
    pub terminal_command: Option<(String, Vec<String>)>, // Command to run in terminal
}

impl ShellManagementView {
    pub fn new() -> Self {
        let mut menu_state = ListState::default();
        menu_state.select(Some(0));

        Self {
            menu_state,
            actions: ShellAction::all(),
            terminal_command: None,
        }
    }

    /// Take the terminal command if one is pending
    pub fn take_terminal_command(&mut self) -> Option<(String, Vec<String>)> {
        self.terminal_command.take()
    }

    pub fn render(&mut self, frame: &mut Frame, area: Rect) {
        let chunks = Layout::default()
            .direction(Direction::Vertical)
            .constraints([
                Constraint::Length(3), // Title
                Constraint::Min(0),    // Content
                Constraint::Length(3), // Footer
            ])
            .split(area);

        // Render title
        self.render_title(frame, chunks[0]);

        // Render main content
        let direction = if area.width < 85 {
            Direction::Vertical
        } else {
            Direction::Horizontal
        };
        let content_constraints = if direction == Direction::Horizontal {
            [Constraint::Percentage(40), Constraint::Percentage(60)]
        } else {
            [Constraint::Length(14), Constraint::Min(0)]
        };
        let content_chunks = Layout::default()
            .direction(direction)
            .constraints(content_constraints)
            .split(chunks[1]);

        self.render_actions_menu(frame, content_chunks[0]);
        self.render_output(frame, content_chunks[1]);

        // Render footer
        self.render_footer(frame, chunks[2]);
    }

    fn render_title(&self, frame: &mut Frame, area: Rect) {
        let title = Paragraph::new(vec![Line::from(vec![
            Span::styled(" ", Style::default().fg(Color::Cyan)),
            Span::styled(
                "Shell Management",
                Style::default()
                    .fg(Color::Cyan)
                    .add_modifier(Modifier::BOLD),
            ),
        ])])
        .block(
            Block::default()
                .borders(Borders::ALL)
                .border_style(Style::default().fg(Color::Cyan)),
        )
        .centered();

        frame.render_widget(title, area);
    }

    fn render_actions_menu(&mut self, frame: &mut Frame, area: Rect) {
        let items: Vec<ListItem> = self
            .actions
            .iter()
            .enumerate()
            .map(|(i, action)| {
                let is_selected = self.menu_state.selected() == Some(i);
                let style = if is_selected {
                    Style::default()
                        .fg(Color::Black)
                        .bg(Color::Cyan)
                        .add_modifier(Modifier::BOLD)
                } else {
                    Style::default().fg(Color::White)
                };

                let content = format!("{} {}", action.icon(), action.title());
                ListItem::new(content).style(style)
            })
            .collect();

        let list = List::new(items)
            .block(
                Block::default()
                    .title(" Shell Actions ")
                    .borders(Borders::ALL)
                    .border_style(Style::default().fg(Color::White)),
            )
            .highlight_style(
                Style::default()
                    .fg(Color::Black)
                    .bg(Color::Cyan)
                    .add_modifier(Modifier::BOLD),
            );

        frame.render_stateful_widget(list, area, &mut self.menu_state);
    }

    fn render_output(&self, frame: &mut Frame, area: Rect) {
        let selected_action = self.menu_state.selected().and_then(|i| self.actions.get(i));

        let mut lines = Vec::new();

        if let Some(action) = selected_action {
            lines.push(Line::from(vec![
                Span::styled(action.icon(), Style::default().fg(Color::Cyan)),
                Span::raw(" "),
                Span::styled(
                    action.title(),
                    Style::default()
                        .fg(Color::Cyan)
                        .add_modifier(Modifier::BOLD),
                ),
            ]));
            lines.push(Line::from(""));
            lines.push(Line::from(Span::styled(
                "Description:",
                Style::default()
                    .fg(Color::Yellow)
                    .add_modifier(Modifier::BOLD),
            )));
            lines.push(Line::from(action.description()));
            lines.push(Line::from(""));
            lines.push(Line::from(Span::styled(
                "Press Enter to execute this action",
                Style::default().fg(Color::Green),
            )));
        } else {
            lines.push(Line::from("No action selected"));
        }

        let output = Paragraph::new(lines)
            .block(
                Block::default()
                    .title(" Details ")
                    .borders(Borders::ALL)
                    .border_style(Style::default().fg(Color::White)),
            )
            .wrap(Wrap { trim: true })
            .scroll((0, 0));

        frame.render_widget(output, area);
    }

    fn render_footer(&self, frame: &mut Frame, area: Rect) {
        let help_text = vec![Line::from(vec![
            Span::styled(
                " ↑/k ",
                Style::default()
                    .fg(Color::Cyan)
                    .add_modifier(Modifier::BOLD),
            ),
            Span::raw("Up  "),
            Span::styled(
                " ↓/j ",
                Style::default()
                    .fg(Color::Cyan)
                    .add_modifier(Modifier::BOLD),
            ),
            Span::raw("Down  "),
            Span::styled(
                " Enter ",
                Style::default()
                    .fg(Color::Green)
                    .add_modifier(Modifier::BOLD),
            ),
            Span::raw("Execute  "),
            Span::styled(
                " Esc/h ",
                Style::default().fg(Color::Red).add_modifier(Modifier::BOLD),
            ),
            Span::raw("Back"),
        ])];

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

        frame.render_widget(footer, area);
    }

    pub fn handle_events(&mut self, event: Option<Event>) -> Result<bool> {
        let key_event = if let Some(Event::Key(key)) = event {
            if key.kind == KeyEventKind::Press {
                Some(key)
            } else {
                None
            }
        } else {
            // Use non-blocking poll with a short timeout
            if !poll(Duration::from_millis(100))? {
                // No event available, return and let the render loop continue
                return Ok(false);
            }

            if let Event::Key(key) = read()? {
                if key.kind == KeyEventKind::Press {
                    Some(key)
                } else {
                    None
                }
            } else {
                None
            }
        };

        if let Some(key) = key_event {
            return Ok(self.handle_key_event(key));
        }
        Ok(false)
    }

    fn handle_key_event(&mut self, key: KeyEvent) -> bool {
        match key.code {
            KeyCode::Esc | KeyCode::Char('h') => {
                return true; // Signal to go back
            }
            KeyCode::Down | KeyCode::Char('j') => {
                self.next_item();
            }
            KeyCode::Up | KeyCode::Char('k') => {
                self.previous_item();
            }
            KeyCode::Enter => {
                if let Some(i) = self.menu_state.selected() {
                    if let Some(action) = self.actions.get(i).cloned() {
                        match action {
                            ShellAction::Back => return true,
                            _ => {
                                self.execute_action(&action);
                            }
                        }
                    }
                }
            }
            _ => {}
        }
        false
    }

    fn execute_action(&mut self, action: &ShellAction) {
        match action {
            ShellAction::ListAvailableShells => {
                self.list_available_shells();
            }
            ShellAction::ChangeDefaultShell => {
                self.change_default_shell();
            }
            ShellAction::Back => {}
        }
    }

    fn list_available_shells(&mut self) {
        // Filter shells to only those in /usr/bin/, format nicely, and capitalize names
        let command = r#"echo "🔍 Detected Shells:" && grep '^/usr/bin/' /etc/shells | sed 's|.*/||' | sed 's/.*/\L&/; s/^./\u&/' | sort | sed 's/^/  ⭐ /'"#;
        self.terminal_command = Some((
            "sh".to_string(),
            vec!["-c".to_string(), command.to_string()],
        ));
    }

    fn change_default_shell(&mut self) {
        // Custom script to interactively change default shell with nice UI
        let script = r#"#!/bin/bash
echo "🔄 Change Default Shell"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Available shells:"
echo "  1. 🐚 Bash  (/usr/bin/bash)"
echo "  2. 🐠 Fish  (/usr/bin/fish)"
echo ""
echo -n "Enter your choice (1-2) or 'q' to quit: "
read -r choice
echo ""

case $choice in
    1)
        echo "🐚 Switching to Bash..."
        if chsh -s /usr/bin/bash; then
            echo "✅ Default shell changed to Bash!"
            echo ""
            echo "Please reboot or logout and log back in! (Recommended)"
            exit 0
        else
            echo "❌ Failed to change shell. Please check your password and permissions."
            exit 1
        fi
        ;;
    2)
        echo "🐠 Switching to Fish..."
        if chsh -s /usr/bin/fish; then
            echo "✅ Default shell changed to Fish!"
            echo ""
            echo "Please reboot or logout and log back in! (Recommended)"
            exit 0
        else
            echo "❌ Failed to change shell. Please check your password and permissions."
            exit 1
        fi
        ;;
    q|Q)
        echo "👋 Operation cancelled successfully."
        exit 0
        ;;
    *)
        echo "❌ Invalid choice. Please run again and select 1 or 2."
        ;;
esac
read -r"#;
        self.terminal_command = Some((
            "bash".to_string(),
            vec!["-c".to_string(), script.to_string()],
        ));
    }

    fn next_item(&mut self) {
        let i = match self.menu_state.selected() {
            Some(i) => {
                if i >= self.actions.len() - 1 {
                    0
                } else {
                    i + 1
                }
            }
            None => 0,
        };
        self.menu_state.select(Some(i));
    }

    fn previous_item(&mut self) {
        let i = match self.menu_state.selected() {
            Some(i) => {
                if i == 0 {
                    self.actions.len() - 1
                } else {
                    i - 1
                }
            }
            None => 0,
        };
        self.menu_state.select(Some(i));
    }
}

impl Default for ShellManagementView {
    fn default() -> Self {
        Self::new()
    }
}
