//! Splitter widget integration tests
//!
//! 스플리터 위젯의 통합 테스트입니다.

use revue::event::Key;
use revue::layout::Rect;
use revue::render::Buffer;
use revue::style::Color;
use revue::widget::traits::{RenderContext, StyledView, View};
use revue::widget::{hsplit, pane, splitter, vsplit, HSplit, Pane, SplitOrientation, Splitter, VSplit};

// =============================================================================
// Constructor and Builder Tests
// 생성자 및 빌더 메서드 테스트
// =============================================================================

#[test]
fn test_splitter_new() {
    let split = Splitter::new();
    // 기본 설정으로 생성되는지 확인
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert!(areas.is_empty());
}

#[test]
fn test_splitter_default() {
    let split = Splitter::default();
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert!(areas.is_empty());
}

#[test]
fn test_splitter_helper() {
    let split = splitter();
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert!(areas.is_empty());
}

#[test]
fn test_splitter_horizontal() {
    let split = Splitter::new().horizontal();
    // 수평 방향으로 설정되고, 패인이 정상적으로 추가되는지 확인
    let split = split.pane(Pane::new("left"));
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert_eq!(areas.len(), 1);
}

#[test]
fn test_splitter_vertical() {
    let split = Splitter::new().vertical();
    let split = split.pane(Pane::new("top"));
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert_eq!(areas.len(), 1);
}

#[test]
fn test_splitter_orientation() {
    let split = Splitter::new().orientation(SplitOrientation::Vertical);
    let split = split.pane(Pane::new("top"));
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert_eq!(areas.len(), 1);
}

#[test]
fn test_splitter_color() {
    let split = Splitter::new().color(Color::RED);
    // 색상이 설정되고 렌더링이 정상적으로 되는지 확인
    let mut buffer = Buffer::new(20, 5);
    let area = Rect::new(0, 0, 20, 5);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let split = split.pane(Pane::new("left")).pane(Pane::new("right"));
    split.render(&mut ctx);
}

#[test]
fn test_splitter_active_color() {
    let split = Splitter::new().active_color(Color::CYAN);
    let mut buffer = Buffer::new(20, 5);
    let area = Rect::new(0, 0, 20, 5);
    let mut ctx = RenderContext::new(&mut buffer, area);

    let split = split.pane(Pane::new("left")).pane(Pane::new("right"));
    split.render(&mut ctx);
}

#[test]
fn test_splitter_add_single_pane() {
    let split = Splitter::new().pane(Pane::new("left"));
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert_eq!(areas.len(), 1);
    assert_eq!(areas[0].0, "left");
}

#[test]
fn test_splitter_add_multiple_panes() {
    let split = Splitter::new()
        .pane(Pane::new("left"))
        .pane(Pane::new("right"));
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert_eq!(areas.len(), 2);
    assert_eq!(areas[0].0, "left");
    assert_eq!(areas[1].0, "right");
}

#[test]
fn test_splitter_panes_vec() {
    let panes = vec![Pane::new("a"), Pane::new("b"), Pane::new("c")];
    let split = Splitter::new().panes(panes);
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert_eq!(areas.len(), 3);
}

#[test]
fn test_splitter_builder_chain() {
    let split = splitter()
        .horizontal()
        .color(Color::BLUE)
        .active_color(Color::GREEN)
        .pane(pane("main"))
        .pane(pane("sidebar"));

    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert_eq!(areas.len(), 2);
}

// =============================================================================
// Pane Tests
// 패인(Pane) 관련 테스트
// =============================================================================

#[test]
fn test_pane_new() {
    let p = Pane::new("test");
    assert_eq!(p.id, "test");
    assert_eq!(p.min_size, 5);
    assert_eq!(p.max_size, 0);
    assert_eq!(p.ratio, 0.5);
    assert!(!p.collapsible);
    assert!(!p.collapsed);
}

#[test]
fn test_pane_helper() {
    let p = pane("helper");
    assert_eq!(p.id, "helper");
    assert_eq!(p.min_size, 5);
    assert_eq!(p.ratio, 0.5);
}

#[test]
fn test_pane_min_size() {
    let p = Pane::new("test").min_size(10);
    assert_eq!(p.min_size, 10);
}

#[test]
fn test_pane_max_size() {
    let p = Pane::new("test").max_size(100);
    assert_eq!(p.max_size, 100);
}

#[test]
fn test_pane_ratio() {
    let p = Pane::new("test").ratio(0.7);
    assert_eq!(p.ratio, 0.7);
}

#[test]
fn test_pane_ratio_clamps_high() {
    let p = Pane::new("test").ratio(1.5);
    assert_eq!(p.ratio, 1.0);
}

#[test]
fn test_pane_ratio_clamps_low() {
    let p = Pane::new("test").ratio(-0.5);
    assert_eq!(p.ratio, 0.0);
}

#[test]
fn test_pane_collapsible() {
    let p = Pane::new("test").collapsible();
    assert!(p.collapsible);
}

#[test]
fn test_pane_toggle_collapse_when_collapsible() {
    let mut p = Pane::new("test").collapsible();
    assert!(!p.collapsed);
    p.toggle_collapse();
    assert!(p.collapsed);
    p.toggle_collapse();
    assert!(!p.collapsed);
}

#[test]
fn test_pane_toggle_collapse_when_not_collapsible() {
    let mut p = Pane::new("test");
    assert!(!p.collapsible);
    assert!(!p.collapsed);
    p.toggle_collapse();
    assert!(!p.collapsed); // Should not toggle
}

#[test]
fn test_pane_builder_chain() {
    let p = pane("main").min_size(10).max_size(50).ratio(0.6).collapsible();
    assert_eq!(p.id, "main");
    assert_eq!(p.min_size, 10);
    assert_eq!(p.max_size, 50);
    assert_eq!(p.ratio, 0.6);
    assert!(p.collapsible);
}

// =============================================================================
// Orientation Tests
// 방향(orientation) 관련 테스트
// =============================================================================

#[test]
fn test_orientation_default_trait() {
    let orientation = SplitOrientation::default();
    assert_eq!(orientation, SplitOrientation::Horizontal);
}

#[test]
fn test_orientation_horizontal() {
    let split = Splitter::new().horizontal();
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane(Pane::new("test")).pane_areas(area);
    assert_eq!(areas.len(), 1);
}

#[test]
fn test_orientation_vertical() {
    let split = Splitter::new().vertical();
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane(Pane::new("test")).pane_areas(area);
    assert_eq!(areas.len(), 1);
}

// =============================================================================
// Pane Areas Tests
// 패인 영역 계산 테스트
// =============================================================================

#[test]
fn test_pane_areas_empty() {
    let split = Splitter::new();
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert!(areas.is_empty());
}

#[test]
fn test_pane_areas_single() {
    let split = Splitter::new().pane(Pane::new("only"));
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert_eq!(areas.len(), 1);
    assert_eq!(areas[0].0, "only");
    // 단일 패인은 전체 너비를 차지
    assert_eq!(areas[0].1.width, area.width);
    assert_eq!(areas[0].1.height, area.height);
}

#[test]
fn test_pane_areas_two_horizontal() {
    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("left").ratio(0.5))
        .pane(Pane::new("right").ratio(0.5));
    let area = Rect::new(0, 0, 81, 24); // 81 = 40 + 1 + 40
    let areas = split.pane_areas(area);

    assert_eq!(areas.len(), 2);
    assert_eq!(areas[0].0, "left");
    assert_eq!(areas[1].0, "right");
    // 첫 번째 패인은 40, 두 번째는 39 (구현체의 반올림 차이)
    assert_eq!(areas[0].1.width, 40);
    assert_eq!(areas[1].1.width, 39); // 구현에 맞춤 수정
    assert_eq!(areas[0].1.height, 24);
    assert_eq!(areas[1].1.height, 24);
}

#[test]
fn test_pane_areas_two_vertical() {
    let split = Splitter::new()
        .vertical()
        .pane(Pane::new("top").ratio(0.5))
        .pane(Pane::new("bottom").ratio(0.5));
    let area = Rect::new(0, 0, 80, 25); // 25 = 12 + 1 + 12
    let areas = split.pane_areas(area);

    assert_eq!(areas.len(), 2);
    assert_eq!(areas[0].0, "top");
    assert_eq!(areas[1].0, "bottom");
    // 둘 다 전체 너비
    assert_eq!(areas[0].1.width, 80);
    assert_eq!(areas[1].1.width, 80);
    // 스플리터가 1행 차지
    assert!(areas[0].1.height <= 12);
    assert!(areas[1].1.height <= 12);
}

#[test]
fn test_pane_areas_three_horizontal() {
    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("a").ratio(1.0))
        .pane(Pane::new("b").ratio(1.0))
        .pane(Pane::new("c").ratio(1.0));
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);

    assert_eq!(areas.len(), 3);
    assert_eq!(areas[0].0, "a");
    assert_eq!(areas[1].0, "b");
    assert_eq!(areas[2].0, "c");
}

#[test]
fn test_pane_areas_with_min_size() {
    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("left").min_size(20).ratio(0.2))
        .pane(Pane::new("right").ratio(0.8));
    let area = Rect::new(0, 0, 100, 24);
    let areas = split.pane_areas(area);

    assert_eq!(areas.len(), 2);
    // 왼쪽은 최소 min_size 이상
    assert!(areas[0].1.width >= 20);
}

#[test]
fn test_pane_areas_with_max_size() {
    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("left").max_size(30).ratio(0.8))
        .pane(Pane::new("right").ratio(0.2));
    let area = Rect::new(0, 0, 100, 24);
    let areas = split.pane_areas(area);

    assert_eq!(areas.len(), 2);
    // 왼쪽은 최대 max_size 이하
    assert!(areas[0].1.width <= 30);
}

#[test]
fn test_pane_areas_collapsed_pane() {
    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("left").ratio(0.5))
        .pane(Pane::new("middle").ratio(0.25).collapsible())
        .pane(Pane::new("right").ratio(0.25));
    let area = Rect::new(0, 0, 80, 24);

    // 먼저 모든 패인이 보이는지 확인
    let areas = split.pane_areas(area);
    assert_eq!(areas.len(), 3);
}

#[test]
fn test_pane_areas_with_offset() {
    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("left").ratio(0.5))
        .pane(Pane::new("right").ratio(0.5));
    let area = Rect::new(10, 5, 80, 20);
    let areas = split.pane_areas(area);

    assert_eq!(areas.len(), 2);
    // 오프셋이 적용되는지 확인
    assert_eq!(areas[0].1.x, 10);
    assert_eq!(areas[0].1.y, 5);
}

// =============================================================================
// Rendering Tests
// 렌더링 테스트
// =============================================================================

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

    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("left").ratio(0.5))
        .pane(Pane::new("right").ratio(0.5));

    split.render(&mut ctx);

    // 중간에 수직 구분선이 있는지 확인
    let mut found_divider = false;
    for x in 8..12 {
        if buffer.get(x, 0).map(|c| c.symbol) == Some('│') {
            found_divider = true;
            break;
        }
    }
    assert!(found_divider);
}

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

    let split = Splitter::new()
        .vertical()
        .pane(Pane::new("top").ratio(0.5))
        .pane(Pane::new("bottom").ratio(0.5));

    split.render(&mut ctx);

    // 중간에 수평 구분선이 있는지 확인
    let mut found_divider = false;
    for y in 4..6 {
        if buffer.get(0, y).map(|c| c.symbol) == Some('─') {
            found_divider = true;
            break;
        }
    }
    assert!(found_divider);
}

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

    let split = Splitter::new()
        .horizontal()
        .color(Color::RED)
        .pane(Pane::new("left").ratio(0.5))
        .pane(Pane::new("right").ratio(0.5));

    split.render(&mut ctx);

    // 구분선의 색상이 설정되어 있는지 확인
    for x in 0..20 {
        if let Some(cell) = buffer.get(x, 0) {
            if cell.symbol == '│' {
                assert_eq!(cell.fg, Some(Color::RED));
                return;
            }
        }
    }
}

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

    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("a").ratio(1.0))
        .pane(Pane::new("b").ratio(1.0))
        .pane(Pane::new("c").ratio(1.0));

    split.render(&mut ctx);

    // 2개의 구분선이 있어야 함
    let mut divider_count = 0;
    for x in 0..30 {
        if buffer.get(x, 0).map(|c| c.symbol) == Some('│') {
            divider_count += 1;
        }
    }
    assert!(divider_count >= 1);
}

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

    let split = Splitter::new()
        .vertical()
        .pane(Pane::new("a").ratio(1.0))
        .pane(Pane::new("b").ratio(1.0))
        .pane(Pane::new("c").ratio(1.0));

    split.render(&mut ctx);

    // 2개의 구분선이 있어야 함
    let mut divider_count = 0;
    for y in 0..30 {
        if buffer.get(0, y).map(|c| c.symbol) == Some('─') {
            divider_count += 1;
        }
    }
    assert!(divider_count >= 1);
}

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

    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("left").ratio(0.5))
        .pane(Pane::new("right").ratio(0.5));

    split.render(&mut ctx);

    // 오프셋 영역 내에 구분선이 렌더링되는지 확인
    let mut found_divider = false;
    for x in 10..30 {
        if buffer.get(x, 5).map(|c| c.symbol) == Some('│') {
            found_divider = true;
            break;
        }
    }
    assert!(found_divider);
}

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

    let split = Splitter::new();
    split.render(&mut ctx);
    // 패인이 없어도 패닉하지 않음
}

// =============================================================================
// Focus Management Tests
// 포커스 관리 테스트
// =============================================================================

#[test]
fn test_splitter_focused_initial() {
    let split = Splitter::new()
        .pane(Pane::new("first"))
        .pane(Pane::new("second"))
        .pane(Pane::new("third"));

    assert_eq!(split.focused(), Some("first"));
}

#[test]
fn test_splitter_focus_next() {
    let mut split = Splitter::new()
        .pane(Pane::new("a"))
        .pane(Pane::new("b"))
        .pane(Pane::new("c"));

    assert_eq!(split.focused(), Some("a"));

    split.focus_next();
    assert_eq!(split.focused(), Some("b"));

    split.focus_next();
    assert_eq!(split.focused(), Some("c"));

    split.focus_next();
    assert_eq!(split.focused(), Some("a")); // 순환
}

#[test]
fn test_splitter_focus_prev() {
    let mut split = Splitter::new()
        .pane(Pane::new("a"))
        .pane(Pane::new("b"))
        .pane(Pane::new("c"));

    split.focus_prev();
    assert_eq!(split.focused(), Some("c")); // 마지막으로

    split.focus_prev();
    assert_eq!(split.focused(), Some("b"));

    split.focus_prev();
    assert_eq!(split.focused(), Some("a"));
}

#[test]
fn test_splitter_focus_with_collapsed_pane() {
    let split = Splitter::new()
        .pane(Pane::new("a"))
        .pane(Pane::new("b").collapsible())
        .pane(Pane::new("c"));

    // 포커스는 축소된 패인을 건너뛰어야 함
    assert_eq!(split.focused(), Some("a"));
}

// =============================================================================
// Resize Interaction Tests
// 크기 조절 상호작용 테스트
// =============================================================================

#[test]
fn test_splitter_start_resize_valid() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    split.start_resize(0);
    // 유효한 디바이더 인덱스로 시작
    // 내부 상태를 직접 확인할 수 없으므로 resize가 동작하는지 확인
    split.resize(10);
}

#[test]
fn test_splitter_start_resize_invalid() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    // 디바이더 인덱스 1은 범위를 벗어남 (2개 패인에 1개 디바이더)
    split.start_resize(1);
    // 유효하지 않은 인덱스는 무시되어야 함
}

#[test]
fn test_splitter_stop_resize() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    let area = Rect::new(0, 0, 100, 24);
    let areas_before = split.pane_areas(area);

    split.start_resize(0);
    split.resize(10);

    let areas_after_resize = split.pane_areas(area);
    // 크기 조절 후 영역이 변경되어야 함
    assert_ne!(areas_before[0].1.width, areas_after_resize[0].1.width);

    split.stop_resize();
    // 크기 조절이 중지되어야 함
}

#[test]
fn test_splitter_resize_positive() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    let area = Rect::new(0, 0, 100, 24);
    let areas_before = split.pane_areas(area);

    split.start_resize(0);
    split.resize(10);

    let areas_after = split.pane_areas(area);

    // 양수 크기 조절 후 첫 번째 패인이 더 커져야 함
    assert!(areas_after[0].1.width > areas_before[0].1.width);
    assert!(areas_after[1].1.width < areas_before[1].1.width);
}

#[test]
fn test_splitter_resize_negative() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    let area = Rect::new(0, 0, 100, 24);
    let areas_before = split.pane_areas(area);

    split.start_resize(0);
    split.resize(-10);

    let areas_after = split.pane_areas(area);

    // 음수 크기 조절 후 첫 번째 패인이 작아져야 함
    assert!(areas_after[0].1.width < areas_before[0].1.width);
    assert!(areas_after[1].1.width > areas_before[1].1.width);
}

#[test]
fn test_splitter_resize_without_start() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    let area = Rect::new(0, 0, 100, 24);
    let areas_before = split.pane_areas(area);
    split.resize(10);

    let areas_after = split.pane_areas(area);

    // 활성 디바이더 없이는 변경되지 않아야 함
    assert_eq!(areas_before[0].1.width, areas_after[0].1.width);
}

#[test]
fn test_splitter_resize_clamps_to_bounds() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    let area = Rect::new(0, 0, 100, 24);

    split.start_resize(0);
    split.resize(100); // 매우 큰 양수

    let areas = split.pane_areas(area);

    // 영역이 유효한 범위 내에 있어야 함 (모두 0보다 크고 전체보다 작음)
    assert!(areas[0].1.width > 0);
    assert!(areas[1].1.width > 0);
    assert!(areas[0].1.width < area.width);
    assert!(areas[1].1.width < area.width);
}

// =============================================================================
// Key Handling Tests
// 키 입력 처리 테스트
// =============================================================================

#[test]
fn test_splitter_handle_key_tab() {
    let mut split = Splitter::new()
        .pane(Pane::new("a"))
        .pane(Pane::new("b"));

    assert_eq!(split.focused(), Some("a"));
    let handled = split.handle_key(&Key::Tab);
    assert!(handled);
    assert_eq!(split.focused(), Some("b"));
}

#[test]
fn test_splitter_handle_key_left_with_active_resize() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    let area = Rect::new(0, 0, 100, 24);
    let areas_before = split.pane_areas(area);

    split.start_resize(0);
    let handled = split.handle_key(&Key::Left);
    assert!(handled);

    let areas_after = split.pane_areas(area);
    // 왼쪽 화살표는 첫 번째 패인을 축소
    assert!(areas_after[0].1.width < areas_before[0].1.width);
}

#[test]
fn test_splitter_handle_key_right_with_active_resize() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    let area = Rect::new(0, 0, 100, 24);
    let areas_before = split.pane_areas(area);

    split.start_resize(0);
    let handled = split.handle_key(&Key::Right);
    assert!(handled);

    let areas_after = split.pane_areas(area);
    // 오른쪽 화살표는 첫 번째 패인을 확장
    assert!(areas_after[0].1.width > areas_before[0].1.width);
}

#[test]
fn test_splitter_handle_key_h_with_active_resize() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    let area = Rect::new(0, 0, 100, 24);
    let areas_before = split.pane_areas(area);

    split.start_resize(0);
    let handled = split.handle_key(&Key::Char('h'));
    assert!(handled);

    let areas_after = split.pane_areas(area);
    // 'h' 키는 첫 번째 패인을 축소
    assert!(areas_after[0].1.width < areas_before[0].1.width);
}

#[test]
fn test_splitter_handle_key_l_with_active_resize() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    let area = Rect::new(0, 0, 100, 24);
    let areas_before = split.pane_areas(area);

    split.start_resize(0);
    let handled = split.handle_key(&Key::Char('l'));
    assert!(handled);

    let areas_after = split.pane_areas(area);
    // 'l' 키는 첫 번째 패인을 확장
    assert!(areas_after[0].1.width > areas_before[0].1.width);
}

#[test]
fn test_splitter_handle_key_up_vertical_resize() {
    let mut split = Splitter::new()
        .vertical()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    split.start_resize(0);
    let handled = split.handle_key(&Key::Up);
    assert!(handled);
}

#[test]
fn test_splitter_handle_key_down_vertical_resize() {
    let mut split = Splitter::new()
        .vertical()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    split.start_resize(0);
    let handled = split.handle_key(&Key::Down);
    assert!(handled);
}

#[test]
fn test_splitter_handle_key_enter_stops_resize() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    split.start_resize(0);
    let handled = split.handle_key(&Key::Enter);
    assert!(handled);
    // 크기 조절이 중지되어야 함
}

#[test]
fn test_splitter_handle_key_escape_stops_resize() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    split.start_resize(0);
    let handled = split.handle_key(&Key::Escape);
    assert!(handled);
    // 크기 조절이 중지되어야 함
}

#[test]
fn test_splitter_handle_key_unhandled() {
    let mut split = Splitter::new()
        .pane(Pane::new("a"))
        .pane(Pane::new("b"));

    let handled = split.handle_key(&Key::Char('x'));
    assert!(!handled);
}

#[test]
fn test_splitter_handle_key_left_without_resize() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").ratio(0.5))
        .pane(Pane::new("b").ratio(0.5));

    let area = Rect::new(0, 0, 100, 24);
    let areas_before = split.pane_areas(area);

    let handled = split.handle_key(&Key::Left);
    assert!(!handled); // 활성 크기 조절 없이는 처리되지 않음

    let areas_after = split.pane_areas(area);
    assert_eq!(areas_before[0].1.width, areas_after[0].1.width);
}

// =============================================================================
// Pane Collapse Tests
// 패인 축소 테스트
// =============================================================================

#[test]
fn test_splitter_toggle_pane_valid() {
    let mut split = Splitter::new()
        .pane(Pane::new("a").collapsible())
        .pane(Pane::new("b"));

    let area = Rect::new(0, 0, 100, 24);

    // 처음에는 두 패인 모두 보임
    let areas_initial = split.pane_areas(area);
    assert_eq!(areas_initial.len(), 2);

    split.toggle_pane(0);
    let areas_after_toggle = split.pane_areas(area);
    // 축소 후에는 한 패인만 보임
    assert_eq!(areas_after_toggle.len(), 1);

    split.toggle_pane(0);
    let areas_after_untoggle = split.pane_areas(area);
    // 다시 토글하면 두 패인 모두 보임
    assert_eq!(areas_after_untoggle.len(), 2);
}

#[test]
fn test_splitter_toggle_pane_invalid_index() {
    let mut split = Splitter::new()
        .pane(Pane::new("a"))
        .pane(Pane::new("b"));

    // 패닉하지 않아야 함
    split.toggle_pane(5);
}

#[test]
fn test_splitter_toggle_non_collapsible_pane() {
    let mut split = Splitter::new()
        .pane(Pane::new("a"))
        .pane(Pane::new("b"));

    let area = Rect::new(0, 0, 100, 24);

    let areas_before = split.pane_areas(area);
    assert_eq!(areas_before.len(), 2);

    split.toggle_pane(0);

    let areas_after = split.pane_areas(area);
    // collapsible하지 않으면 변경되지 않아야 함
    assert_eq!(areas_after.len(), 2);
}

// =============================================================================
// HSplit Tests
// 수평 분할(HSplit) 테스트
// =============================================================================

#[test]
fn test_hsplit_new() {
    let split = HSplit::new(0.5);
    assert_eq!(split.ratio, 0.5);
    assert_eq!(split.min_left, 5);
    assert_eq!(split.min_right, 5);
    assert!(split.show_splitter);
    assert_eq!(split.color, Color::rgb(80, 80, 80));
}

#[test]
fn test_hsplit_helper() {
    let split = hsplit(0.3);
    assert_eq!(split.ratio, 0.3);
}

#[test]
fn test_hsplit_ratio_clamps() {
    let split = HSplit::new(1.5);
    assert_eq!(split.ratio, 0.9);
}

#[test]
fn test_hsplit_min_widths() {
    let split = HSplit::new(0.5).min_widths(10, 20);
    assert_eq!(split.min_left, 10);
    assert_eq!(split.min_right, 20);
}

#[test]
fn test_hsplit_hide_splitter() {
    let split = HSplit::new(0.5).hide_splitter();
    assert!(!split.show_splitter);
}

#[test]
fn test_hsplit_areas() {
    let split = HSplit::new(0.5);
    let area = Rect::new(0, 0, 100, 50);
    let (left, right) = split.areas(area);

    assert!(left.width > 0);
    assert!(right.width > 0);
    assert_eq!(left.y, 0);
    assert_eq!(right.y, 0);
    assert_eq!(left.height, 50);
    assert_eq!(right.height, 50);
    assert_eq!(left.x + left.width + 1, right.x); // 스플리터용 +1
}

#[test]
fn test_hsplit_areas_with_min_widths() {
    let split = HSplit::new(0.1).min_widths(20, 20);
    let area = Rect::new(0, 0, 100, 50);
    let (left, right) = split.areas(area);

    assert!(left.width >= 20);
    assert!(right.width >= 20);
}

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

    let split = HSplit::new(0.5);
    split.render(&mut ctx);

    // 수직 구분선을 찾아야 함
    let mut found_divider = false;
    for x in 0..20 {
        if buffer.get(x, 0).map(|c| c.symbol) == Some('│') {
            found_divider = true;
            break;
        }
    }
    assert!(found_divider);
}

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

    let split = HSplit::new(0.5).hide_splitter();
    split.render(&mut ctx);

    // 보이는 구분선이 없어야 함
    for x in 0..20 {
        if let Some(cell) = buffer.get(x, 0) {
            if cell.symbol == '│' {
                panic!("스플리터가 숨겨져 있어야 하는데 구분선 발견");
            }
        }
    }
}

// =============================================================================
// VSplit Tests
// 수직 분할(VSplit) 테스트
// =============================================================================

#[test]
fn test_vsplit_new() {
    let split = VSplit::new(0.5);
    assert_eq!(split.ratio, 0.5);
    assert_eq!(split.min_top, 3);
    assert_eq!(split.min_bottom, 3);
    assert!(split.show_splitter);
    assert_eq!(split.color, Color::rgb(80, 80, 80));
}

#[test]
fn test_vsplit_helper() {
    let split = vsplit(0.7);
    assert_eq!(split.ratio, 0.7);
}

#[test]
fn test_vsplit_ratio_clamps() {
    let split = VSplit::new(0.05);
    assert_eq!(split.ratio, 0.1);
}

#[test]
fn test_vsplit_areas() {
    let split = VSplit::new(0.5);
    let area = Rect::new(0, 0, 80, 24);
    let (top, bottom) = split.areas(area);

    assert!(top.height > 0);
    assert!(bottom.height > 0);
    assert_eq!(top.x, 0);
    assert_eq!(bottom.x, 0);
    assert_eq!(top.width, 80);
    assert_eq!(bottom.width, 80);
    assert_eq!(top.y + top.height + 1, bottom.y); // 스플리터용 +1
}

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

    let split = VSplit::new(0.5);
    split.render(&mut ctx);

    // 수평 구분선을 찾아야 함
    let mut found_divider = false;
    for y in 0..10 {
        if buffer.get(0, y).map(|c| c.symbol) == Some('─') {
            found_divider = true;
            break;
        }
    }
    assert!(found_divider);
}

// =============================================================================
// Edge Case Tests
// 엣지 케이스 테스트
// =============================================================================

#[test]
fn test_splitter_zero_ratio_normalizes() {
    let split = Splitter::new()
        .pane(Pane::new("a").ratio(0.0))
        .pane(Pane::new("b").ratio(0.0));

    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);

    // 균등한 분배로 정규화되어야 함
    assert_eq!(areas.len(), 2);
    assert!(areas[0].1.width > 0);
    assert!(areas[1].1.width > 0);
}

#[test]
fn test_splitter_all_ratios_zero() {
    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("a").ratio(0.0))
        .pane(Pane::new("b").ratio(0.0));

    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);

    // 여전히 공간을 균등하게 할당해야 함
    assert_eq!(areas.len(), 2);
}

#[test]
fn test_splitter_uneven_ratios() {
    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("a").ratio(0.8))
        .pane(Pane::new("b").ratio(0.2));

    let area = Rect::new(0, 0, 100, 24);
    let areas = split.pane_areas(area);

    // 첫 번째 패인이 더 커야 함
    assert!(areas[0].1.width > areas[1].1.width);
}

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

    let split = Splitter::new().pane(Pane::new("only"));
    split.render(&mut ctx);

    // 구분선이 렌더링되지 않아야 함
    for x in 0..20 {
        if let Some(cell) = buffer.get(x, 0) {
            assert_ne!(cell.symbol, '│');
        }
    }
}

#[test]
fn test_splitter_very_small_area() {
    let split = Splitter::new()
        .pane(Pane::new("a").min_size(1))
        .pane(Pane::new("b").min_size(1));

    let area = Rect::new(0, 0, 5, 5);
    let areas = split.pane_areas(area);

    // 패닉 없이 영역 계산
    assert_eq!(areas.len(), 2);
}

#[test]
fn test_splitter_max_size_enforcement() {
    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("a").max_size(10).ratio(0.9))
        .pane(Pane::new("b").ratio(0.1));

    let area = Rect::new(0, 0, 100, 24);
    let areas = split.pane_areas(area);

    // 첫 번째 패인은 max_size로 제한되어야 함
    assert!(areas[0].1.width <= 10);
}

#[test]
fn test_splitter_min_size_enforcement() {
    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("a").min_size(50).ratio(0.1))
        .pane(Pane::new("b").ratio(0.9));

    let area = Rect::new(0, 0, 100, 24);
    let areas = split.pane_areas(area);

    // 첫 번째 패인은 최소 min_size 이상이어야 함
    assert!(areas[0].1.width >= 50);
}

#[test]
fn test_splitter_empty_pane_vec() {
    let panes = vec![];
    let split = Splitter::new().panes(panes);
    let area = Rect::new(0, 0, 80, 24);
    let areas = split.pane_areas(area);
    assert!(areas.is_empty());
}

#[test]
fn test_splitter_large_number_of_panes() {
    let mut split = Splitter::new();
    for i in 0..10 {
        split = split.pane(Pane::new(format!("pane_{}", i)).ratio(1.0));
    }

    let area = Rect::new(0, 0, 200, 24);
    let areas = split.pane_areas(area);

    assert_eq!(areas.len(), 10);
}

// =============================================================================
// View Trait Tests
// View 트레이트 테스트
// =============================================================================

#[test]
fn test_splitter_view_widget_type() {
    let split = Splitter::new();
    assert_eq!(split.widget_type(), "Splitter");
}

#[test]
fn test_splitter_view_id_none() {
    let split = Splitter::new();
    assert!(View::id(&split).is_none());
}

#[test]
fn test_splitter_view_id_some() {
    let split = Splitter::new().element_id("my-splitter");
    assert_eq!(View::id(&split), Some("my-splitter"));
}

#[test]
fn test_splitter_view_classes_empty() {
    let split = Splitter::new();
    assert!(View::classes(&split).is_empty());
}

#[test]
fn test_splitter_view_classes_with_values() {
    let split = Splitter::new().class("horizontal").class("resizable");
    let classes = View::classes(&split);
    assert_eq!(classes.len(), 2);
    assert!(classes.contains(&"horizontal".to_string()));
    assert!(classes.contains(&"resizable".to_string()));
}

#[test]
fn test_splitter_view_meta() {
    let split = Splitter::new().element_id("test-id").class("test-class");
    let meta = split.meta();
    assert_eq!(meta.widget_type, "Splitter");
    assert_eq!(meta.id, Some("test-id".to_string()));
    assert!(meta.classes.contains("test-class"));
}

#[test]
fn test_splitter_view_children_default() {
    let split = Splitter::new();
    assert!(View::children(&split).is_empty());
}

// =============================================================================
// StyledView Trait Tests
// StyledView 트레이트 테스트
// =============================================================================

#[test]
fn test_splitter_styled_view_set_id() {
    let mut split = Splitter::new();
    StyledView::set_id(&mut split, "test-id");
    assert_eq!(View::id(&split), Some("test-id"));
}

#[test]
fn test_splitter_styled_view_add_class() {
    let mut split = Splitter::new();
    StyledView::add_class(&mut split, "first");
    StyledView::add_class(&mut split, "second");
    assert!(StyledView::has_class(&split, "first"));
    assert!(StyledView::has_class(&split, "second"));
    assert_eq!(View::classes(&split).len(), 2);
}

#[test]
fn test_splitter_styled_view_remove_class() {
    let mut split = Splitter::new().class("a").class("b").class("c");
    StyledView::remove_class(&mut split, "b");
    assert!(StyledView::has_class(&split, "a"));
    assert!(!StyledView::has_class(&split, "b"));
    assert!(StyledView::has_class(&split, "c"));
}

#[test]
fn test_splitter_styled_view_toggle_class() {
    let mut split = Splitter::new();
    StyledView::toggle_class(&mut split, "test");
    assert!(StyledView::has_class(&split, "test"));
    StyledView::toggle_class(&mut split, "test");
    assert!(!StyledView::has_class(&split, "test"));
}

// =============================================================================
// Builder Props Tests
// 빌더 속성 테스트
// =============================================================================

#[test]
fn test_splitter_builder_element_id() {
    let split = Splitter::new().element_id("my-splitter");
    assert_eq!(View::id(&split), Some("my-splitter"));
}

#[test]
fn test_splitter_builder_class() {
    let split = Splitter::new().class("horizontal").class("line");
    assert!(split.has_class("horizontal"));
    assert!(split.has_class("line"));
}

#[test]
fn test_splitter_builder_classes() {
    let split = Splitter::new().classes(vec!["first", "second", "third"]);
    assert!(split.has_class("first"));
    assert!(split.has_class("second"));
    assert!(split.has_class("third"));
}

// =============================================================================
// Active Divider Color Tests
// 활성 디바이더 색상 테스트
// =============================================================================

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

    let split = Splitter::new()
        .horizontal()
        .color(Color::rgb(80, 80, 80))
        .active_color(Color::YELLOW)
        .pane(Pane::new("left").ratio(0.5))
        .pane(Pane::new("right").ratio(0.5));

    split.render(&mut ctx);

    // 활성 색상 설정으로 렌더링 성공
    // (디바이더가 크기 조절 중일 때 활성 색상이 표시됨)
}

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

    let mut split = Splitter::new()
        .horizontal()
        .active_color(Color::YELLOW)
        .pane(Pane::new("left").ratio(0.5))
        .pane(Pane::new("right").ratio(0.5));

    // 활성 디바이더 설정
    split.start_resize(0);

    split.render(&mut ctx);

    // 활성 색상으로 구분선 렌더링
    for x in 0..20 {
        if let Some(cell) = buffer.get(x, 0) {
            if cell.symbol == '│' && cell.fg == Some(Color::YELLOW) {
                return; // 활성 색상 구분선 발견
            }
        }
    }
    // 렌더링이 성공하면 테스트 통과
}

// =============================================================================
// All Orientations Render Test
// 모든 방향 렌더링 테스트
// =============================================================================

#[test]
fn test_splitter_all_orientations_render() {
    let orientations = [SplitOrientation::Horizontal, SplitOrientation::Vertical];

    for orientation in orientations {
        let mut buffer = Buffer::new(20, 10);
        let area = Rect::new(0, 0, 20, 10);
        let mut ctx = RenderContext::new(&mut buffer, area);

        let split = Splitter::new()
            .orientation(orientation)
            .pane(Pane::new("first").ratio(0.5))
            .pane(Pane::new("second").ratio(0.5));

        split.render(&mut ctx);
        // 모든 방향에서 패닉 없어야 함
    }
}

// =============================================================================
// Real-world Usage Scenarios
// 실제 사용 시나리오 테스트
// =============================================================================

#[test]
fn test_splitter_three_column_layout() {
    // 3열 레이아웃 시나리오 (사이드바 - 메인 - 인포패널)
    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("sidebar").ratio(0.2).min_size(15))
        .pane(Pane::new("main").ratio(0.6))
        .pane(Pane::new("info").ratio(0.2).min_size(15));

    let area = Rect::new(0, 0, 120, 30);
    let areas = split.pane_areas(area);

    assert_eq!(areas.len(), 3);
    assert_eq!(areas[0].0, "sidebar");
    assert_eq!(areas[1].0, "main");
    assert_eq!(areas[2].0, "info");

    // 각 영역이 유효한지 확인
    assert!(areas[0].1.width >= 15);
    assert!(areas[1].1.width > 0);
    assert!(areas[2].1.width >= 15);
}

#[test]
fn test_splitter_code_editor_layout() {
    // 코드 편집기 레이아웃 (코드 트리 + 에디터 + 터미널)
    let split = Splitter::new()
        .horizontal()
        .pane(Pane::new("filetree").ratio(0.25).min_size(10))
        .pane(Pane::new("editor").ratio(0.75))
        .pane(Pane::new("terminal").ratio(0.3).collapsible());

    let area = Rect::new(0, 0, 100, 40);
    let areas = split.pane_areas(area);

    assert_eq!(areas.len(), 3);
}

#[test]
fn test_splitter_dashboard_layout() {
    // 대시보드 레이아웃 (상단 메트릭 + 하단 차트)
    let split = Splitter::new()
        .vertical()
        .pane(Pane::new("metrics").ratio(0.3).min_size(5))
        .pane(Pane::new("charts").ratio(0.7).min_size(10));

    let area = Rect::new(0, 0, 80, 30);
    let areas = split.pane_areas(area);

    assert_eq!(areas.len(), 2);
    assert!(areas[0].1.height >= 5);
    assert!(areas[1].1.height >= 10);
}

#[test]
fn test_splitter_idetlike_layout() {
    // IDE와 유사한 레이아웃 (좌: 파일트리, 우: 상단에디터+하단터미널)
    // 이것은 두 개의 스플리터 조합으로 구현될 수 있음
    let h_split = Splitter::new()
        .horizontal()
        .pane(Pane::new("filetree").ratio(0.25).min_size(15))
        .pane(Pane::new("right_panel").ratio(0.75));

    let area = Rect::new(0, 0, 120, 40);
    let areas = h_split.pane_areas(area);

    assert_eq!(areas.len(), 2);
    assert!(areas[0].1.width >= 15);
    assert!(areas[1].1.width > 0);
}
