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

const MIN_WIDTH: u16 = 80;
const MIN_HEIGHT: u16 = 30;

fn check_terminal_size() -> Result<bool> {
    let (width, height) = size()?;
    Ok(width >= MIN_WIDTH && height >= MIN_HEIGHT)
}

use crate::modules::shell_management::ShellManagementView;
use crate::modules::system_info::SystemInfoView;
use crate::modules::system_updates::SystemUpdatesView;
use crate::terminal::TerminalPopup;

#[derive(Debug, Clone)]
pub enum MenuItem {
    SystemUpdates,
    ShellManagement,
    PackageManagement,
    DesktopConfig,
    SystemServices,
    FlatpakManagement,
    ContainerManagement,
    UserManagement,
    NetworkConfig,
    BootKernelOptions,
    StorageFilesystem,
    SystemInfo,
}

impl MenuItem {
    pub fn all() -> Vec<Self> {
        vec![
            Self::SystemUpdates,
            Self::ShellManagement,
            Self::PackageManagement,
            Self::DesktopConfig,
            Self::SystemServices,
            Self::FlatpakManagement,
            Self::ContainerManagement,
            Self::UserManagement,
            Self::NetworkConfig,
            Self::BootKernelOptions,
            Self::StorageFilesystem,
            Self::SystemInfo,
        ]
    }

    pub fn title(&self) -> &str {
        match self {
            Self::SystemUpdates => "System Updates & Maintenance",
            Self::ShellManagement => "Shell Management",
            Self::PackageManagement => "Package Management (coming soon)",
            Self::DesktopConfig => "Desktop Environment Configuration (coming soon)",
            Self::SystemServices => "System Services (coming soon)",
            Self::FlatpakManagement => "Flatpak Management (coming soon)",
            Self::ContainerManagement => "Container & Toolbox Management (coming soon)",
            Self::UserManagement => "User & Group Management (coming soon)",
            Self::NetworkConfig => "Network Configuration (coming soon)",
            Self::BootKernelOptions => "Boot & Kernel Options (coming soon)",
            Self::StorageFilesystem => "Storage & Filesystem (coming soon)",
            Self::SystemInfo => "System Information",
        }
    }

    pub fn description(&self) -> &str {
        match self {
            Self::SystemUpdates => "Updates System and Security\nRollback to previous versions if issues arise after updates\nView detailed deployment history, logs, and update changelogs\nSchedule automatic updates or perform manual installations\nMonitor update progress and handle conflicts or dependencies",
            Self::ShellManagement => "List all available and installed shell environments (bash, zsh, fish, etc.)\nChange the default shell for existing user accounts",
            Self::PackageManagement => "Install packages in layered mode without affecting base system\nRemove unwanted packages and automatically clean up dependencies\nSearch packages across multiple repositories and overlays\nManage package overlays, remotes, and custom repositories\nView package information, dependencies, and reverse dependencies\nHandle package conflicts and perform system-wide package updates",
            Self::DesktopConfig => "Configure Cosmic desktop appearance, themes, and wallpapers\nManage display manager settings and login screen customization\nControl user session options and startup applications\nCustomize desktop environment preferences and keyboard shortcuts\nSet up multiple monitors and display configurations\nConfigure accessibility options and input device settings",
            Self::SystemServices => "Enable or disable system services at boot time\nView real-time service status and health monitoring\nManage systemd units, timers, and service configurations\nMonitor service logs, errors, and performance metrics\nStart, stop, restart, or reload individual services\nConfigure service dependencies and startup ordering",
            Self::FlatpakManagement => "Install Flatpak applications from Flathub and other remotes\nRemove unused Flatpak apps and clean up orphaned runtimes\nUpdate Flatpaks to latest versions with sandboxed updates\nAdd and manage Flatpak remotes for different app sources\nView installed Flatpaks, permissions, and sandbox details\nOverride app permissions and configure runtime environments",
            Self::ContainerManagement => "Create and manage Podman containers for development and deployment\nSet up development toolboxes with isolated environments\nConfigure Distrobox environments for different Linux distributions\nMonitor container resources, CPU, memory, and network usage\nManage container images, volumes, and networking\nSet up container orchestration and automated deployments",
            Self::UserManagement => "Add new user accounts with custom home directories and permissions\nRemove user accounts safely while preserving or deleting data\nModify user group memberships and sudo privileges\nManage passwords, authentication methods, and security policies\nConfigure user quotas, login restrictions, and session limits\nSet up SSH keys and multi-factor authentication for users",
            Self::NetworkConfig => "Configure WiFi connections with WPA2/3 encryption and profiles\nSet up VPN connections for secure remote access (OpenVPN, WireGuard)\nManage network interfaces, IP addresses, and routing tables\nChange system hostname and domain configuration\nConfigure firewall rules and network security policies\nMonitor network traffic, bandwidth usage, and connection quality",
            Self::BootKernelOptions => "Edit kernel command line parameters for boot customization\nConfigure GRUB bootloader options and menu entries\nManage multiple boot entries for different kernels or OS\nUpdate initramfs images and regenerate bootloader configs\nSet up kernel modules and device driver loading\nConfigure secure boot settings and EFI variables",
            Self::StorageFilesystem => "Monitor disk usage, space allocation, and file system health\nManage filesystem mount points and automatic mounting\nView partition tables, disk layouts, and storage devices\nResize partitions safely with data preservation\nConfigure RAID arrays and logical volume management\nSet up disk encryption and secure storage options",
            Self::SystemInfo => "View comprehensive system overview including OS version and architecture\nDisplay detailed hardware information (CPU, RAM, GPU, storage)\nMonitor real-time resource usage and system performance metrics\nRun system health checks and diagnostic tests\nView kernel version, loaded modules, and system logs\nGenerate system reports for troubleshooting and support",
        }
    }

    pub fn icon(&self) -> &str {
        match self {
            Self::SystemUpdates => "󰚰 ",       // nf-md-update
            Self::ShellManagement => " ",     // nf-dev-terminal
            Self::PackageManagement => "󰏖 ",   // nf-md-package_variant
            Self::DesktopConfig => "󰍹 ",       // nf-md-monitor
            Self::SystemServices => " ",      // nf-fa-cogs
            Self::FlatpakManagement => "󰏖 ",   // nf-md-package
            Self::ContainerManagement => "󰡨 ", // nf-md-docker
            Self::UserManagement => "󰀉 ",      // nf-md-account_multiple
            Self::NetworkConfig => "󰛳 ",       // nf-md-network
            Self::BootKernelOptions => "󱓞 ",   // nf-fa-rocket
            Self::StorageFilesystem => "󰋊 ",   // nf-md-harddisk
            Self::SystemInfo => " ",          // nf-fa-info_circle
        }
    }
}

pub enum AppView {
    MainMenu,
    ShellManagement,
    SystemUpdates,
    SystemInfo,
}

pub struct App {
    pub should_quit: bool,
    pub menu_state: ListState,
    pub menu_items: Vec<MenuItem>,
    pub current_view: AppView,
    pub shell_management_view: Option<ShellManagementView>,
    pub system_updates_view: Option<SystemUpdatesView>,
    pub system_info_view: Option<SystemInfoView>,
    pub terminal_popup: Option<TerminalPopup>,
    pub too_small: bool,
}

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

        let too_small = !check_terminal_size().unwrap_or(true); // Default to true if check fails

        Self {
            should_quit: false,
            menu_state,
            menu_items: MenuItem::all(),
            current_view: AppView::MainMenu,
            shell_management_view: None,
            system_updates_view: None,
            system_info_view: None,
            terminal_popup: None,
            too_small,
        }
    }

    pub fn run(&mut self, terminal: &mut ratatui::DefaultTerminal) -> Result<()> {
        while !self.should_quit {
            terminal.draw(|frame| self.render(frame))?;
            self.handle_events()?;
        }
        Ok(())
    }

    fn render(&mut self, frame: &mut Frame) {
        if self.too_small {
            self.render_too_small(frame, frame.area());
            return;
        }

        // Create margins around the content
        let content_area = Layout::default()
            .direction(Direction::Horizontal)
            .constraints([
                Constraint::Percentage(5),  // Left margin
                Constraint::Percentage(90), // Content
                Constraint::Percentage(5),  // Right margin
            ])
            .split(frame.area())[1];

        match self.current_view {
            AppView::MainMenu => self.render_main_menu(frame, content_area),
            AppView::ShellManagement => {
                if let Some(view) = &mut self.shell_management_view {
                    view.render(frame, content_area);
                }
            }
            AppView::SystemUpdates => {
                if let Some(view) = &mut self.system_updates_view {
                    view.render(frame, content_area);
                }
            }
            AppView::SystemInfo => {
                if let Some(view) = &mut self.system_info_view {
                    view.render(frame, content_area);
                }
            }
        }

        // Render terminal popup on top if active
        if let Some(popup) = &mut self.terminal_popup {
            popup.render(frame, content_area);
        }
    }

    fn render_main_menu(&mut self, frame: &mut Frame, area: Rect) {
        // Create main layout
        let chunks = Layout::default()
            .direction(Direction::Vertical)
            .constraints([
                Constraint::Length(3), // Header
                Constraint::Min(0),    // Main content
                Constraint::Length(3), // Footer
            ])
            .split(area);

        // Render header
        self.render_header(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_menu(frame, content_chunks[0]);
        self.render_details(frame, content_chunks[1]);

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

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

        frame.render_widget(title, area);
    }

    fn render_menu(&mut self, frame: &mut Frame, area: Rect) {
        let items: Vec<ListItem> = self
            .menu_items
            .iter()
            .enumerate()
            .map(|(i, item)| {
                let is_selected = self.menu_state.selected() == Some(i);
                // Don't show selection highlight when terminal popup is active
                let style = if is_selected && self.terminal_popup.is_none() {
                    Style::default()
                        .fg(Color::Black)
                        .bg(Color::Cyan)
                        .add_modifier(Modifier::BOLD)
                } else {
                    Style::default().fg(Color::White)
                };

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

        let list = List::new(items).block(
            Block::default()
                .title(" Main Menu ")
                .borders(Borders::ALL)
                .border_style(Style::default().fg(Color::White)),
        );

        // Only apply highlight style when popup is not active
        let list = if self.terminal_popup.is_none() {
            list.highlight_style(
                Style::default()
                    .fg(Color::Black)
                    .bg(Color::Cyan)
                    .add_modifier(Modifier::BOLD),
            )
        } else {
            list
        };

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

    fn render_details(&self, frame: &mut Frame, area: Rect) {
        let selected_item = self
            .menu_state
            .selected()
            .and_then(|i| self.menu_items.get(i));

        let content = if let Some(item) = selected_item {
            let mut content = vec![
                Line::from(vec![
                    Span::styled(item.icon(), Style::default().fg(Color::Cyan)),
                    Span::raw(" "),
                    Span::styled(
                        item.title(),
                        Style::default()
                            .fg(Color::Cyan)
                            .add_modifier(Modifier::BOLD),
                    ),
                ]),
                Line::from(""),
                Line::from(Span::styled(
                    "Description:",
                    Style::default()
                        .fg(Color::Yellow)
                        .add_modifier(Modifier::BOLD),
                )),
            ];
            content.extend(item.description().lines().map(Line::from));
            content.extend(vec![
                Line::from(""),
                Line::from(Span::styled(
                    "Press Enter to access this module",
                    Style::default().fg(Color::Green),
                )),
            ]);
            content
        } else {
            vec![Line::from("No item selected")]
        };

        let details = Paragraph::new(content)
            .block(
                Block::default()
                    .title(" Details ")
                    .borders(Borders::ALL)
                    .border_style(Style::default().fg(Color::White)),
            )
            .wrap(ratatui::widgets::Wrap { trim: true });

        frame.render_widget(details, 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/l ",
                Style::default()
                    .fg(Color::Green)
                    .add_modifier(Modifier::BOLD),
            ),
            Span::raw("Select  "),
            Span::styled(
                " q/Esc ",
                Style::default().fg(Color::Red).add_modifier(Modifier::BOLD),
            ),
            Span::raw("Quit"),
        ])];

        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_too_small(&self, frame: &mut Frame, area: Rect) {
        let message = Paragraph::new(vec![
            Line::from("Terminal size too small."),
            Line::from(""),
            Line::from(format!(
                "Please resize to at least {}x{}.",
                MIN_WIDTH, MIN_HEIGHT
            )),
            Line::from(""),
            Line::from("Press Ctrl+C to exit."),
        ])
        .block(
            Block::default()
                .borders(Borders::ALL)
                .border_style(Style::default().fg(Color::Red))
                .title("Size Warning"),
        )
        .centered();

        frame.render_widget(message, area);
    }

    fn handle_events(&mut self) -> Result<()> {
        // Use a very short timeout (10ms) for more responsive updates
        // This allows the render loop to continue frequently even when no input is available
        // The short timeout ensures we can detect PTY output changes quickly
        if !poll(Duration::from_millis(10))? {
            // No event available, return and let the render loop continue
            // This is important for PTY output to be displayed in real-time
            return Ok(());
        }

        let event = read()?;

        // Handle resize globally
        if let Event::Resize(w, h) = event {
            self.too_small = w < MIN_WIDTH || h < MIN_HEIGHT;
            return Ok(());
        }

        // If terminal popup is active, route key events to it
        if let Some(popup) = &mut self.terminal_popup {
            if let Event::Key(key) = event {
                if key.kind == KeyEventKind::Press {
                    let should_close = popup.handle_key(key)?;
                    if should_close {
                        self.terminal_popup = None;
                    }
                }
            }
            return Ok(());
        }

        match self.current_view {
            AppView::MainMenu => {
                if let Event::Key(key) = event {
                    if key.kind == KeyEventKind::Press {
                        self.handle_key_event(key);
                    }
                }
            }
            AppView::ShellManagement => {
                let mut should_go_back = false;
                let mut terminal_command = None;

                if let Some(view) = &mut self.shell_management_view {
                    should_go_back = view.handle_events(Some(event))?;

                    // Check if a terminal command should be spawned
                    terminal_command = view.take_terminal_command();
                }

                if should_go_back {
                    self.current_view = AppView::MainMenu;
                    self.shell_management_view = None;
                } else if let Some((cmd, args)) = terminal_command {
                    let mut popup =
                        TerminalPopup::new(format!("Running: {} {}", cmd, args.join(" ")));
                    let args_refs: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
                    if let Err(_e) = popup.start(&cmd, &args_refs) {
                        // If failed to start, the error will be shown in the terminal popup
                        // For now, we just don't create the popup
                    } else {
                        self.terminal_popup = Some(popup);
                    }
                }
            }
            AppView::SystemUpdates => {
                let mut should_go_back = false;
                let mut terminal_command = None;

                if let Some(view) = &mut self.system_updates_view {
                    should_go_back = view.handle_events(Some(event))?;

                    // Check if a terminal command should be spawned
                    terminal_command = view.take_terminal_command();
                }

                if should_go_back {
                    self.current_view = AppView::MainMenu;
                    self.system_updates_view = None;
                } else if let Some((cmd, args)) = terminal_command {
                    let mut popup =
                        TerminalPopup::new(format!("Running: {} {}", cmd, args.join(" ")));
                    let args_refs: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
                    if let Err(_e) = popup.start(&cmd, &args_refs) {
                        // If failed to start, the error will be shown in the terminal popup
                        // For now, we just don't create the popup
                    } else {
                        self.terminal_popup = Some(popup);
                    }
                }
            }
            AppView::SystemInfo => {
                let mut should_go_back = false;
                let mut terminal_command = None;

                if let Some(view) = &mut self.system_info_view {
                    should_go_back = view.handle_events(Some(event))?;

                    // Check if a terminal command should be spawned
                    terminal_command = view.take_terminal_command();
                }

                if should_go_back {
                    self.current_view = AppView::MainMenu;
                    self.system_info_view = None;
                } else if let Some((cmd, args)) = terminal_command {
                    let mut popup =
                        TerminalPopup::new(format!("Running: {} {}", cmd, args.join(" ")));
                    let args_refs: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
                    if let Err(_e) = popup.start(&cmd, &args_refs) {
                        // If failed to start, the error will be shown in the terminal popup
                        // For now, we just don't create the popup
                    } else {
                        self.terminal_popup = Some(popup);
                    }
                }
            }
        }
        Ok(())
    }

    fn handle_key_event(&mut self, key: KeyEvent) {
        match key.code {
            KeyCode::Char('q') | KeyCode::Esc => {
                self.should_quit = true;
            }
            KeyCode::Down | KeyCode::Char('j') => {
                self.next_item();
            }
            KeyCode::Up | KeyCode::Char('k') => {
                self.previous_item();
            }
            KeyCode::Enter | KeyCode::Char('l') => {
                if let Some(i) = self.menu_state.selected() {
                    if let Some(item) = self.menu_items.get(i) {
                        match item {
                            MenuItem::ShellManagement => {
                                self.current_view = AppView::ShellManagement;
                                self.shell_management_view = Some(ShellManagementView::new());
                            }
                            MenuItem::SystemUpdates => {
                                self.current_view = AppView::SystemUpdates;
                                self.system_updates_view = Some(SystemUpdatesView::new());
                            }
                            MenuItem::SystemInfo => {
                                self.current_view = AppView::SystemInfo;
                                self.system_info_view = Some(SystemInfoView::new());
                            }
                            _ => {
                                // Other modules not implemented yet
                            }
                        }
                    }
                }
            }
            _ => {}
        }
    }

    fn next_item(&mut self) {
        let i = match self.menu_state.selected() {
            Some(i) => {
                if i >= self.menu_items.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.menu_items.len() - 1
                } else {
                    i - 1
                }
            }
            None => 0,
        };
        self.menu_state.select(Some(i));
    }
}

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