use super::{PtySession, TerminalWidget};
use color_eyre::Result;
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use ratatui::{
    layout::{Constraint, Direction, Layout, Rect},
    style::{Color, Style},
    text::{Line, Span},
    widgets::{Block, Borders, Paragraph},
    Frame,
};

/// State of the terminal popup
pub enum TerminalPopupState {
    Running,
    Finished(Option<i32>), // Exit code
    Cancelled,             // User cancelled with Ctrl+C
}

/// A terminal popup that displays a PTY session
pub struct TerminalPopup {
    pty: Option<PtySession>,
    state: TerminalPopupState,
    scroll_offset: u16,
    title: String,
    user_cancelled: bool, // Track if user sent Ctrl+C
}

impl TerminalPopup {
    /// Create a new terminal popup (not yet started)
    pub fn new(title: String) -> Self {
        Self {
            pty: None,
            state: TerminalPopupState::Running,
            scroll_offset: 0,
            title,
            user_cancelled: false,
        }
    }

    /// Start the PTY session with the given command
    pub fn start(&mut self, command: &str, args: &[&str]) -> Result<()> {
        // Use current terminal size for PTY
        let pty = PtySession::spawn(command, args, 0, 0)?;
        self.pty = Some(pty);
        self.state = TerminalPopupState::Running;
        self.user_cancelled = false; // Reset cancellation flag
        Ok(())
    }

    /// Check and update the process status if it has finished
    pub fn update_process_status(&mut self) {
        if let Some(pty) = &self.pty {
            if pty.is_finished() {
                if self.user_cancelled {
                    self.state = TerminalPopupState::Cancelled;
                } else if let Some(code) = pty.get_exit_code() {
                    self.state = TerminalPopupState::Finished(Some(code));
                } else {
                    self.state = TerminalPopupState::Finished(None);
                }
            }
        }
    }

    /// Handle keyboard input
    pub fn handle_key(&mut self, key: KeyEvent) -> Result<bool> {
        // Check if process has finished
        self.update_process_status();

        match self.state {
            TerminalPopupState::Running => {
                // Forward input to PTY
                if let Some(pty) = &mut self.pty {
                    match key.code {
                        KeyCode::Char(c) => {
                            if key.modifiers.contains(KeyModifiers::CONTROL) {
                                // Handle Ctrl+C and other control characters
                                match c {
                                    'c' => {
                                        self.user_cancelled = true; // Mark as user cancelled
                                        pty.send_input(&[3])?; // Ctrl+C
                                    }
                                    'd' => {
                                        pty.send_input(&[4])?; // Ctrl+D (EOF)
                                    }
                                    'z' => {
                                        pty.send_input(&[26])?; // Ctrl+Z
                                    }
                                    _ => {
                                        // Other Ctrl combinations
                                        let ctrl_char = (c as u8) & 0x1f;
                                        pty.send_input(&[ctrl_char])?;
                                    }
                                }
                            } else {
                                // Regular character
                                let mut buf = [0u8; 4];
                                let s = c.encode_utf8(&mut buf);
                                pty.send_input(s.as_bytes())?;
                            }
                        }
                        KeyCode::Enter => {
                            pty.send_input(b"\n")?;
                        }
                        KeyCode::Backspace => {
                            pty.send_input(&[127])?; // DEL character
                        }
                        KeyCode::Tab => {
                            pty.send_input(b"\t")?;
                        }
                        KeyCode::Esc => {
                            pty.send_input(&[27])?; // ESC character
                        }
                        KeyCode::Up => {
                            pty.send_input(b"\x1b[A")?;
                        }
                        KeyCode::Down => {
                            pty.send_input(b"\x1b[B")?;
                        }
                        KeyCode::Right => {
                            pty.send_input(b"\x1b[C")?;
                        }
                        KeyCode::Left => {
                            pty.send_input(b"\x1b[D")?;
                        }
                        KeyCode::Home => {
                            pty.send_input(b"\x1b[H")?;
                        }
                        KeyCode::End => {
                            pty.send_input(b"\x1b[F")?;
                        }
                        KeyCode::PageUp => {
                            // Scroll up
                            if self.scroll_offset > 0 {
                                self.scroll_offset = self.scroll_offset.saturating_sub(5);
                            }
                        }
                        KeyCode::PageDown => {
                            // Scroll down
                            self.scroll_offset = self.scroll_offset.saturating_add(5);
                        }
                        _ => {}
                    }
                }
                Ok(false) // Don't close
            }
            TerminalPopupState::Finished(_) | TerminalPopupState::Cancelled => {
                // Process finished or cancelled - any key closes the popup
                match key.code {
                    KeyCode::Enter | KeyCode::Esc | KeyCode::Char('q') => Ok(true),
                    _ => Ok(false),
                }
            }
        }
    }

    /// Render the terminal popup
    pub fn render(&mut self, frame: &mut Frame, area: Rect) {
        // Update process status before rendering to ensure UI reflects current state
        self.update_process_status();

        // Adjust popup size based on screen width: wider on smaller screens
        let (width_percent, height_percent) = if area.width < 100 {
            (100, 82) // Wider and taller on small screens
        } else {
            (75, 65) // Default sizes
        };

        // Create a centered popup (% width, % height)
        let popup_area = centered_rect(width_percent, height_percent, area);

        // Clear the entire popup area with a solid background to prevent underlying UI colors from showing through
        let background_block = Block::default().style(Style::default().bg(Color::Black));
        frame.render_widget(background_block, popup_area);

        // Get terminal content
        let lines = if let Some(pty) = &self.pty {
            pty.get_screen()
        } else {
            vec!["Starting terminal...".to_string()]
        };

        // Determine border color and status text based on state
        let (border_color, status_text): (Color, String) = match &self.state {
            TerminalPopupState::Running => (Color::Cyan, "Running".to_string()),
            TerminalPopupState::Finished(Some(0)) => {
                (Color::Green, "Finished (Success)".to_string())
            }
            TerminalPopupState::Finished(Some(code)) => {
                (Color::Red, format!("Finished (Exit code: {})", code))
            }
            TerminalPopupState::Finished(None) => (Color::Yellow, "Finished".to_string()),
            TerminalPopupState::Cancelled => (Color::Yellow, "Cancelled".to_string()),
        };

        // Create the terminal widget
        let terminal_widget = TerminalWidget::new(lines)
            .block(
                Block::default()
                    .title(format!(" {} ", self.title))
                    .borders(Borders::ALL),
            )
            .scroll_offset(self.scroll_offset);

        // Render the terminal
        frame.render_widget(terminal_widget, popup_area);

        // Render status bar at the bottom
        let status_area = Rect {
            x: popup_area.x,
            y: popup_area.y + popup_area.height.saturating_sub(1),
            width: popup_area.width,
            height: 1,
        };

        let status_line = match &self.state {
            TerminalPopupState::Running => Line::from(vec![
                Span::styled(
                    " Status: ",
                    Style::default().fg(Color::DarkGray).bg(Color::Black),
                ),
                Span::styled(
                    status_text.clone(),
                    Style::default().fg(border_color).bg(Color::Black),
                ),
                Span::styled(" | ", Style::default().fg(Color::DarkGray).bg(Color::Black)),
                Span::styled(
                    "Ctrl+C",
                    Style::default().fg(Color::Yellow).bg(Color::Black),
                ),
                Span::styled(
                    " to interrupt ",
                    Style::default().fg(Color::DarkGray).bg(Color::Black),
                ),
            ]),
            TerminalPopupState::Finished(_) | TerminalPopupState::Cancelled => Line::from(vec![
                Span::styled(
                    " Status: ",
                    Style::default().fg(Color::DarkGray).bg(Color::Black),
                ),
                Span::styled(
                    status_text.clone(),
                    Style::default().fg(border_color).bg(Color::Black),
                ),
                Span::styled(
                    " | Press ",
                    Style::default().fg(Color::DarkGray).bg(Color::Black),
                ),
                Span::styled("Enter", Style::default().fg(Color::Green).bg(Color::Black)),
                Span::styled(
                    " or ",
                    Style::default().fg(Color::DarkGray).bg(Color::Black),
                ),
                Span::styled("Esc", Style::default().fg(Color::Green).bg(Color::Black)),
                Span::styled(
                    " to close ",
                    Style::default().fg(Color::DarkGray).bg(Color::Black),
                ),
            ]),
        };

        let status_widget = Paragraph::new(status_line).style(Style::default().bg(Color::Black));
        frame.render_widget(status_widget, status_area);

        // PTY size is fixed to avoid content offset issues when resizing
    }
}

/// 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]
}
