use crate::data::StructuredNote;
use ratatui::{
    layout::Rect,
    style::{Color, Modifier, Style},
    text::{Line, Span},
    widgets::{Block, Borders, Paragraph},
    Frame,
};
use std::collections::HashMap;

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum InputField {
    Switch1,
    Switch2,
    Switches,
    Select,
    Number,
    Value1,
    Value2,
    DirectSelect,
    MidiFunction,
    MidiChan,
    Config,
    ExpressionPedalA,
    ExpressionPedalB,
    Display1,
    Display2,
    Display3,
    ButtonLeds,
    ButtonPresses,
}

impl InputField {
    pub fn next(&self) -> Self {
        match self {
            InputField::Switch1 => InputField::Switch2,
            InputField::Switch2 => InputField::Switches,
            InputField::Switches => InputField::Select,
            InputField::Select => InputField::Number,
            InputField::Number => InputField::Value1,
            InputField::Value1 => InputField::Value2,
            InputField::Value2 => InputField::DirectSelect,
            InputField::DirectSelect => InputField::MidiFunction,
            InputField::MidiFunction => InputField::MidiChan,
            InputField::MidiChan => InputField::Config,
            InputField::Config => InputField::ExpressionPedalA,
            InputField::ExpressionPedalA => InputField::ExpressionPedalB,
            InputField::ExpressionPedalB => InputField::Display1,
            InputField::Display1 => InputField::Display2,
            InputField::Display2 => InputField::Display3,
            InputField::Display3 => InputField::ButtonLeds,
            InputField::ButtonLeds => InputField::ButtonPresses,
            InputField::ButtonPresses => InputField::Switch1, // Wrap around
        }
    }

    pub fn prev(&self) -> Self {
        match self {
            InputField::Switch1 => InputField::ButtonPresses,
            InputField::Switch2 => InputField::Switch1,
            InputField::Switches => InputField::Switch2,
            InputField::Select => InputField::Switches,
            InputField::Number => InputField::Select,
            InputField::Value1 => InputField::Number,
            InputField::Value2 => InputField::Value1,
            InputField::DirectSelect => InputField::Value2,
            InputField::MidiFunction => InputField::DirectSelect,
            InputField::MidiChan => InputField::MidiFunction,
            InputField::Config => InputField::MidiChan,
            InputField::ExpressionPedalA => InputField::Config,
            InputField::ExpressionPedalB => InputField::ExpressionPedalA,
            InputField::Display1 => InputField::ExpressionPedalB,
            InputField::Display2 => InputField::Display1,
            InputField::Display3 => InputField::Display2,
            InputField::ButtonLeds => InputField::Display3,
            InputField::ButtonPresses => InputField::ButtonLeds,
        }
    }

    pub fn name(&self) -> &str {
        match self {
            InputField::Switch1 => "Switch 1",
            InputField::Switch2 => "Switch 2",
            InputField::Switches => "Switches",
            InputField::Select => "Select",
            InputField::Number => "Number",
            InputField::Value1 => "Value 1",
            InputField::Value2 => "Value 2",
            InputField::DirectSelect => "Direct Select",
            InputField::MidiFunction => "MIDI Function",
            InputField::MidiChan => "MIDI Chan",
            InputField::Config => "Config",
            InputField::ExpressionPedalA => "Expression Pedal A",
            InputField::ExpressionPedalB => "Expression Pedal B",
            InputField::Display1 => "Display 1",
            InputField::Display2 => "Display 2",
            InputField::Display3 => "Display 3",
            InputField::ButtonLeds => "Button LEDs",
            InputField::ButtonPresses => "Button Presses",
        }
    }

    pub fn is_led_field(&self) -> bool {
        matches!(
            self,
            InputField::Switch1
                | InputField::Switch2
                | InputField::Switches
                | InputField::Select
                | InputField::Number
                | InputField::Value1
                | InputField::Value2
                | InputField::DirectSelect
                | InputField::MidiFunction
                | InputField::MidiChan
                | InputField::Config
                | InputField::ExpressionPedalA
                | InputField::ExpressionPedalB
        )
    }

    pub fn is_text_field(&self) -> bool {
        matches!(
            self,
            InputField::Display1
                | InputField::Display2
                | InputField::Display3
                | InputField::ButtonLeds
                | InputField::ButtonPresses
        )
    }
}

pub struct StructuredInputForm {
    pub current_note: StructuredNote,
    pub current_field: InputField,
    pub cursor_position: usize,
}

impl StructuredInputForm {
    pub fn new(register_values: HashMap<String, u8>) -> Self {
        let mut current_note = StructuredNote::default();
        current_note.register_values = register_values;

        Self {
            current_note,
            current_field: InputField::Switch1,
            cursor_position: 0,
        }
    }

    pub fn reset(&mut self, register_values: HashMap<String, u8>) {
        self.current_note = StructuredNote::default();
        self.current_note.register_values = register_values;
        self.current_field = InputField::Switch1;
        self.cursor_position = 0;
    }

    pub fn get_led_value(&self, field: &InputField) -> Option<u8> {
        match field {
            InputField::Switch1 => self.current_note.switch_1,
            InputField::Switch2 => self.current_note.switch_2,
            InputField::Switches => self.current_note.switches,
            InputField::Select => self.current_note.select,
            InputField::Number => self.current_note.number,
            InputField::Value1 => self.current_note.value_1,
            InputField::Value2 => self.current_note.value_2,
            InputField::DirectSelect => self.current_note.direct_select,
            InputField::MidiFunction => self.current_note.midi_function,
            InputField::MidiChan => self.current_note.midi_chan,
            InputField::Config => self.current_note.config,
            InputField::ExpressionPedalA => self.current_note.expression_pedal_a,
            InputField::ExpressionPedalB => self.current_note.expression_pedal_b,
            _ => None,
        }
    }

    pub fn get_text_value(&self, field: &InputField) -> &str {
        match field {
            InputField::Display1 => &self.current_note.display_1,
            InputField::Display2 => &self.current_note.display_2,
            InputField::Display3 => &self.current_note.display_3,
            InputField::ButtonLeds => &self.current_note.button_leds,
            InputField::ButtonPresses => &self.current_note.button_presses,
            _ => "",
        }
    }

    pub fn set_led_value(&mut self, field: &InputField, value: Option<u8>) {
        match field {
            InputField::Switch1 => self.current_note.switch_1 = value,
            InputField::Switch2 => self.current_note.switch_2 = value,
            InputField::Switches => self.current_note.switches = value,
            InputField::Select => self.current_note.select = value,
            InputField::Number => self.current_note.number = value,
            InputField::Value1 => self.current_note.value_1 = value,
            InputField::Value2 => self.current_note.value_2 = value,
            InputField::DirectSelect => self.current_note.direct_select = value,
            InputField::MidiFunction => self.current_note.midi_function = value,
            InputField::MidiChan => self.current_note.midi_chan = value,
            InputField::Config => self.current_note.config = value,
            InputField::ExpressionPedalA => self.current_note.expression_pedal_a = value,
            InputField::ExpressionPedalB => self.current_note.expression_pedal_b = value,
            _ => {}
        }
    }

    pub fn get_text_value_mut(&mut self, field: &InputField) -> Option<&mut String> {
        match field {
            InputField::Display1 => Some(&mut self.current_note.display_1),
            InputField::Display2 => Some(&mut self.current_note.display_2),
            InputField::Display3 => Some(&mut self.current_note.display_3),
            InputField::ButtonLeds => Some(&mut self.current_note.button_leds),
            InputField::ButtonPresses => Some(&mut self.current_note.button_presses),
            _ => None,
        }
    }

    pub fn finalize_note(&mut self) -> StructuredNote {
        self.current_note.description = self.current_note.generate_description();
        self.current_note.clone()
    }
}

pub fn draw_structured_input_form(f: &mut Frame, form: &StructuredInputForm, area: Rect) {
    let mut lines = Vec::new();

    // Helper function to create field line
    let create_field_line = |field: &InputField, form: &StructuredInputForm| -> Line {
        let is_current = form.current_field == *field;
        let prefix = if is_current { "→ " } else { "  " };
        let style = if is_current {
            Style::default()
                .fg(Color::Yellow)
                .add_modifier(Modifier::BOLD)
        } else {
            Style::default()
        };

        if field.is_led_field() {
            let value = form.get_led_value(field);
            let value_str = match value {
                Some(1) => "1",
                Some(0) => "0",
                _ => "─",
            };
            Line::from(vec![Span::styled(
                format!("{}{}: {}", prefix, field.name().to_lowercase(), value_str),
                style,
            )])
        } else {
            let text = form.get_text_value(field);
            let display_text = if is_current {
                let mut display = text.to_string();
                if form.cursor_position <= display.len() {
                    display.insert(form.cursor_position, '│');
                }
                display
            } else if text.is_empty() {
                "".to_string()
            } else {
                text.to_string()
            };
            Line::from(vec![Span::styled(
                format!(
                    "{}{} (list of active segments): {}",
                    prefix,
                    field.name().to_lowercase(),
                    display_text
                ),
                style,
            )])
        }
    };

    // Switch controls
    lines.push(create_field_line(&InputField::Switch1, form));
    lines.push(create_field_line(&InputField::Switch2, form));
    lines.push(Line::from(""));

    // Main LED controls
    lines.push(create_field_line(&InputField::Switches, form));
    lines.push(create_field_line(&InputField::Select, form));
    lines.push(create_field_line(&InputField::Number, form));
    lines.push(create_field_line(&InputField::Value1, form));
    lines.push(create_field_line(&InputField::Value2, form));
    lines.push(Line::from(""));

    // Additional controls
    lines.push(create_field_line(&InputField::DirectSelect, form));
    lines.push(create_field_line(&InputField::MidiFunction, form));
    lines.push(create_field_line(&InputField::MidiChan, form));
    lines.push(create_field_line(&InputField::Config, form));
    lines.push(Line::from(""));

    // Expression pedals
    lines.push(create_field_line(&InputField::ExpressionPedalA, form));
    lines.push(create_field_line(&InputField::ExpressionPedalB, form));
    lines.push(Line::from(""));

    // Display segments
    lines.push(create_field_line(&InputField::Display1, form));
    lines.push(create_field_line(&InputField::Display2, form));
    lines.push(create_field_line(&InputField::Display3, form));
    lines.push(Line::from(""));

    // Button controls
    lines.push(create_field_line(&InputField::ButtonLeds, form));
    lines.push(create_field_line(&InputField::ButtonPresses, form));

    let block = Paragraph::new(lines).block(
        Block::default()
            .borders(Borders::ALL)
            .title("Structured Note Input"),
    );
    f.render_widget(block, area);
}
