use crate::*;

#[derive(Clone, Debug, PartialEq, strum::Display, strum::EnumString)]
pub enum TrackState {
    Empty,
    Idle,
    Playing,
    Recording,
}

#[derive(Debug, Clone)]
pub struct Track {
    pub state: TrackState,
    pub volume: f32,
}

#[derive(Debug, Clone)]
pub struct Column<const ROWS: usize> {
    pub tracks: [Track; ROWS],
    pub beat_count: usize,   // total beats in column (0 = no beats set)
    pub current_beat: usize, // current beat position (0-based internally)
}

#[derive(Debug, Clone)]
pub struct State<const COLS: usize, const ROWS: usize> {
    pub selected_column: usize, // 0-based (converted to 1-based for OSC)
    pub selected_row: usize,    // 0-based (converted to 1-based for OSC)
    pub columns: [Column<ROWS>; COLS],
    pub metronome_position: f32, // 0.0 - 1.0 position within current beat
    pub metronome_timestamp: std::time::Instant, // When position was last updated
    pub tempo: f32,              // BPM
}

impl<const ROWS: usize> Column<ROWS> {
    pub fn new() -> Self {
        Self {
            tracks: std::array::from_fn(|_| Track {
                state: TrackState::Empty,
                volume: 1.0,
            }),
            beat_count: 0,
            current_beat: 0,
        }
    }
}

impl<const COLS: usize, const ROWS: usize> State<COLS, ROWS> {
    pub fn new(tempo: f32) -> Self {
        Self {
            selected_column: 0,
            selected_row: 0,
            columns: std::array::from_fn(|_| Column::new()),
            metronome_position: 0.0,
            metronome_timestamp: std::time::Instant::now(),
            tempo,
        }
    }

    pub fn update(&mut self, message: &Message) {
        match message {
            Message::TrackStateChanged { column, row, state } => {
                if *column < COLS && *row < ROWS {
                    self.columns[*column].tracks[*row].state = state.clone();
                }
            }
            Message::TrackVolumeChanged {
                column,
                row,
                volume,
            } => {
                if *column < COLS && *row < ROWS {
                    self.columns[*column].tracks[*row].volume = *volume;
                }
            }
            Message::SelectedColumnChanged { column } => {
                if *column < COLS {
                    self.selected_column = *column;
                }
            }
            Message::SelectedRowChanged { row } => {
                if *row < ROWS {
                    self.selected_row = *row;
                }
            }
            Message::MetronomePosition { position } => {
                self.set_metronome_position(*position);
            }
            Message::Tempo { bpm } => {
                self.set_tempo(*bpm);
            }
            Message::ColumnBeatsChanged { column, beats } => {
                self.set_column_beats(*column, *beats);
            }
            Message::ColumnBeatChanged { column, beat } => {
                self.set_column_beat(*column, *beat);
            }
        }
    }

    pub fn create_state_dump(&self) -> Vec<Message> {
        let mut messages = Vec::new();

        // Send tempo
        messages.push(Message::Tempo { bpm: self.tempo });

        // Send current selections
        messages.push(Message::SelectedColumnChanged {
            column: self.selected_column,
        });
        messages.push(Message::SelectedRowChanged {
            row: self.selected_row,
        });

        // Send column beat information and cell states/volumes
        for (column, column_data) in self.columns.iter().enumerate() {
            // Send column beat info
            messages.push(Message::ColumnBeatsChanged {
                column,
                beats: column_data.beat_count,
            });
            messages.push(Message::ColumnBeatChanged {
                column,
                beat: column_data.current_beat,
            });

            // Send all cell states and volumes for this column
            for (row, track) in column_data.tracks.iter().enumerate() {
                messages.push(Message::TrackStateChanged {
                    column,
                    row,
                    state: track.state.clone(),
                });
                messages.push(Message::TrackVolumeChanged {
                    column,
                    row,
                    volume: track.volume,
                });
            }
        }

        messages
    }

    pub fn set_track_state(&mut self, column: usize, row: usize, state: TrackState) {
        if column < COLS && row < ROWS {
            self.columns[column].tracks[row].state = state;
        }
    }

    pub fn set_selected_column(&mut self, column: usize) {
        if column < COLS {
            self.selected_column = column;
        }
    }

    pub fn set_selected_row(&mut self, row: usize) {
        if row < ROWS {
            self.selected_row = row;
        }
    }

    pub fn set_track_volume(&mut self, column: usize, row: usize, volume: f32) {
        if column < COLS && row < ROWS {
            self.columns[column].tracks[row].volume = volume;
        }
    }

    pub fn set_metronome_position(&mut self, position: f32) {
        self.metronome_position = position;
        self.metronome_timestamp = std::time::Instant::now();
    }

    pub fn set_tempo(&mut self, bpm: f32) {
        self.tempo = bpm;
    }

    pub fn set_column_beats(&mut self, column: usize, beats: usize) {
        if column < COLS {
            self.columns[column].beat_count = beats;
        }
    }

    pub fn set_column_beat(&mut self, column: usize, beat: usize) {
        if column < COLS {
            self.columns[column].current_beat = beat;
        }
    }
}
