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, Clear, List, ListItem, ListState, Paragraph, Wrap},
    Frame,
};
use std::time::Duration;

#[derive(Debug, Clone)]
pub enum UpdateAction {
    UpdateSystem,
    Rollback,
    ViewDeployments,
    PinDeployment,
    UnpinDeployment,
    CleanupDeployments,
    Back,
}

impl UpdateAction {
    pub fn all() -> Vec<Self> {
        vec![
            Self::UpdateSystem,
            Self::Rollback,
            Self::ViewDeployments,
            Self::PinDeployment,
            Self::UnpinDeployment,
            Self::CleanupDeployments,
            Self::Back,
        ]
    }

    pub fn title(&self) -> &str {
        match self {
            Self::UpdateSystem => "Update System",
            Self::Rollback => "Rollback to Previous Deployment",
            Self::ViewDeployments => "View Deployment History",
            Self::PinDeployment => "Pin Current Deployment",
            Self::UnpinDeployment => "Unpin Deployment",
            Self::CleanupDeployments => "Cleanup Old Deployments",
            Self::Back => "Back to Main Menu",
        }
    }

    pub fn description(&self) -> &str {
        match self {
            Self::UpdateSystem => "Download and apply available system updates (requires reboot)",
            Self::Rollback => "Revert to the previous deployment (requires reboot)",
            Self::ViewDeployments => "Show deployment history and current status",
            Self::PinDeployment => "Pin the current deployment to prevent cleanup",
            Self::UnpinDeployment => "Unpin a deployment to allow cleanup",
            Self::CleanupDeployments => "Remove old, unpinned deployments to free space",
            Self::Back => "Return to the main menu",
        }
    }

    pub fn icon(&self) -> &str {
        match self {
            Self::UpdateSystem => "󰇚 ",       // nf-md-download
            Self::Rollback => "󰕌 ",           // nf-md-backup_restore
            Self::ViewDeployments => "󰈙 ",    // nf-md-format_list_bulleted
            Self::PinDeployment => "󰐃 ",      // nf-md-pin
            Self::UnpinDeployment => "󰐄 ",    // nf-md-pin_off
            Self::CleanupDeployments => "󰃨 ", // nf-md-delete_sweep
            Self::Back => "󰌍 ",               // nf-md-arrow_left
        }
    }
}

#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct Deployment {
    pub index: usize,
    pub checksum: String,
    pub version: String,
    pub timestamp: String,
    pub is_booted: bool,
    pub is_pinned: bool,
}

pub struct SystemUpdatesView {
    pub menu_state: ListState,
    pub actions: Vec<UpdateAction>,
    #[allow(dead_code)]
    pub deployments: Vec<Deployment>,
    pub show_confirmation: bool,
    pub pending_action: Option<UpdateAction>,
    pub terminal_command: Option<(String, Vec<String>)>, // Command to run in terminal
}

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

        Self {
            menu_state,
            actions: UpdateAction::all(),
            deployments: Vec::new(),
            show_confirmation: false,
            pending_action: None,
            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]);

        // Render confirmation dialog if needed
        if self.show_confirmation {
            self.render_confirmation(frame, area);
        }
    }

    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(
                "System Updates & Maintenance",
                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(" 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);
    }

    fn render_confirmation(&self, frame: &mut Frame, area: Rect) {
        let action = self.pending_action.as_ref().unwrap();

        // Create a centered popup
        let popup_area = centered_rect(60, 30, area);

        // Clear the background
        frame.render_widget(Clear, popup_area);
        frame.render_widget(
            Block::default()
                .borders(Borders::ALL)
                .border_style(Style::default().fg(Color::Yellow)),
            popup_area,
        );

        let chunks = Layout::default()
            .direction(Direction::Vertical)
            .margin(2)
            .constraints([
                Constraint::Length(3),
                Constraint::Min(0),
                Constraint::Length(3),
            ])
            .split(popup_area);

        // Title
        let title = Paragraph::new(Line::from(vec![
            Span::styled(" ", Style::default().fg(Color::Yellow)),
            Span::styled(
                "Confirmation Required",
                Style::default()
                    .fg(Color::Yellow)
                    .add_modifier(Modifier::BOLD),
            ),
        ]))
        .centered();
        frame.render_widget(title, chunks[0]);

        // Message
        let message = match action {
            UpdateAction::UpdateSystem => {
                "This will download and apply system updates.\nA reboot will be required.\n\nContinue?"
            }
            UpdateAction::Rollback => {
                "This will rollback to the previous deployment.\nA reboot will be required.\n\nContinue?"
            }
            UpdateAction::CleanupDeployments => {
                "This will remove old, unpinned deployments.\nThis action cannot be undone.\n\nContinue?"
            }
            _ => "Are you sure you want to proceed?",
        };

        let msg = Paragraph::new(message).centered().wrap(Wrap { trim: true });
        frame.render_widget(msg, chunks[1]);

        // Options
        let options = Paragraph::new(Line::from(vec![
            Span::styled(
                " y ",
                Style::default()
                    .fg(Color::Green)
                    .add_modifier(Modifier::BOLD),
            ),
            Span::raw("Yes  "),
            Span::styled(
                " n ",
                Style::default().fg(Color::Red).add_modifier(Modifier::BOLD),
            ),
            Span::raw("No"),
        ]))
        .centered();
        frame.render_widget(options, chunks[2]);
    }

    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 {
        if self.show_confirmation {
            match key.code {
                KeyCode::Char('y') | KeyCode::Char('Y') => {
                    self.show_confirmation = false;
                    if let Some(action) = self.pending_action.take() {
                        self.execute_action(&action);
                    }
                }
                KeyCode::Char('n') | KeyCode::Char('N') | KeyCode::Esc => {
                    self.show_confirmation = false;
                    self.pending_action = None;
                }
                _ => {}
            }
            return false;
        }

        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 {
                            UpdateAction::Back => return true,
                            UpdateAction::UpdateSystem
                            | UpdateAction::Rollback
                            | UpdateAction::CleanupDeployments => {
                                self.pending_action = Some(action);
                                self.show_confirmation = true;
                            }
                            _ => {
                                self.execute_action(&action);
                            }
                        }
                    }
                }
            }
            _ => {}
        }
        false
    }

    fn execute_action(&mut self, action: &UpdateAction) {
        match action {
            UpdateAction::UpdateSystem => {
                self.apply_updates();
            }
            UpdateAction::Rollback => {
                self.rollback();
            }
            UpdateAction::ViewDeployments => {
                self.view_deployments();
            }
            UpdateAction::PinDeployment => {
                self.pin_deployment();
            }
            UpdateAction::UnpinDeployment => {
                self.unpin_deployment();
            }
            UpdateAction::CleanupDeployments => {
                self.cleanup_deployments();
            }
            UpdateAction::Back => {}
        }
    }

    fn apply_updates(&mut self) {
        self.terminal_command = Some(("topgrade".to_string(), vec!["-y".to_string()]));
    }

    fn rollback(&mut self) {
        self.terminal_command = Some((
            "sudo".to_string(),
            vec!["rpm-ostree".to_string(), "rollback".to_string()],
        ));
    }

    fn view_deployments(&mut self) {
        self.terminal_command = Some(("rpm-ostree".to_string(), vec!["status".to_string()]));
    }

    fn pin_deployment(&mut self) {
        // Use terminal popup for interactive command execution
        self.terminal_command = Some((
            "sudo".to_string(),
            vec![
                "ostree".to_string(),
                "admin".to_string(),
                "pin".to_string(),
                "0".to_string(),
            ],
        ));
    }

    fn unpin_deployment(&mut self) {
        // Use terminal popup for interactive command execution
        self.terminal_command = Some((
            "sudo".to_string(),
            vec![
                "ostree".to_string(),
                "admin".to_string(),
                "pin".to_string(),
                "--unpin".to_string(),
                "0".to_string(),
            ],
        ));
    }

    fn cleanup_deployments(&mut self) {
        // Use terminal popup for interactive command execution
        self.terminal_command = Some((
            "sudo".to_string(),
            vec![
                "rpm-ostree".to_string(),
                "cleanup".to_string(),
                "-b".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 SystemUpdatesView {
    fn default() -> Self {
        Self::new()
    }
}

// Helper function to create a centered rectangle
fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
    let popup_layout = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Percentage((100 - percent_y) / 2),
            Constraint::Percentage(percent_y),
            Constraint::Percentage((100 - percent_y) / 2),
        ])
        .split(r);

    Layout::default()
        .direction(Direction::Horizontal)
        .constraints([
            Constraint::Percentage((100 - percent_x) / 2),
            Constraint::Percentage(percent_x),
            Constraint::Percentage((100 - percent_x) / 2),
        ])
        .split(popup_layout[1])[1]
}
