use crate::{message::Message, state::State};
use iced::{
    Alignment, Border, Color, Element, Length,
    widget::{Id, button, column, container, row, text, text_input},
};

#[derive(Debug)]
pub struct TrackMarkerView {
    state: State,
}

impl TrackMarkerView {
    pub fn new(state: State) -> Self {
        Self { state }
    }

    pub fn name_input_id() -> Id {
        Id::new("track-marker-name-input")
    }

    pub fn update(&mut self, message: &Message) {
        if let Message::TrackMarkerNameInput(input) = message
            && let Some(dialog) = &mut self.state.blocking_write().track_marker_dialog
        {
            dialog.name = input.clone();
        }
    }

    pub fn view(&self) -> Element<'_, Message> {
        let state = self.state.blocking_read();
        let Some(dialog) = &state.track_marker_dialog else {
            return container("").into();
        };

        let can_confirm = !dialog.name.trim().is_empty();
        let is_rename = dialog.marker_index.is_some();
        let confirm_button = if can_confirm {
            button(if is_rename { "Rename" } else { "Create" })
                .on_press(Message::TrackMarkerNameConfirm)
        } else {
            button(if is_rename { "Rename" } else { "Create" })
        };

        container(
            column![
                text(if is_rename {
                    "Edit Marker"
                } else {
                    "Add Marker"
                }),
                text(format!("Track: {}", dialog.track_name)).size(11),
                text_input("Enter marker name", &dialog.name)
                    .id(Self::name_input_id())
                    .on_input(Message::TrackMarkerNameInput)
                    .on_submit(Message::TrackMarkerNameConfirm)
                    .width(Length::Fill),
                row![
                    confirm_button,
                    button("Cancel")
                        .on_press(Message::TrackMarkerNameCancel)
                        .style(button::secondary)
                ]
                .spacing(10),
            ]
            .align_x(Alignment::Start)
            .spacing(10),
        )
        .style(|_theme| container::Style {
            border: Border {
                color: Color::from_rgba(0.34, 0.42, 0.56, 0.72),
                width: 1.0,
                ..Border::default()
            },
            ..crate::style::app_background()
        })
        .padding(12)
        .width(Length::Fixed(320.0))
        .height(Length::Fill)
        .into()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::Arc;
    use tokio::sync::RwLock;

    #[test]
    fn update_sets_track_marker_name_when_dialog_is_open() {
        let state = Arc::new(RwLock::new(crate::state::StateData::default()));
        state.blocking_write().track_marker_dialog = Some(crate::state::TrackMarkerDialog {
            track_name: "Lead".to_string(),
            sample: 128,
            marker_index: None,
            name: "Verse".to_string(),
        });
        let mut view = TrackMarkerView::new(state.clone());

        view.update(&Message::TrackMarkerNameInput("Chorus".to_string()));

        assert_eq!(
            state
                .blocking_read()
                .track_marker_dialog
                .as_ref()
                .map(|dialog| dialog.name.as_str()),
            Some("Chorus")
        );
    }

    #[test]
    fn update_ignores_non_matching_messages() {
        let state = Arc::new(RwLock::new(crate::state::StateData::default()));
        state.blocking_write().track_marker_dialog = Some(crate::state::TrackMarkerDialog {
            track_name: "Lead".to_string(),
            sample: 128,
            marker_index: None,
            name: "Verse".to_string(),
        });
        let mut view = TrackMarkerView::new(state.clone());

        view.update(&Message::Cancel);

        assert_eq!(
            state
                .blocking_read()
                .track_marker_dialog
                .as_ref()
                .map(|dialog| dialog.name.as_str()),
            Some("Verse")
        );
    }

    #[test]
    fn new_creates_view() {
        let state = crate::state::State::default();
        let view = TrackMarkerView::new(state);
        let _ = &view;
    }

    #[test]
    fn name_input_id_returns_expected_id() {
        let id = TrackMarkerView::name_input_id();
        let _ = &id;
    }

    #[test]
    fn view_returns_empty_when_no_dialog() {
        let state = Arc::new(RwLock::new(crate::state::StateData::default()));
        let view = TrackMarkerView::new(state);
        let element = view.view();
        let _ = &element;
    }
}
