use crate::{
    app::{App, InputMode, SelectedRegister},
    input_form::draw_structured_input_form,
};
use ratatui::{
    backend::Backend,
    layout::{Alignment, Constraint, Direction, Layout, Rect},
    style::{Color, Modifier, Style},
    text::{Line, Span},
    widgets::{Block, Borders, Clear, List, ListItem, Paragraph, Wrap},
    Frame, Terminal,
};
use std::error::Error;

pub fn ui(f: &mut Frame, app: &mut App) {
    if app.show_help {
        draw_help(f);
        return;
    }

    draw_structured_ui(f, app);

    // Input popup if needed
    if matches!(
        app.input_mode,
        InputMode::EditValue | InputMode::SaveFile | InputMode::LoadFile
    ) {
        draw_input_popup(f, app);
    }
}

fn draw_structured_ui(f: &mut Frame, app: &mut App) {
    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Length(3),
            Constraint::Length(7),
            Constraint::Min(5),
            Constraint::Length(3),
        ])
        .split(f.size());

    // Title
    let title = Paragraph::new("FCB1010 Structured Note Mapper")
        .style(
            Style::default()
                .fg(Color::Cyan)
                .add_modifier(Modifier::BOLD),
        )
        .alignment(Alignment::Center)
        .block(Block::default().borders(Borders::ALL));
    f.render_widget(title, chunks[0]);

    // Register values
    draw_register_values(f, app, chunks[1]);

    // Main content area
    if app.input_mode == InputMode::StructuredInput {
        draw_structured_input_form(f, &app.structured_form, chunks[2]);
    } else {
        draw_structured_notes_list(f, app, chunks[2]);
    }

    // Status bar
    let status_text = if app.input_mode == InputMode::StructuredInput {
        "Enter: Save note | Esc: Cancel | Space/↑↓: Navigate fields | 0/1: LED state | Letters: Text input"
    } else {
        "←→: Select register | 0-7: Toggle bit | v: Edit value | r: Reset | f: Fill | n: New note | ↑↓: Navigate | Del: Delete | s: Save | l: Load | h: Help | q: Quit"
    };

    let status = Paragraph::new(status_text)
        .style(Style::default().fg(Color::White))
        .block(Block::default().borders(Borders::ALL));
    f.render_widget(status, chunks[3]);
}

fn draw_structured_notes_list(f: &mut Frame, app: &mut App, area: Rect) {
    let items: Vec<ListItem> = app
        .structured_notes
        .iter()
        .enumerate()
        .map(|(i, note)| {
            let mut content = String::new();

            // Add register values in binary format first
            let ic03 = note.register_values.get("IC03").unwrap_or(&0);
            let ic10 = note.register_values.get("IC10").unwrap_or(&0);
            let ic11 = note.register_values.get("IC11").unwrap_or(&0);
            content.push_str(&format!(
                "[IC03:{:08b}, IC10:{:08b}, IC11:{:08b}]",
                ic03, ic10, ic11
            ));

            // Add dash separator and note description
            content.push_str(&format!(" - {}. {}", i + 1, note.description));

            ListItem::new(content)
        })
        .collect();

    let mut notes_list_state = app.notes_list_state.clone();
    let notes_list = List::new(items)
        .block(
            Block::default()
                .borders(Borders::ALL)
                .title("Structured Notes (Enter to restore register values, Del to remove)"),
        )
        .highlight_style(
            Style::default()
                .fg(Color::Yellow)
                .add_modifier(Modifier::BOLD),
        )
        .highlight_symbol("→ ");

    f.render_stateful_widget(notes_list, area, &mut notes_list_state);
}

fn draw_register_values(f: &mut Frame, app: &App, area: Rect) {
    let chunks = Layout::default()
        .direction(Direction::Horizontal)
        .constraints([
            Constraint::Percentage(33),
            Constraint::Percentage(33),
            Constraint::Percentage(34),
        ])
        .split(area);

    let registers = [
        (&SelectedRegister::IC03, "IC03"),
        (&SelectedRegister::IC10, "IC10"),
        (&SelectedRegister::IC11, "IC11"),
    ];

    for (i, (register, name)) in registers.iter().enumerate() {
        let value = *app.register_values.get(*name).unwrap_or(&0);
        let is_selected = app.selected_register == **register;

        let mut lines = Vec::new();
        lines.push(Line::from(vec![
            Span::styled(
                format!("{}: ", name),
                Style::default().add_modifier(Modifier::BOLD),
            ),
            Span::raw(format!("{:08b} = {}", value, value)),
        ]));

        // Bit representation
        let mut bit_spans = Vec::new();
        for bit in (0..8).rev() {
            let is_set = (value >> bit) & 1 == 1;
            let style = if is_set {
                Style::default()
                    .fg(Color::Green)
                    .add_modifier(Modifier::BOLD)
            } else {
                Style::default().fg(Color::DarkGray)
            };
            bit_spans.push(Span::styled(
                format!("[{}]", if is_set { "■" } else { "□" }),
                style,
            ));
        }
        lines.push(Line::from(bit_spans));

        // Bit numbers
        let mut bit_num_spans = Vec::new();
        for bit in (0..8).rev() {
            bit_num_spans.push(Span::styled(
                format!(" {} ", bit),
                Style::default().fg(Color::Yellow),
            ));
        }
        lines.push(Line::from(bit_num_spans));

        let border_style = if is_selected {
            Style::default().fg(Color::Yellow)
        } else {
            Style::default()
        };

        let block = Block::default()
            .borders(Borders::ALL)
            .style(border_style)
            .title(if is_selected {
                format!("→ {}", name)
            } else {
                name.to_string()
            });

        let paragraph = Paragraph::new(lines).block(block);
        f.render_widget(paragraph, chunks[i]);
    }
}

fn draw_input_popup(f: &mut Frame, app: &App) {
    let area = centered_rect(60, 20, f.size());
    f.render_widget(Clear, area);

    let title = match app.input_mode {
        InputMode::EditValue => "Edit Value",
        InputMode::SaveFile => "Save File",
        InputMode::LoadFile => "Load File",
        _ => "Input",
    };

    let block = Block::default()
        .title(title)
        .borders(Borders::ALL)
        .style(Style::default().fg(Color::Yellow));

    // Create text with cursor using char-aware operations
    let mut spans = Vec::new();
    let chars: Vec<char> = app.input_buffer.chars().collect();

    if chars.is_empty() {
        spans.push(Span::styled(
            "█",
            Style::default()
                .fg(Color::White)
                .add_modifier(Modifier::REVERSED),
        ));
    } else {
        if app.cursor_position > 0 {
            let before_cursor: String = chars.iter().take(app.cursor_position).collect();
            spans.push(Span::raw(before_cursor));
        }

        if app.cursor_position < chars.len() {
            let cursor_char = chars[app.cursor_position];
            spans.push(Span::styled(
                cursor_char.to_string(),
                Style::default()
                    .fg(Color::White)
                    .add_modifier(Modifier::REVERSED),
            ));

            if app.cursor_position + 1 < chars.len() {
                let after_cursor: String = chars.iter().skip(app.cursor_position + 1).collect();
                spans.push(Span::raw(after_cursor));
            }
        } else {
            spans.push(Span::styled(
                "█",
                Style::default()
                    .fg(Color::White)
                    .add_modifier(Modifier::REVERSED),
            ));
        }
    }

    let paragraph = Paragraph::new(Line::from(spans)).block(block);

    f.render_widget(paragraph, area);
}

fn draw_help(f: &mut Frame) {
    let help_text = vec![
        "FCB1010 Structured Note Mapper - Help",
        "",
        "Register Control:",
        "  ←→          - Select IC03, IC10, IC11 register",
        "  0-7         - Toggle bit 0-7 of selected register",
        "  v           - Edit register value directly (0-255)",
        "  r           - Reset register to 0",
        "  f           - Fill register (set to 255)",
        "",
        "Notes Management:",
        "  n           - Create new structured note",
        "  ↑↓          - Navigate notes list",
        "  Enter       - Restore register values from selected note",
        "  Del         - Delete selected note",
        "",
        "File Operations:",
        "  s           - Save mapping to file",
        "  l           - Load mapping from file",
        "",
        "In Structured Note Input:",
        "  0/1         - Set LED state for current field",
        "  Space/↑↓    - Navigate between fields",
        "  Text input  - For display segments and button fields",
        "  Enter       - Save structured note",
        "  Esc         - Cancel input",
        "",
        "LED Fields:",
        "  Switch 1, Switch 2, Switches, Select, Number,",
        "  Value 1, Value 2, Direct Select, MIDI Function,",
        "  MIDI Chan, Config, Expression Pedal A/B",
        "",
        "Text Fields:",
        "  Display 1/2/3 - Active display segments",
        "  Button LEDs - Active button LEDs",
        "  Button Presses - Buttons that react to press",
        "",
        "File Format:",
        "  Saves/loads in original format for compatibility",
        "  Register editor + structured notes for full control",
        "",
        "Other:",
        "  h           - Toggle this help",
        "  q           - Quit",
        "",
        "Press 'h' again to return to main view",
    ];

    let help_paragraph = Paragraph::new(
        help_text
            .iter()
            .map(|&line| Line::from(line))
            .collect::<Vec<_>>(),
    )
    .block(Block::default().title("Help").borders(Borders::ALL))
    .wrap(Wrap { trim: true });

    f.render_widget(help_paragraph, f.size());
}

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

pub fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> Result<(), Box<dyn Error>> {
    loop {
        terminal.draw(|f| ui(f, &mut app))?;

        if let crossterm::event::Event::Key(key) = crossterm::event::read()? {
            if key.kind == crossterm::event::KeyEventKind::Press {
                if handle_input(&mut app, key.code)? {
                    break;
                }
            }
        }
    }
    Ok(())
}

pub fn handle_input(app: &mut App, key: crossterm::event::KeyCode) -> Result<bool, Box<dyn Error>> {
    match app.input_mode {
        InputMode::StructuredInput => app.handle_structured_input(key),
        _ => handle_legacy_input(app, key),
    }
}

fn handle_legacy_input(
    app: &mut App,
    key: crossterm::event::KeyCode,
) -> Result<bool, Box<dyn Error>> {
    match app.input_mode {
        InputMode::Normal => handle_normal_input(app, key),
        InputMode::EditValue => handle_edit_value_input(app, key),
        InputMode::SaveFile => handle_save_file_input(app, key),
        InputMode::LoadFile => handle_load_file_input(app, key),
        _ => Ok(false),
    }
}

fn handle_normal_input(
    app: &mut App,
    key: crossterm::event::KeyCode,
) -> Result<bool, Box<dyn Error>> {
    use crossterm::event::KeyCode;

    match key {
        KeyCode::Char('q') => {
            let _ = app.command_sender.send(crate::midi::MidiCommand::Quit);
            return Ok(true);
        }
        KeyCode::Char('h') => app.show_help = !app.show_help,
        KeyCode::Char('n') => {
            app.start_structured_input();
        }
        KeyCode::Left => {
            app.selected_register = match app.selected_register {
                SelectedRegister::IC03 => SelectedRegister::IC11,
                SelectedRegister::IC10 => SelectedRegister::IC03,
                SelectedRegister::IC11 => SelectedRegister::IC10,
            };
        }
        KeyCode::Right => {
            app.selected_register = match app.selected_register {
                SelectedRegister::IC03 => SelectedRegister::IC10,
                SelectedRegister::IC10 => SelectedRegister::IC11,
                SelectedRegister::IC11 => SelectedRegister::IC03,
            };
        }
        KeyCode::Char(c @ '0'..='7') => {
            if let Some(bit) = c.to_digit(10) {
                app.toggle_bit(bit as u8);
            }
        }
        KeyCode::Char('r') => {
            app.set_current_value(0);
            app.status_message = format!("{} reset to 0", app.selected_register.as_str());
        }
        KeyCode::Char('f') => {
            app.set_current_value(255);
            app.status_message = format!("{} set to 255", app.selected_register.as_str());
        }
        KeyCode::Char('v') => {
            app.input_mode = InputMode::EditValue;
            app.input_buffer = app.get_current_value().to_string();
            app.cursor_position = app.input_buffer.chars().count();
        }
        KeyCode::Char('s') => {
            app.input_mode = InputMode::SaveFile;
            app.input_buffer = "mapping.json".to_string();
            app.cursor_position = app.input_buffer.chars().count();
        }
        KeyCode::Char('l') => {
            app.input_mode = InputMode::LoadFile;
            app.input_buffer = "mapping.json".to_string();
            app.cursor_position = app.input_buffer.chars().count();
        }
        KeyCode::Up => {
            let notes_len = app.structured_notes.len();

            if let Some(selected) = app.notes_list_state.selected() {
                if selected > 0 {
                    app.notes_list_state.select(Some(selected - 1));
                }
            } else if notes_len > 0 {
                app.notes_list_state.select(Some(0));
            }
        }
        KeyCode::Down => {
            let notes_len = app.structured_notes.len();

            if let Some(selected) = app.notes_list_state.selected() {
                if selected < notes_len.saturating_sub(1) {
                    app.notes_list_state.select(Some(selected + 1));
                }
            } else if notes_len > 0 {
                app.notes_list_state.select(Some(0));
            }
        }
        KeyCode::Enter => {
            if let Some(selected) = app.notes_list_state.selected() {
                if let Some(note) = app.structured_notes.get(selected) {
                    // Restore register values from note
                    app.register_values = note.register_values.clone();
                    app.status_message = "Register values restored from note".to_string();

                    // Send MIDI updates for all registers
                    for (register_name, &value) in &app.register_values {
                        match register_name.as_str() {
                            "IC03" => {
                                let old_selected = app.selected_register;
                                app.selected_register = SelectedRegister::IC03;
                                app.send_midi_value(value);
                                app.selected_register = old_selected;
                            }
                            "IC10" => {
                                let old_selected = app.selected_register;
                                app.selected_register = SelectedRegister::IC10;
                                app.send_midi_value(value);
                                app.selected_register = old_selected;
                            }
                            "IC11" => {
                                let old_selected = app.selected_register;
                                app.selected_register = SelectedRegister::IC11;
                                app.send_midi_value(value);
                                app.selected_register = old_selected;
                            }
                            _ => {}
                        }
                    }
                }
            }
        }
        KeyCode::Delete => {
            if let Some(selected) = app.notes_list_state.selected() {
                if selected < app.structured_notes.len() {
                    app.structured_notes.remove(selected);
                    if app.structured_notes.is_empty() {
                        app.notes_list_state.select(None);
                    } else if selected >= app.structured_notes.len() {
                        app.notes_list_state
                            .select(Some(app.structured_notes.len() - 1));
                    }
                    app.status_message = "Note deleted".to_string();
                }
            }
        }
        _ => {}
    }
    Ok(false)
}

// Implement other input handlers (edit_value, save_file, load_file)

fn handle_edit_value_input(
    app: &mut App,
    key: crossterm::event::KeyCode,
) -> Result<bool, Box<dyn Error>> {
    use crossterm::event::KeyCode;

    match key {
        KeyCode::Enter => {
            match app.input_buffer.parse::<u8>() {
                Ok(value) => {
                    app.set_current_value(value);
                    app.status_message =
                        format!("{} set to {}", app.selected_register.as_str(), value);
                }
                Err(_) => {
                    app.status_message = "Invalid value (0-255)".to_string();
                }
            }
            app.input_mode = InputMode::Normal;
            app.input_buffer.clear();
            app.cursor_position = 0;
        }
        KeyCode::Esc => {
            app.input_mode = InputMode::Normal;
            app.input_buffer.clear();
            app.cursor_position = 0;
        }
        KeyCode::Left => {
            if app.cursor_position > 0 {
                app.cursor_position -= 1;
            }
        }
        KeyCode::Right => {
            let char_count = app.input_buffer.chars().count();
            if app.cursor_position < char_count {
                app.cursor_position += 1;
            }
        }
        KeyCode::Home => {
            app.cursor_position = 0;
        }
        KeyCode::End => {
            app.cursor_position = app.input_buffer.chars().count();
        }
        KeyCode::Backspace => {
            if app.cursor_position > 0 {
                let mut chars: Vec<char> = app.input_buffer.chars().collect();
                chars.remove(app.cursor_position - 1);
                app.input_buffer = chars.into_iter().collect();
                app.cursor_position -= 1;
            }
        }
        KeyCode::Delete => {
            let char_count = app.input_buffer.chars().count();
            if app.cursor_position < char_count {
                let mut chars: Vec<char> = app.input_buffer.chars().collect();
                chars.remove(app.cursor_position);
                app.input_buffer = chars.into_iter().collect();
            }
        }
        KeyCode::Char(c) => {
            if let Ok(potential_value) =
                format!("{}{}", &app.input_buffer[..app.cursor_position], c).parse::<u16>()
            {
                if potential_value <= 255 {
                    let mut chars: Vec<char> = app.input_buffer.chars().collect();
                    chars.insert(app.cursor_position, c);
                    app.input_buffer = chars.into_iter().collect();
                    app.cursor_position += 1;
                }
            } else if app.input_buffer.len() < 3 {
                let mut chars: Vec<char> = app.input_buffer.chars().collect();
                chars.insert(app.cursor_position, c);
                app.input_buffer = chars.into_iter().collect();
                app.cursor_position += 1;
            }
        }
        _ => {}
    }
    Ok(false)
}

fn handle_save_file_input(
    app: &mut App,
    key: crossterm::event::KeyCode,
) -> Result<bool, Box<dyn Error>> {
    use crossterm::event::KeyCode;

    match key {
        KeyCode::Enter => {
            match app.save_mapping(&app.input_buffer) {
                Ok(_) => app.status_message = format!("Saved to {}", app.input_buffer),
                Err(e) => app.status_message = format!("Save failed: {}", e),
            }
            app.input_mode = InputMode::Normal;
            app.input_buffer.clear();
            app.cursor_position = 0;
        }
        KeyCode::Esc => {
            app.input_mode = InputMode::Normal;
            app.input_buffer.clear();
            app.cursor_position = 0;
        }
        KeyCode::Left => {
            if app.cursor_position > 0 {
                app.cursor_position -= 1;
            }
        }
        KeyCode::Right => {
            let char_count = app.input_buffer.chars().count();
            if app.cursor_position < char_count {
                app.cursor_position += 1;
            }
        }
        KeyCode::Home => {
            app.cursor_position = 0;
        }
        KeyCode::End => {
            app.cursor_position = app.input_buffer.chars().count();
        }
        KeyCode::Backspace => {
            if app.cursor_position > 0 {
                let mut chars: Vec<char> = app.input_buffer.chars().collect();
                chars.remove(app.cursor_position - 1);
                app.input_buffer = chars.into_iter().collect();
                app.cursor_position -= 1;
            }
        }
        KeyCode::Delete => {
            let char_count = app.input_buffer.chars().count();
            if app.cursor_position < char_count {
                let mut chars: Vec<char> = app.input_buffer.chars().collect();
                chars.remove(app.cursor_position);
                app.input_buffer = chars.into_iter().collect();
            }
        }
        KeyCode::Char(c) => {
            let mut chars: Vec<char> = app.input_buffer.chars().collect();
            chars.insert(app.cursor_position, c);
            app.input_buffer = chars.into_iter().collect();
            app.cursor_position += 1;
        }
        _ => {}
    }
    Ok(false)
}

fn handle_load_file_input(
    app: &mut App,
    key: crossterm::event::KeyCode,
) -> Result<bool, Box<dyn Error>> {
    use crossterm::event::KeyCode;

    match key {
        KeyCode::Enter => {
            let filename = app.input_buffer.clone();
            match app.load_mapping(&filename) {
                Ok(_) => {
                    if app.status_message.is_empty() {
                        app.status_message = format!("Loaded from {}", filename);
                    }
                }
                Err(e) => app.status_message = format!("Load failed: {}", e),
            }
            app.input_mode = InputMode::Normal;
            app.input_buffer.clear();
            app.cursor_position = 0;
        }
        KeyCode::Esc => {
            app.input_mode = InputMode::Normal;
            app.input_buffer.clear();
            app.cursor_position = 0;
        }
        KeyCode::Left => {
            if app.cursor_position > 0 {
                app.cursor_position -= 1;
            }
        }
        KeyCode::Right => {
            if app.cursor_position < app.input_buffer.len() {
                app.cursor_position += 1;
            }
        }
        KeyCode::Home => {
            app.cursor_position = 0;
        }
        KeyCode::End => {
            app.cursor_position = app.input_buffer.len();
        }
        KeyCode::Backspace => {
            if app.cursor_position > 0 {
                app.input_buffer.remove(app.cursor_position - 1);
                app.cursor_position -= 1;
            }
        }
        KeyCode::Delete => {
            if app.cursor_position < app.input_buffer.len() {
                app.input_buffer.remove(app.cursor_position);
            }
        }
        KeyCode::Char(c) => {
            app.input_buffer.insert(app.cursor_position, c);
            app.cursor_position += 1;
        }
        _ => {}
    }
    Ok(false)
}
