// D64 File Picker Dialog
// Shows list of PRG files from a D64 disk image and allows user to select one

use crate::parser::d64::{D64FileEntry, FileType};
use crate::state::AppState;
use crate::ui::widget::{Widget, WidgetResult};
use crate::ui_state::UIState;
use ratatui::{
    Frame,
    layout::Rect,
    style::{Color, Modifier, Style},
    text::{Line, Span},
    widgets::{List, ListItem, ListState},
};
use std::path::PathBuf;

struct FilePickerEntry {
    entry: D64FileEntry,
    start_addr: Option<u16>,
    end_addr: Option<u16>,
    entropy: Option<f32>,
}

pub struct D64FilePickerDialog {
    files: Vec<FilePickerEntry>,
    selected_index: usize,
    disk_data: Vec<u8>,
    disk_path: PathBuf,
}

impl D64FilePickerDialog {
    pub fn new(files: Vec<D64FileEntry>, disk_data: Vec<u8>, disk_path: PathBuf) -> Self {
        let entries = files
            .into_iter()
            .map(|entry| {
                let mut start_addr = None;
                let mut end_addr = None;
                let mut entropy = None;

                if entry.file_type == FileType::PRG
                    && let Ok((start, data)) = crate::parser::d64::extract_file(&disk_data, &entry)
                {
                    start_addr = Some(start);
                    if !data.is_empty() {
                        end_addr = Some(start.wrapping_add(data.len() as u16).wrapping_sub(1));
                        entropy = Some(crate::utils::calculate_entropy(&data));
                    } else {
                        // Empty file (just load address?)
                        end_addr = Some(start);
                        entropy = Some(0.0);
                    }
                }

                FilePickerEntry {
                    entry,
                    start_addr,
                    end_addr,
                    entropy,
                }
            })
            .collect();

        Self {
            files: entries,
            selected_index: 0,
            disk_data,
            disk_path,
        }
    }

    fn page_up(&mut self) {
        // Move back by 10 items
        self.selected_index = self.selected_index.saturating_sub(10);
    }

    fn page_down(&mut self) {
        if !self.files.is_empty() {
            // Advance by 10 items, but don't go past the last item
            self.selected_index = (self.selected_index + 10).min(self.files.len() - 1);
        }
    }
}

impl Widget for D64FilePickerDialog {
    fn render(&self, f: &mut Frame, area: Rect, _app_state: &AppState, ui_state: &mut UIState) {
        let theme = &ui_state.theme;
        let disk_name = self
            .disk_path
            .file_name()
            .and_then(|n| n.to_str())
            .unwrap_or("Unknown");

        let title = format!(" Select PRG from {} (Enter: Load, Esc: Cancel) ", disk_name);
        let block = crate::ui::widget::create_dialog_block(&title, theme);

        let area = crate::utils::centered_rect_adaptive(80, 60, 80, 14, area);
        ui_state.active_dialog_area = area;
        f.render_widget(ratatui::widgets::Clear, area); // Clear background

        let items: Vec<ListItem> = self
            .files
            .iter()
            .map(|picker_entry| {
                let entry = &picker_entry.entry;
                let filename = if entry.filename.len() > 37 {
                    format!("{}...", &entry.filename[..34])
                } else {
                    entry.filename.clone()
                };

                let addr_str = if let (Some(start), Some(end)) =
                    (picker_entry.start_addr, picker_entry.end_addr)
                {
                    format!("${:04X}-${:04X}", start, end)
                } else {
                    String::new()
                };

                let entropy_str = if let Some(e) = picker_entry.entropy {
                    format!("{:>5.2}", e)
                } else {
                    "     ".to_string()
                };

                let content = format!(
                    "{:<37} {:>3} {:>4} blks  {:<11}  {}",
                    filename,
                    entry.file_type.as_str(),
                    entry.size_sectors,
                    addr_str,
                    entropy_str
                );

                let is_prg = entry.file_type == FileType::PRG;

                // Dim non-PRG files when not selected (selection style handles the rest)
                let style = if !is_prg {
                    Style::default().fg(Color::DarkGray)
                } else {
                    Style::default()
                };

                ListItem::new(Line::from(Span::styled(content, style)))
            })
            .collect();

        let list = List::new(items)
            .block(block)
            .highlight_style(
                Style::default()
                    .bg(theme.menu_selected_bg)
                    .fg(theme.menu_selected_fg)
                    .add_modifier(Modifier::BOLD),
            )
            .highlight_symbol(">> ");

        let mut state = ListState::default();
        state.select(Some(self.selected_index));

        f.render_stateful_widget(list, area, &mut state);
    }

    fn handle_input(
        &mut self,
        key: crossterm::event::KeyEvent,
        app_state: &mut AppState,
        ui_state: &mut UIState,
    ) -> WidgetResult {
        use crossterm::event::{KeyCode, KeyModifiers};

        match key.code {
            KeyCode::Esc => {
                // Cancel and return to file browser
                WidgetResult::Close
            }
            KeyCode::Up | KeyCode::Char('k') => {
                if !self.files.is_empty() {
                    if self.selected_index > 0 {
                        self.selected_index -= 1;
                    } else {
                        self.selected_index = self.files.len() - 1;
                    }
                }
                WidgetResult::Handled
            }
            KeyCode::Down | KeyCode::Char('j') => {
                if !self.files.is_empty() {
                    if self.selected_index < self.files.len() - 1 {
                        self.selected_index += 1;
                    } else {
                        self.selected_index = 0;
                    }
                }
                WidgetResult::Handled
            }
            KeyCode::PageUp => {
                self.page_up();
                WidgetResult::Handled
            }
            KeyCode::PageDown => {
                self.page_down();
                WidgetResult::Handled
            }
            KeyCode::Char('u') if key.modifiers == KeyModifiers::CONTROL => {
                self.page_up();
                WidgetResult::Handled
            }
            KeyCode::Char('d') if key.modifiers == KeyModifiers::CONTROL => {
                self.page_down();
                WidgetResult::Handled
            }
            KeyCode::Enter => {
                // Load the selected file
                let selected_entry = &self.files[self.selected_index].entry;

                if selected_entry.file_type != FileType::PRG {
                    ui_state.set_status_message(format!(
                        "Cannot load {} file: only PRG files supported",
                        selected_entry.file_type.as_str()
                    ));
                    return WidgetResult::Handled;
                }

                match crate::parser::d64::extract_file(&self.disk_data, selected_entry) {
                    Ok((load_address, program_data)) => {
                        // Set origin and raw data
                        app_state.origin = load_address;
                        // Let's redo.
                        match app_state.load_binary(load_address, program_data) {
                            Ok(loaded_data) => {
                                // Apply loaded UI state if needed (like cursor pos), though load_binary defaults them.
                                crate::ui::dialog_warning::WarningDialog::show_if_needed(
                                    loaded_data.entropy_warning,
                                    ui_state,
                                );

                                app_state.file_path = Some(self.disk_path.clone());
                                WidgetResult::Close
                            }
                            Err(e) => {
                                ui_state.set_status_message(format!("Error loading file: {}", e));
                                WidgetResult::Handled
                            }
                        }
                    }
                    Err(e) => {
                        ui_state.set_status_message(format!("Error loading file: {}", e));
                        WidgetResult::Handled
                    }
                }
            }
            _ => WidgetResult::Handled,
        }
    }
}
