// Screen 10 — Install progress.
//
// `state.progress` mirrors the background install worker; app::update
// drains its slot on every tick and transitions to InstallFinish (or
// back to DiskManagement on error) when the worker ends.

use ltk::
{
	ButtonVariant, Element,
	button, column, dialog, progress_bar, scroll, spacer, stack, text,
};

use crate::app::Msg;
use crate::i18n::tr;
use crate::state::State;
use crate::ui::{ chrome, widgets };
use crate::ui::theme as t;

pub fn view( state: &State ) -> Element<Msg>
{
	let palette = ltk::theme_palette();
	let fraction = state.progress.as_ref().map( |p| p.fraction ).unwrap_or( 0.0 );
	let phase = state.progress.as_ref()
		.map( |p| p.phase )
		.unwrap_or( crate::install::Phase::Partition );

	let percent = format!( "{}%", ( fraction * 100.0 ).round() as u32 );

	let phase_text = match phase
	{
		crate::install::Phase::Partition  => tr!( "progress.phase_partition" ),
		crate::install::Phase::Format     => tr!( "progress.phase_format" ),
		crate::install::Phase::Copy       => tr!( "progress.phase_copy" ),
		crate::install::Phase::Bootloader => tr!( "progress.phase_bootloader" ),
		crate::install::Phase::Finalize   => tr!( "progress.phase_finalize" ),
	};

	// The inner spacers keep the block vertically centred while it fits.
	let content = column::<Msg>()
		.spacing( t::SECTION_SPACING )
		.push( spacer() )
		.push( spinner_block() )
		.push( chrome::title_block(
			&tr!( "progress.title" ),
			Some( &tr!( "progress.subtitle" ) ),
		) )
		.push( progress_bar( fraction ) )
		.push(
			text( percent )
				.size( t::BODY_SIZE )
				.color( palette.text_primary )
				.align_center(),
		)
		.push( widgets::info_card( None, &[ phase_text.to_string() ] ) )
		.push( spacer() );

	let body = column::<Msg>()
		.padding( t::PAGE_PADDING_H )
		.push( scroll( content ) )
		.push( chrome::skip_link( &tr!( "progress.cancel" ), Msg::CancelInstall ) );

	let page = chrome::page( body );
	if state.confirm_cancel_install
	{
		return stack::<Msg>().push( page ).push( cancel_dialog() ).into();
	}
	page
}

fn cancel_dialog() -> Element<Msg>
{
	dialog::<Msg>()
		.title( tr!( "progress.cancel_confirm_title" ).to_string() )
		.subtitle( tr!( "progress.cancel_confirm_subtitle" ).to_string() )
		.cancel( Msg::DismissCancelInstall )
		.action(
			button::<Msg>( tr!( "progress.cancel_confirm_no" ).to_string() )
				.variant( ButtonVariant::Tertiary )
				.font_size( t::control_font_size() )
				.on_press( Msg::DismissCancelInstall )
				.height( t::control_height() ),
		)
		.action(
			button::<Msg>( tr!( "progress.cancel_confirm_yes" ).to_string() )
				.variant( ButtonVariant::Primary )
				.font_size( t::control_font_size() )
				.on_press( Msg::ConfirmCancelInstall )
				.height( t::control_height() ),
		)
		.into()
}

fn spinner_block() -> Element<Msg>
{
	use ltk::spinner;
	column::<Msg>()
		.align_center_x( true )
		.push(
			spinner()
				.size( 64.0 )
				.stroke_width( 4.0 )
				.phase( spinner_phase() ),
		)
		.into()
}

/// ltk's spinner is stateless — without a `phase` it stays frozen at
/// angle 0. Same helper as the wireless connecting overlay.
fn spinner_phase() -> f32
{
	use std::sync::OnceLock;
	use std::time::Instant;
	static START: OnceLock<Instant> = OnceLock::new();
	START.get_or_init( Instant::now ).elapsed().as_secs_f32()
}
