// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

use super::*;
use crate::render::Canvas;
use crate::types::Rect;

fn make_canvas() -> Canvas { Canvas::new( 400, 400 ) }

#[ test ]
fn value_clamped_on_creation()
{
	let s: VSlider<()> = vslider( 1.5 );
	assert_eq!( s.value, 1.0 );
	let s: VSlider<()> = vslider( -0.5 );
	assert_eq!( s.value, 0.0 );
}

#[ test ]
fn value_from_y_top_is_one()
{
	let rect = Rect { x: 0.0, y: 0.0, width: 56.0, height: 160.0 };
	assert_eq!( value_from_y_in_rect( rect, 0.0 ), 1.0 );
}

#[ test ]
fn value_from_y_bottom_is_zero()
{
	let rect = Rect { x: 0.0, y: 0.0, width: 56.0, height: 160.0 };
	assert_eq!( value_from_y_in_rect( rect, 160.0 ), 0.0 );
}

#[ test ]
fn value_from_y_center_is_half()
{
	let rect = Rect { x: 0.0, y: 0.0, width: 56.0, height: 160.0 };
	let v = value_from_y_in_rect( rect, 80.0 );
	assert!( ( v - 0.5 ).abs() < 1e-6 );
}

#[ test ]
fn value_from_y_above_rect_clamps_to_one()
{
	let rect = Rect { x: 0.0, y: 10.0, width: 56.0, height: 160.0 };
	assert_eq!( value_from_y_in_rect( rect, -50.0 ), 1.0 );
}

#[ test ]
fn value_from_y_below_rect_clamps_to_zero()
{
	let rect = Rect { x: 0.0, y: 10.0, width: 56.0, height: 160.0 };
	assert_eq!( value_from_y_in_rect( rect, 500.0 ), 0.0 );
}

#[ test ]
fn value_from_y_respects_rect_offset()
{
	// A rect starting at y=100 with height=100: y=100 → 1.0, y=200 → 0.0.
	let rect = Rect { x: 0.0, y: 100.0, width: 56.0, height: 100.0 };
	assert_eq!( value_from_y_in_rect( rect, 100.0 ), 1.0 );
	assert_eq!( value_from_y_in_rect( rect, 200.0 ), 0.0 );
	let v = value_from_y_in_rect( rect, 150.0 );
	assert!( ( v - 0.5 ).abs() < 1e-6 );
}

#[ test ]
fn size_overrides_defaults()
{
	let canvas = make_canvas();
	let s: VSlider<()> = vslider( 0.5 ).size( 40.0, 200.0 );
	let ( w, h ) = s.preferred_size( 500.0, &canvas );
	assert_eq!( w, 40.0 );
	assert_eq!( h, 200.0 );
}

#[ test ]
fn size_clamps_to_minimum()
{
	let canvas = make_canvas();
	let s: VSlider<()> = vslider( 0.5 ).size( 0.0, 0.0 );
	let ( w, h ) = s.preferred_size( 500.0, &canvas );
	assert_eq!( w, 2.0 );
	assert_eq!( h, 2.0 );
}

#[ test ]
fn preferred_size_ignores_max_width()
{
	// A VSlider is intrinsically sized — the parent's max_width doesn't
	// change what we return.
	let _g = crate::TEST_GLOBALS_LOCK.lock().unwrap_or_else( |e| e.into_inner() );
	let canvas = make_canvas();
	let s: VSlider<()> = vslider( 0.5 );
	let ( w_small, _ ) = s.preferred_size(  10.0, &canvas );
	let ( w_big,   _ ) = s.preferred_size( 9_999.0, &canvas );
	// The intrinsic width now follows the widget-scaling mode.
	assert_eq!( w_small, canvas.geom_px( theme::WIDTH ) );
	assert_eq!( w_big,   canvas.geom_px( theme::WIDTH ) );
}

#[ test ]
fn default_dimensions_follow_widget_scaling()
{
	let _g = crate::TEST_GLOBALS_LOCK.lock().unwrap_or_else( |e| e.into_inner() );
	let s: VSlider<()> = vslider( 0.0 );
	assert_eq!( s.width,  Length::widget( theme::WIDTH ) );
	assert_eq!( s.height, Length::widget( theme::HEIGHT ) );
}

#[ test ]
fn draw_at_value_zero_does_not_panic()
{
	let mut canvas = make_canvas();
	let rect = Rect { x: 10.0, y: 10.0, width: 56.0, height: 160.0 };
	let s: VSlider<()> = vslider( 0.0 );
	s.draw( &mut canvas, rect, false );
}

#[ test ]
fn draw_at_value_one_does_not_panic()
{
	let mut canvas = make_canvas();
	let rect = Rect { x: 10.0, y: 10.0, width: 56.0, height: 160.0 };
	let s: VSlider<()> = vslider( 1.0 );
	s.draw( &mut canvas, rect, true );
}

#[ test ]
fn on_change_is_stored()
{
	let s: VSlider<u32> = vslider( 0.5 ).on_change( |v| ( v * 100.0 ) as u32 );
	let cb = s.on_change.expect( "on_change was set" );
	assert_eq!( cb( 0.25 ), 25 );
}

#[ test ]
fn element_from_vslider()
{
	let s: VSlider<()> = vslider( 0.5 );
	let el: Element<()> = s.into();
	assert!( matches!( el, Element::VSlider( _ ) ) );
}

#[ test ]
fn paint_bounds_equals_layout_rect()
{
	let rect = Rect { x: 4.0, y: 8.0, width: 56.0, height: 160.0 };
	let s: VSlider<()> = vslider( 0.5 );
	let pb = s.paint_bounds( rect );
	assert_eq!( pb.x,      rect.x );
	assert_eq!( pb.y,      rect.y );
	assert_eq!( pb.width,  rect.width );
	assert_eq!( pb.height, rect.height );
}
