use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StructuredNote {
    pub description: String,
    pub register_values: HashMap<String, u8>,

    // LED states (0/1)
    pub switch_1: Option<u8>,
    pub switch_2: Option<u8>,
    pub switches: Option<u8>,
    pub select: Option<u8>,
    pub number: Option<u8>,
    pub value_1: Option<u8>,
    pub value_2: Option<u8>,
    pub direct_select: Option<u8>,
    pub midi_function: Option<u8>,
    pub midi_chan: Option<u8>,
    pub config: Option<u8>,
    pub expression_pedal_a: Option<u8>,
    pub expression_pedal_b: Option<u8>,

    // Display segments (strings of active segments)
    pub display_1: String,
    pub display_2: String,
    pub display_3: String,

    // Button states (strings of active button numbers)
    pub button_leds: String,
    pub button_presses: String,
}

impl Default for StructuredNote {
    fn default() -> Self {
        Self {
            description: String::new(),
            register_values: HashMap::new(),
            switch_1: None,
            switch_2: None,
            switches: None,
            select: None,
            number: None,
            value_1: None,
            value_2: None,
            direct_select: None,
            midi_function: None,
            midi_chan: None,
            config: None,
            expression_pedal_a: None,
            expression_pedal_b: None,
            display_1: String::new(),
            display_2: String::new(),
            display_3: String::new(),
            button_leds: String::new(),
            button_presses: String::new(),
        }
    }
}

// Legacy format for file I/O compatibility
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegisterNote {
    pub description: String,
    pub register_values: Option<HashMap<String, u8>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MappingData {
    pub notes: Vec<RegisterNote>,
    pub register_values: HashMap<String, u8>,
}

impl Default for MappingData {
    fn default() -> Self {
        let mut register_values = HashMap::new();
        register_values.insert("IC03".to_string(), 255);
        register_values.insert("IC10".to_string(), 255);
        register_values.insert("IC11".to_string(), 8);

        Self {
            notes: Vec::new(),
            register_values,
        }
    }
}

impl StructuredNote {
    pub fn is_empty(&self) -> bool {
        self.switch_1.is_none()
            && self.switch_2.is_none()
            && self.display_1.is_empty()
            && self.display_2.is_empty()
            && self.display_3.is_empty()
            && self.button_leds.is_empty()
            && self.button_presses.is_empty()
    }

    pub fn generate_description(&self) -> String {
        let format_list = |text: &str| -> String {
            if text.is_empty() {
                String::new()
            } else {
                text.chars()
                    .map(|c| c.to_string())
                    .collect::<Vec<_>>()
                    .join(", ")
            }
        };

        format!(
            "{}{} {}{}{}{}{} {}{}{}{} {}{} [{}] [{}] [{}] [{}] [{}]",
            self.switch_1.unwrap_or(0),
            self.switch_2.unwrap_or(0),
            self.switches.unwrap_or(0),
            self.select.unwrap_or(0),
            self.number.unwrap_or(0),
            self.value_1.unwrap_or(0),
            self.value_2.unwrap_or(0),
            self.direct_select.unwrap_or(0),
            self.midi_function.unwrap_or(0),
            self.midi_chan.unwrap_or(0),
            self.config.unwrap_or(0),
            self.expression_pedal_a.unwrap_or(0),
            self.expression_pedal_b.unwrap_or(0),
            format_list(&self.display_1),
            format_list(&self.display_2),
            format_list(&self.display_3),
            format_list(&self.button_leds),
            format_list(&self.button_presses)
        )
    }

    pub fn to_register_note(&self) -> RegisterNote {
        RegisterNote {
            description: self.generate_description(),
            register_values: Some(self.register_values.clone()),
        }
    }

    pub fn from_register_note(note: &RegisterNote) -> Option<Self> {
        // Parse the description to extract structured data
        // Format: "01 10000 1101 00 [B, C, E, F, G, P] [A, B, C, P] [A, B, C, P] [3, 4, 5, 6, 7, 8] []"
        let description = &note.description;
        let mut structured_note = StructuredNote {
            description: description.clone(),
            register_values: note.register_values.clone().unwrap_or_default(),
            ..Default::default()
        };

        // Split the description into parts
        let parts: Vec<&str> = description.split_whitespace().collect();

        if parts.len() >= 4 {
            // Parse LED states from first 4 parts
            // Part 0: switch1+switch2 (e.g., "01")
            if let Some(switches) = parts.get(0) {
                if switches.len() >= 2 {
                    if let Some(c) = switches.chars().nth(0) {
                        structured_note.switch_1 = c.to_digit(10).map(|d| d as u8);
                    }
                    if let Some(c) = switches.chars().nth(1) {
                        structured_note.switch_2 = c.to_digit(10).map(|d| d as u8);
                    }
                }
            }

            // Part 1: switches+select+number+value1+value2 (e.g., "10000")
            if let Some(middle_bits) = parts.get(1) {
                let chars: Vec<char> = middle_bits.chars().collect();
                if chars.len() >= 5 {
                    structured_note.switches = chars[0].to_digit(10).map(|d| d as u8);
                    structured_note.select = chars[1].to_digit(10).map(|d| d as u8);
                    structured_note.number = chars[2].to_digit(10).map(|d| d as u8);
                    structured_note.value_1 = chars[3].to_digit(10).map(|d| d as u8);
                    structured_note.value_2 = chars[4].to_digit(10).map(|d| d as u8);
                }
            }

            // Part 2: direct_select+midi_function+midi_chan+config (e.g., "1101")
            if let Some(last_bits) = parts.get(2) {
                let chars: Vec<char> = last_bits.chars().collect();
                if chars.len() >= 4 {
                    structured_note.direct_select = chars[0].to_digit(10).map(|d| d as u8);
                    structured_note.midi_function = chars[1].to_digit(10).map(|d| d as u8);
                    structured_note.midi_chan = chars[2].to_digit(10).map(|d| d as u8);
                    structured_note.config = chars[3].to_digit(10).map(|d| d as u8);
                }
            }

            // Part 3: expression_pedal_a+expression_pedal_b (e.g., "00")
            if let Some(pedals) = parts.get(3) {
                let chars: Vec<char> = pedals.chars().collect();
                if chars.len() >= 2 {
                    structured_note.expression_pedal_a = chars[0].to_digit(10).map(|d| d as u8);
                    structured_note.expression_pedal_b = chars[1].to_digit(10).map(|d| d as u8);
                }
            }
        }

        // Parse the bracketed sections for text fields
        let bracket_sections = Self::extract_bracket_sections(description);
        if bracket_sections.len() >= 5 {
            structured_note.display_1 = bracket_sections[0].clone();
            structured_note.display_2 = bracket_sections[1].clone();
            structured_note.display_3 = bracket_sections[2].clone();
            structured_note.button_leds = bracket_sections[3].clone();
            structured_note.button_presses = bracket_sections[4].clone();
        }

        Some(structured_note)
    }

    fn extract_bracket_sections(text: &str) -> Vec<String> {
        let mut sections = Vec::new();
        let mut current_section = String::new();
        let mut inside_brackets = false;

        for ch in text.chars() {
            match ch {
                '[' => {
                    inside_brackets = true;
                    current_section.clear();
                }
                ']' => {
                    if inside_brackets {
                        // Convert comma-separated to no commas for storage
                        let clean_section = current_section
                            .split(", ")
                            .map(|s| s.trim())
                            .filter(|s| !s.is_empty())
                            .collect::<Vec<_>>()
                            .join("");
                        sections.push(clean_section);
                        inside_brackets = false;
                    }
                }
                _ => {
                    if inside_brackets {
                        current_section.push(ch);
                    }
                }
            }
        }

        sections
    }
}

impl MappingData {
    pub fn from_structured_notes(
        notes: Vec<StructuredNote>,
        register_values: HashMap<String, u8>,
    ) -> Self {
        let legacy_notes = notes.iter().map(|n| n.to_register_note()).collect();
        Self {
            notes: legacy_notes,
            register_values,
        }
    }

    pub fn to_structured_notes(&self) -> Vec<StructuredNote> {
        self.notes
            .iter()
            .filter_map(StructuredNote::from_register_note)
            .collect()
    }
}
