//! Combobox tests

#![allow(unused_imports)]

use revue::layout::Rect;
use revue::prelude::RenderContext;
use revue::render::Buffer;
use revue::style::Color;
use revue::utils::FilterMode;
use revue::widget::traits::View;
use revue::widget::input_widgets::combobox::{combobox, ComboOption, Combobox};
use revue::event::Key;

#[test]
fn test_combobox_new() {
    let cb = Combobox::new();
    assert!(cb.input().is_empty());
    assert!(!cb.is_open());
    assert_eq!(cb.option_count(), 0);
}

#[test]
fn test_combobox_options() {
    let cb = Combobox::new().options(vec!["Apple", "Banana", "Cherry"]);
    assert_eq!(cb.option_count(), 3);
    assert_eq!(cb.filtered_count(), 3);
}

#[test]
fn test_combobox_options_with() {
    let cb = Combobox::new().options_with(vec![
        ComboOption::new("Apple").value("apple"),
        ComboOption::new("Banana").disabled(true),
    ]);
    assert_eq!(cb.option_count(), 2);
}

#[test]
fn test_combobox_filtering_fuzzy() {
    let mut cb = Combobox::new()
        .options(vec!["Hello World", "Help Me", "Goodbye"])
        .filter_mode(FilterMode::Fuzzy);

    cb.set_input("hw");
    assert_eq!(cb.filtered_count(), 1);
}

#[test]
fn test_combobox_filtering_prefix() {
    let mut cb = Combobox::new()
        .options(vec!["Hello", "Help", "World"])
        .filter_mode(FilterMode::Prefix);

    cb.set_input("Hel");
    assert_eq!(cb.filtered_count(), 2);
}

#[test]
fn test_combobox_filtering_contains() {
    let mut cb = Combobox::new()
        .options(vec!["Hello", "Shell", "World"])
        .filter_mode(FilterMode::Contains);

    cb.set_input("ell");
    assert_eq!(cb.filtered_count(), 2);
}

#[test]
fn test_combobox_filtering_exact() {
    let mut cb = Combobox::new()
        .options(vec!["Hello", "hello", "HELLO"])
        .filter_mode(FilterMode::Exact);

    cb.set_input("hello");
    assert_eq!(cb.filtered_count(), 3);
}

#[test]
fn test_combobox_navigation() {
    let mut cb = Combobox::new().options(vec!["A", "B", "C"]);

    cb.open_dropdown();
    assert!(cb.is_open());

    cb.select_next();
    assert_eq!(cb.selected_idx, 1);

    cb.select_next();
    assert_eq!(cb.selected_idx, 2);

    cb.select_next();
    assert_eq!(cb.selected_idx, 0);

    cb.select_prev();
    assert_eq!(cb.selected_idx, 2);

    cb.select_first();
    assert_eq!(cb.selected_idx, 0);

    cb.select_last();
    assert_eq!(cb.selected_idx, 2);
}

#[test]
fn test_combobox_select_current() {
    let mut cb = Combobox::new().options(vec!["Apple", "Banana"]);

    cb.open_dropdown();
    cb.select_next();
    cb.select_current();

    assert_eq!(cb.input(), "Banana");
    assert!(!cb.is_open());
}

#[test]
fn test_combobox_multi_select() {
    let mut cb = Combobox::new()
        .options(vec!["A", "B", "C"])
        .multi_select(true);

    cb.open_dropdown();
    cb.select_current();
    assert!(cb.is_selected("A"));
    assert!(cb.is_open());

    cb.select_next();
    cb.select_current();
    assert!(cb.is_selected("A"));
    assert!(cb.is_selected("B"));

    cb.select_first();
    cb.select_current();
    assert!(!cb.is_selected("A"));
    assert!(cb.is_selected("B"));
}

#[test]
fn test_combobox_allow_custom() {
    let cb = Combobox::new()
        .options(vec!["Apple", "Banana"])
        .allow_custom(true)
        .value("Custom Value");

    assert_eq!(cb.selected_value(), Some("Custom Value"));
}

#[test]
fn test_combobox_disabled_option() {
    let mut cb = Combobox::new().options_with(vec![
        ComboOption::new("Enabled"),
        ComboOption::new("Disabled").disabled(true),
    ]);

    cb.open_dropdown();
    cb.select_next();
    let selected = cb.select_current();
    assert!(!selected);
}

#[test]
fn test_combobox_input_manipulation() {
    let mut cb = Combobox::new();

    cb.insert_char('H');
    cb.insert_char('i');
    assert_eq!(cb.input(), "Hi");
    assert_eq!(cb.cursor, 2);

    cb.delete_backward();
    assert_eq!(cb.input(), "H");
    assert_eq!(cb.cursor, 1);

    cb.move_left();
    assert_eq!(cb.cursor, 0);

    cb.insert_char('O');
    assert_eq!(cb.input(), "OH");

    cb.move_to_end();
    assert_eq!(cb.cursor, 2);

    cb.move_to_start();
    assert_eq!(cb.cursor, 0);
}

#[test]
fn test_combobox_handle_key() {
    let mut cb = Combobox::new().options(vec!["Apple", "Banana"]);

    cb.handle_key(&Key::Char('a'));
    assert_eq!(cb.input(), "a");
    assert!(cb.is_open());

    cb.handle_key(&Key::Down);
    assert_eq!(cb.selected_idx, 1);

    cb.handle_key(&Key::Enter);
    assert!(!cb.is_open());

    cb.open_dropdown();
    cb.handle_key(&Key::Escape);
    assert!(!cb.is_open());
}

#[test]
fn test_combobox_loading_state() {
    let cb = Combobox::new().loading(true).loading_text("Fetching...");

    assert!(cb.is_loading());
}

#[test]
fn test_combobox_render_closed() {
    let mut buffer = Buffer::new(30, 10);
    let area = Rect::new(0, 0, 30, 10);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let cb = Combobox::new()
        .options(vec!["Option 1", "Option 2"])
        .placeholder("Select...");

    cb.render(&mut ctx);
}

#[test]
fn test_combobox_render_open() {
    let mut buffer = Buffer::new(30, 10);
    let area = Rect::new(0, 0, 30, 10);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let mut cb = Combobox::new().options(vec!["Apple", "Banana"]);
    cb.open_dropdown();

    cb.render(&mut ctx);
}

#[test]
fn test_combobox_helper() {
    let cb = combobox().option("Test").placeholder("Pick one");
    assert_eq!(cb.option_count(), 1);
}

#[test]
fn test_combobox_clear_input() {
    let mut cb = Combobox::new().options(vec!["A", "B"]).value("test");

    assert_eq!(cb.input(), "test");
    cb.clear_input();
    assert!(cb.input().is_empty());
}

#[test]
fn test_combobox_scroll() {
    let mut cb = Combobox::new()
        .options(vec!["A", "B", "C", "D", "E", "F", "G", "H"])
        .max_visible(3);

    cb.open_dropdown();

    for _ in 0..7 {
        cb.select_next();
    }

    assert!(cb.scroll_offset > 0);
}

#[test]
fn test_combo_option_builder() {
    let opt = ComboOption::new("Label")
        .value("value")
        .disabled(true)
        .group("Category");

    assert_eq!(opt.label, "Label");
    assert_eq!(opt.get_value(), "value");
    assert!(opt.disabled);
    assert_eq!(opt.group, Some("Category".to_string()));
}

#[test]
fn test_combobox_empty_filter() {
    let mut cb = Combobox::new().options(vec!["Apple", "Banana"]);

    cb.set_input("xyz");
    assert_eq!(cb.filtered_count(), 0);
}

#[test]
fn test_filter_mode_default() {
    assert_eq!(FilterMode::default(), FilterMode::Fuzzy);
}

#[test]
fn test_combobox_builder_methods() {
    let cb = Combobox::new()
        .loading_text("Please wait...")
        .empty_text("Nothing found")
        .width(50)
        .input_style(Color::WHITE, Color::BLACK)
        .selected_style(Color::BLACK, Color::WHITE)
        .highlight_fg(Color::YELLOW)
        .fg(Color::WHITE)
        .bg(Color::BLACK);

    assert_eq!(cb.loading_text, "Please wait...");
    assert_eq!(cb.empty_text, "Nothing found");
    assert_eq!(cb.width, Some(50));
}

#[test]
fn test_combobox_selected_values() {
    let cb = Combobox::new()
        .multi_select(true)
        .selected_values(vec!["A".to_string(), "B".to_string()]);

    assert_eq!(cb.selected_values_ref(), &["A", "B"]);
}

#[test]
fn test_combobox_delete_forward() {
    let mut cb = Combobox::new().value("Hello");
    cb.move_to_start();
    cb.delete_forward();
    assert_eq!(cb.input(), "ello");
}

#[test]
fn test_combobox_delete_forward_at_end() {
    let mut cb = Combobox::new().value("Hi");
    cb.delete_forward();
    assert_eq!(cb.input(), "Hi");
}

#[test]
fn test_combobox_delete_backward_at_start() {
    let mut cb = Combobox::new().value("Hi");
    cb.move_to_start();
    cb.delete_backward();
    assert_eq!(cb.input(), "Hi");
}

#[test]
fn test_combobox_move_right_at_end() {
    let mut cb = Combobox::new().value("Hi");
    cb.move_right();
    assert_eq!(cb.cursor, 2);
}

#[test]
fn test_combobox_move_left_at_start() {
    let mut cb = Combobox::new().value("Hi");
    cb.move_to_start();
    cb.move_left();
    assert_eq!(cb.cursor, 0);
}

#[test]
fn test_combobox_toggle_dropdown() {
    let mut cb = Combobox::new().options(vec!["A", "B"]);
    assert!(!cb.is_open());

    cb.toggle_dropdown();
    assert!(cb.is_open());

    cb.toggle_dropdown();
    assert!(!cb.is_open());
}

#[test]
fn test_combobox_handle_key_down_when_closed() {
    let mut cb = Combobox::new().options(vec!["Apple", "Banana"]);
    assert!(!cb.is_open());

    cb.handle_key(&Key::Down);
    assert!(cb.is_open());
}

#[test]
fn test_combobox_handle_key_tab_completion() {
    let mut cb = Combobox::new().options(vec!["Apple", "Banana"]);
    cb.open_dropdown();
    cb.handle_key(&Key::Tab);

    assert_eq!(cb.input(), "Apple");
}

#[test]
fn test_combobox_handle_key_delete() {
    let mut cb = Combobox::new().value("Hello");
    cb.move_to_start();
    cb.handle_key(&Key::Delete);
    assert_eq!(cb.input(), "ello");
}

#[test]
fn test_combobox_handle_key_home_end() {
    let mut cb = Combobox::new().value("Hello");
    cb.handle_key(&Key::Home);
    assert_eq!(cb.cursor, 0);

    cb.handle_key(&Key::End);
    assert_eq!(cb.cursor, 5);
}

#[test]
fn test_combobox_handle_key_left_right() {
    let mut cb = Combobox::new().value("Hi");
    cb.handle_key(&Key::Left);
    assert_eq!(cb.cursor, 1);

    cb.handle_key(&Key::Right);
    assert_eq!(cb.cursor, 2);
}

#[test]
fn test_combobox_handle_key_up_when_open() {
    let mut cb = Combobox::new().options(vec!["A", "B", "C"]);
    cb.open_dropdown();
    cb.select_next();
    cb.handle_key(&Key::Up);
    assert_eq!(cb.selected_idx, 0);
}

#[test]
fn test_combobox_handle_key_unhandled() {
    let mut cb = Combobox::new();
    let handled = cb.handle_key(&Key::F(1));
    assert!(!handled);
}

#[test]
fn test_combobox_selected_value_from_option() {
    let cb = Combobox::new()
        .options(vec!["Apple", "Banana"])
        .value("Apple");

    assert_eq!(cb.selected_value(), Some("Apple"));
}

#[test]
fn test_combobox_selected_value_multi_select_returns_none() {
    let cb = Combobox::new()
        .options(vec!["A", "B"])
        .multi_select(true)
        .value("A");

    assert_eq!(cb.selected_value(), None);
}

#[test]
fn test_combobox_selected_value_no_match_no_custom() {
    let cb = Combobox::new()
        .options(vec!["Apple", "Banana"])
        .value("Custom");

    assert_eq!(cb.selected_value(), None);
}

#[test]
fn test_combobox_get_match_non_fuzzy() {
    let cb = Combobox::new()
        .options(vec!["Apple"])
        .filter_mode(FilterMode::Prefix)
        .value("App");

    assert!(cb.get_match("Apple").is_none());
}

#[test]
fn test_combobox_select_on_empty_filtered() {
    let mut cb = Combobox::new().options(vec!["Apple"]);
    cb.set_input("xyz");
    let selected = cb.select_current();
    assert!(!selected);
}

#[test]
fn test_combobox_navigation_empty_options() {
    let mut cb = Combobox::new();
    cb.select_next();
    cb.select_prev();
    cb.select_last();
    assert_eq!(cb.selected_idx, 0);
}

#[test]
fn test_combobox_render_loading_state() {
    let mut buffer = Buffer::new(30, 10);
    let area = Rect::new(0, 0, 30, 10);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let mut cb = Combobox::new()
        .options(vec!["A", "B"])
        .loading(true)
        .loading_text("Loading...")
        .width(30);
    cb.open_dropdown();

    cb.render(&mut ctx);

    assert_eq!(buffer.get(28, 0).unwrap().symbol, '⟳');
}

#[test]
fn test_combobox_render_empty_state() {
    let mut buffer = Buffer::new(30, 10);
    let area = Rect::new(0, 0, 30, 10);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let mut cb = Combobox::new()
        .options(vec!["Apple", "Banana"])
        .empty_text("No results");
    cb.set_input("xyz");
    cb.open_dropdown();

    cb.render(&mut ctx);
}

#[test]
fn test_combobox_render_with_scroll_indicators() {
    let mut buffer = Buffer::new(30, 5);
    let area = Rect::new(0, 0, 30, 5);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let mut cb = Combobox::new()
        .options(vec!["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"])
        .max_visible(3);
    cb.open_dropdown();

    for _ in 0..5 {
        cb.select_next();
    }

    cb.render(&mut ctx);
}

#[test]
fn test_combobox_render_multi_select() {
    let mut buffer = Buffer::new(30, 10);
    let area = Rect::new(0, 0, 30, 10);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let mut cb = Combobox::new()
        .options(vec!["A", "B", "C"])
        .multi_select(true);
    cb.open_dropdown();
    cb.select_current();

    cb.render(&mut ctx);
}

#[test]
fn test_combobox_render_with_input() {
    let mut buffer = Buffer::new(30, 10);
    let area = Rect::new(0, 0, 30, 10);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let mut cb = Combobox::new().options(vec!["Apple", "Banana"]);
    cb.set_input("App");
    cb.open_dropdown();

    cb.render(&mut ctx);
}

#[test]
fn test_combobox_render_disabled_option() {
    let mut buffer = Buffer::new(30, 10);
    let area = Rect::new(0, 0, 30, 10);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let mut cb = Combobox::new().options_with(vec![
        ComboOption::new("Enabled"),
        ComboOption::new("Disabled").disabled(true),
    ]);
    cb.open_dropdown();

    cb.render(&mut ctx);
}

#[test]
fn test_combobox_render_small_area() {
    let mut buffer = Buffer::new(2, 1);
    let area = Rect::new(0, 0, 2, 1);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let cb = Combobox::new().options(vec!["A"]);
    cb.render(&mut ctx);
}

#[test]
fn test_combobox_render_height_one() {
    let mut buffer = Buffer::new(30, 1);
    let area = Rect::new(0, 0, 30, 1);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let mut cb = Combobox::new().options(vec!["A", "B"]);
    cb.open_dropdown();
    cb.render(&mut ctx);
}

#[test]
fn test_combobox_default() {
    let cb = Combobox::default();
    assert!(cb.input().is_empty());
    assert!(!cb.is_open());
}

#[test]
fn test_combo_option_from_string() {
    let opt: ComboOption = "Test".into();
    assert_eq!(opt.label, "Test");
    assert_eq!(opt.get_value(), "Test");
}

#[test]
fn test_combobox_ensure_visible_scroll_up() {
    let mut cb = Combobox::new()
        .options(vec!["A", "B", "C", "D", "E", "F", "G", "H"])
        .max_visible(3);

    cb.open_dropdown();

    for _ in 0..7 {
        cb.select_next();
    }
    assert!(cb.scroll_offset > 0);

    for _ in 0..7 {
        cb.select_prev();
    }
    assert_eq!(cb.scroll_offset, 0);
}

#[test]
fn test_combobox_handle_key_enter_not_open_allow_custom() {
    let mut cb = Combobox::new()
        .options(vec!["A", "B"])
        .allow_custom(true)
        .value("Custom");

    let handled = cb.handle_key(&Key::Enter);
    assert!(handled);
}

#[test]
fn test_combobox_option_with_separate_value() {
    let mut cb = Combobox::new()
        .options_with(vec![ComboOption::new("Display Name").value("actual_value")]);

    cb.open_dropdown();
    cb.select_current();

    assert_eq!(cb.input(), "Display Name");
}

#[test]
fn test_combobox_cursor_render_boundary() {
    let mut buffer = Buffer::new(10, 5);
    let area = Rect::new(0, 0, 10, 5);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let cb = Combobox::new().value("Very long text that exceeds width");
    cb.render(&mut ctx);
}

#[test]
fn test_combobox_render_highlighted_option() {
    let mut buffer = Buffer::new(30, 10);
    let area = Rect::new(0, 0, 30, 10);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let mut cb = Combobox::new().options(vec!["Apple", "Banana", "Cherry"]);
    cb.open_dropdown();
    cb.select_next();

    cb.render(&mut ctx);
}

#[test]
fn test_combobox_open_dropdown() {
    let mut cb = Combobox::new().options(vec!["A", "B"]);
    assert!(!cb.is_open());

    cb.open_dropdown();
    assert!(cb.is_open());
    assert_eq!(cb.selected_idx, 0);
    assert_eq!(cb.scroll_offset, 0);
}

#[test]
fn test_combobox_close_dropdown() {
    let mut cb = Combobox::new().options(vec!["A", "B"]);
    cb.open_dropdown();
    cb.select_next();
    assert!(cb.is_open());
    assert_eq!(cb.selected_idx, 1);

    cb.close_dropdown();
    assert!(!cb.is_open());
    assert_eq!(cb.selected_idx, 0);
    assert_eq!(cb.scroll_offset, 0);
}

#[test]
fn test_combobox_select_current_empty_filtered() {
    let mut cb = Combobox::new().options(vec!["Apple"]);
    cb.set_input("xyz");
    let selected = cb.select_current();
    assert!(!selected);
}

#[test]
fn test_combobox_select_current_disabled() {
    let mut cb = Combobox::new().options_with(vec![
        ComboOption::new("Enabled"),
        ComboOption::new("Disabled").disabled(true),
    ]);

    cb.open_dropdown();
    cb.select_next();
    let selected = cb.select_current();
    assert!(!selected);
}

#[test]
fn test_combobox_select_next_empty_options() {
    let mut cb = Combobox::new();
    cb.select_next();
    assert_eq!(cb.selected_idx, 0);
}

#[test]
fn test_combobox_select_prev_empty_options() {
    let mut cb = Combobox::new();
    cb.select_prev();
    assert_eq!(cb.selected_idx, 0);
}

#[test]
fn test_combobox_select_last_empty_options() {
    let mut cb = Combobox::new();
    cb.select_last();
    assert_eq!(cb.selected_idx, 0);
}

#[test]
fn test_combobox_select_first_resets_scroll() {
    let mut cb = Combobox::new()
        .options(vec!["A", "B", "C", "D", "E", "F", "G", "H"])
        .max_visible(3);

    cb.open_dropdown();
    for _ in 0..5 {
        cb.select_next();
    }
    assert!(cb.scroll_offset > 0);

    cb.select_first();
    assert_eq!(cb.selected_idx, 0);
    assert_eq!(cb.scroll_offset, 0);
}

#[test]
fn test_combobox_ensure_visible_above_viewport() {
    let mut cb = Combobox::new()
        .options(vec!["A", "B", "C", "D", "E", "F", "G", "H"])
        .max_visible(3);

    cb.open_dropdown();
    for _ in 0..5 {
        cb.select_next();
    }
    assert!(cb.scroll_offset > 0);

    cb.selected_idx = 0;
    cb.ensure_visible();
    assert_eq!(cb.scroll_offset, 0);
}

#[test]
fn test_combobox_ensure_visible_below_viewport() {
    let mut cb = Combobox::new()
        .options(vec!["A", "B", "C", "D", "E", "F", "G", "H"])
        .max_visible(3);

    cb.open_dropdown();
    cb.selected_idx = 7;
    cb.ensure_visible();
    assert!(cb.scroll_offset > 0);
}

#[test]
fn test_combobox_ensure_visible_already_visible() {
    let mut cb = Combobox::new()
        .options(vec!["A", "B", "C", "D", "E", "F", "G", "H"])
        .max_visible(3);

    cb.open_dropdown();
    cb.select_next();
    let initial_offset = cb.scroll_offset;
    cb.ensure_visible();
    assert_eq!(cb.scroll_offset, initial_offset);
}

#[test]
fn test_combobox_set_input_updates_cursor() {
    let mut cb = Combobox::new();
    cb.set_input("Hello");
    assert_eq!(cb.input(), "Hello");
    assert_eq!(cb.cursor, 5);
}

#[test]
fn test_combobox_set_input_opens_dropdown() {
    let mut cb = Combobox::new().options(vec!["A", "B"]);
    assert!(!cb.is_open());

    cb.set_input("test");
    assert!(cb.is_open());
}

#[test]
fn test_combobox_set_input_empty_does_not_open() {
    let mut cb = Combobox::new().options(vec!["A", "B"]);
    assert!(!cb.is_open());

    cb.set_input("");
    assert!(!cb.is_open());
}

#[test]
fn test_combobox_set_input_updates_filter() {
    let mut cb = Combobox::new().options(vec!["Apple", "Banana", "Cherry"]);
    cb.set_input("App");
    assert_eq!(cb.filtered_count(), 1);
}

#[test]
fn test_combobox_clear_input_resets_cursor() {
    let mut cb = Combobox::new();
    cb.set_input("Hello");
    assert_eq!(cb.cursor, 5);

    cb.clear_input();
    assert_eq!(cb.input(), "");
    assert_eq!(cb.cursor, 0);
}

#[test]
fn test_combobox_clear_input_updates_filter() {
    let mut cb = Combobox::new().options(vec!["Apple", "Banana", "Cherry"]);
    cb.set_input("xyz");
    assert_eq!(cb.filtered_count(), 0);

    cb.clear_input();
    assert_eq!(cb.filtered_count(), 3);
}

#[test]
fn test_combobox_toggle_dropdown_from_closed() {
    let mut cb = Combobox::new().options(vec!["A", "B"]);
    assert!(!cb.is_open());

    cb.toggle_dropdown();
    assert!(cb.is_open());
}

#[test]
fn test_combobox_toggle_dropdown_from_open() {
    let mut cb = Combobox::new().options(vec!["A", "B"]);
    cb.open_dropdown();
    assert!(cb.is_open());

    cb.toggle_dropdown();
    assert!(!cb.is_open());
}

#[test]
fn test_combobox_input() {
    let cb = Combobox::new().value("test value");
    assert_eq!(cb.input(), "test value");
}

#[test]
fn test_combobox_input_empty() {
    let cb = Combobox::new();
    assert!(cb.input().is_empty());
}

#[test]
fn test_combobox_selected_value_matching_label() {
    let cb = Combobox::new()
        .options(vec!["Apple", "Banana"])
        .value("Apple");

    assert_eq!(cb.selected_value(), Some("Apple"));
}

#[test]
fn test_combobox_selected_value_no_match() {
    let cb = Combobox::new()
        .options(vec!["Apple", "Banana"])
        .value("Cherry");

    assert_eq!(cb.selected_value(), None);
}

#[test]
fn test_combobox_selected_value_custom_allowed() {
    let cb = Combobox::new()
        .options(vec!["Apple", "Banana"])
        .allow_custom(true)
        .value("Custom");

    assert_eq!(cb.selected_value(), Some("Custom"));
}

#[test]
fn test_combobox_selected_value_custom_empty() {
    let cb = Combobox::new()
        .options(vec!["Apple", "Banana"])
        .allow_custom(true)
        .value("");

    assert_eq!(cb.selected_value(), None);
}

#[test]
fn test_combobox_selected_values_ref_empty() {
    let cb = Combobox::new().multi_select(true);
    assert!(cb.selected_values_ref().is_empty());
}

#[test]
fn test_combobox_selected_values_ref_with_values() {
    let cb = Combobox::new()
        .multi_select(true)
        .selected_values(vec!["A".to_string(), "B".to_string()]);

    assert_eq!(cb.selected_values_ref(), &["A", "B"]);
}

#[test]
fn test_combobox_is_open_true() {
    let mut cb = Combobox::new();
    cb.open_dropdown();
    assert!(cb.is_open());
}

#[test]
fn test_combobox_is_open_false() {
    let cb = Combobox::new();
    assert!(!cb.is_open());
}

#[test]
fn test_combobox_is_loading_true() {
    let cb = Combobox::new().loading(true);
    assert!(cb.is_loading());
}

#[test]
fn test_combobox_is_loading_false() {
    let cb = Combobox::new();
    assert!(!cb.is_loading());
}

#[test]
fn test_combobox_option_count() {
    let cb = Combobox::new().options(vec!["A", "B", "C", "D"]);
    assert_eq!(cb.option_count(), 4);
}

#[test]
fn test_combobox_option_count_empty() {
    let cb = Combobox::new();
    assert_eq!(cb.option_count(), 0);
}

#[test]
fn test_combobox_filtered_count_no_filter() {
    let cb = Combobox::new().options(vec!["A", "B", "C"]);
    assert_eq!(cb.filtered_count(), 3);
}

#[test]
fn test_combobox_filtered_count_with_filter() {
    let mut cb = Combobox::new().options(vec!["Apple", "Banana", "Cherry"]);
    cb.set_input("App");
    assert_eq!(cb.filtered_count(), 1);
}

#[test]
fn test_combobox_is_selected_true() {
    let cb = Combobox::new()
        .multi_select(true)
        .selected_values(vec!["A".to_string(), "B".to_string()]);

    assert!(cb.is_selected("A"));
    assert!(cb.is_selected("B"));
}

#[test]
fn test_combobox_is_selected_false() {
    let cb = Combobox::new()
        .multi_select(true)
        .selected_values(vec!["A".to_string()]);

    assert!(!cb.is_selected("B"));
}

#[test]
fn test_combobox_is_selected_empty() {
    let cb = Combobox::new().multi_select(true);
    assert!(!cb.is_selected("A"));
}

#[test]
fn test_combobox_selected_value_with_separate_value() {
    let cb = Combobox::new()
        .options_with(vec![ComboOption::new("Display").value("actual")])
        .value("Display");

    assert_eq!(cb.selected_value(), Some("actual"));
}

#[test]
fn test_combobox_update_filter_empty_input() {
    let mut cb = Combobox::new().options(vec!["Apple", "Banana", "Cherry"]);
    cb.set_input("App");
    assert_eq!(cb.filtered_count(), 1);

    cb.clear_input();
    assert_eq!(cb.filtered_count(), 3);
    assert_eq!(cb.selected_idx, 0);
    assert_eq!(cb.scroll_offset, 0);
}

#[test]
fn test_combobox_update_filter_resets_selection() {
    let mut cb = Combobox::new().options(vec!["Apple", "Banana", "Cherry"]);
    cb.open_dropdown();
    cb.select_next();
    assert_eq!(cb.selected_idx, 1);

    cb.set_input("App");
    assert_eq!(cb.selected_idx, 0);
    assert_eq!(cb.scroll_offset, 0);
}

#[test]
fn test_combobox_get_match_fuzzy_mode() {
    let cb = Combobox::new()
        .options(vec!["Hello World"])
        .filter_mode(FilterMode::Fuzzy)
        .value("hw");

    let match_result = cb.get_match("Hello World");
    assert!(match_result.is_some());
}

#[test]
fn test_combobox_get_match_empty_input() {
    let cb = Combobox::new()
        .options(vec!["Apple"])
        .filter_mode(FilterMode::Fuzzy);

    let match_result = cb.get_match("Apple");
    assert!(match_result.is_none());
}

#[test]
fn test_combobox_get_match_non_fuzzy_mode() {
    let cb = Combobox::new()
        .options(vec!["Apple"])
        .filter_mode(FilterMode::Prefix)
        .value("App");

    let match_result = cb.get_match("Apple");
    assert!(match_result.is_none());
}

#[test]
fn test_combobox_filter_mode_none() {
    let mut cb = Combobox::new()
        .options(vec!["Apple", "Banana", "Cherry"])
        .filter_mode(FilterMode::None);

    cb.set_input("xyz");
    assert_eq!(cb.filtered_count(), 3);
}

#[test]
fn test_combobox_filter_prefix_case_insensitive() {
    let mut cb = Combobox::new()
        .options(vec!["apple", "APPLE", "Apple"])
        .filter_mode(FilterMode::Prefix);

    cb.set_input("APP");
    assert_eq!(cb.filtered_count(), 3);
}

#[test]
fn test_combobox_filter_exact_case_insensitive() {
    let mut cb = Combobox::new()
        .options(vec!["apple", "APPLE", "Apple"])
        .filter_mode(FilterMode::Exact);

    cb.set_input("apple");
    assert_eq!(cb.filtered_count(), 3);
}

#[test]
fn test_combobox_filter_contains_case_insensitive() {
    let mut cb = Combobox::new()
        .options(vec!["Apple", "Pineapple", "apple"])
        .filter_mode(FilterMode::Contains);

    cb.set_input("APP");
    assert_eq!(cb.filtered_count(), 3);
}

#[test]
fn test_combobox_update_filter_multiple_times() {
    let mut cb = Combobox::new()
        .options(vec!["Apple", "Banana", "Cherry", "Date"])
        .filter_mode(FilterMode::Prefix);

    cb.set_input("A");
    assert_eq!(cb.filtered_count(), 1);

    cb.set_input("B");
    assert_eq!(cb.filtered_count(), 1);

    cb.set_input("");
    assert_eq!(cb.filtered_count(), 4);
}
