// Centralised asset loader.
//
// Illustrations from the figma export ship as SVGs embedded in the
// binary via `include_bytes!`, so the running installer has no
// filesystem dependency on the source tree. Logos and icons come from
// the active ltk theme, looked up by name through the public theme
// API.

use std::sync::Arc;

use ltk::{ Element, decode_svg_bytes, img_widget };

// ── Embedded illustrations ───────────────────────────────────────────────────

macro_rules! illustration
{
	( $name:ident, $path:expr ) =>
	{
		pub const $name: &[ u8 ] = include_bytes!( concat!( "../assets/illustrations/", $path ) );
	};
}

illustration!( LANGUAGE_ICON,           "language.svg" );
illustration!( NAV_GESTURES,            "gestures.svg" );
illustration!( NAV_THREE_BUTTON,        "buttons.svg"  );
illustration!( INSTALL_PROGRESS,        "10-Install progress.svg" );
illustration!( INSTALL_FINISH,          "11-Install finish.svg"   );

illustration!( TUTORIAL_GESTURES_INTRO, "12-Tutorial 01.svg" );
illustration!( TUTORIAL_GESTURES_1,     "12-Tutorial 02.svg" );
illustration!( TUTORIAL_GESTURES_2,     "12-Tutorial 03.svg" );
illustration!( TUTORIAL_GESTURES_3,     "12-Tutorial 04.svg" );

illustration!( TUTORIAL_SMARTCAST_INTRO, "13-Tutorial Smartcast 01.svg" );
illustration!( TUTORIAL_SMARTCAST_1_A,   "13-Tutorial Smartcast 02.1.svg" );
illustration!( TUTORIAL_SMARTCAST_1_B,   "13-Tutorial Smartcast 02.2.svg" );
illustration!( TUTORIAL_SMARTCAST_1_C,   "13-Tutorial Smartcast 02.3.svg" );
illustration!( TUTORIAL_SMARTCAST_1_D,   "13-Tutorial Smartcast 02.4.svg" );
illustration!( TUTORIAL_SMARTCAST_2,     "13-Tutorial Smartcast 03.svg" );
illustration!( TUTORIAL_SMARTCAST_3,     "13-Tutorial Smartcast 04.svg" );

// ── Embedded brand icons ─────────────────────────────────────────────────────

macro_rules! brand_icon
{
	( $name:ident, $path:expr ) =>
	{
		pub const $name: &[ u8 ] = include_bytes!( concat!( "../assets/icons/", $path ) );
	};
}

brand_icon!( PROTON_ICON,  "proton.svg"  );
brand_icon!( DROPBOX_ICON, "dropbox.svg" );

// ── Permissions screen icons ─────────────────────────────────────────────────

brand_icon!( PERM_LOCATION,      "location.svg"      );
brand_icon!( PERM_MICROPHONE,    "microphone.svg"    );
brand_icon!( PERM_CAMERA,        "camera.svg"        );
brand_icon!( PERM_NOTIFICATIONS, "notifications.svg" );

// ── SVG decoding ─────────────────────────────────────────────────────────────

/// Decode an embedded SVG to raw RGBA at the requested pixel size.
/// Returns the buffer plus the actual `( width, height )` produced by
/// resvg, which is what `img_widget()` needs.
pub fn decode_illustration( bytes: &[ u8 ], size: u32 ) -> Option<( Arc<Vec<u8>>, u32, u32 )>
{
	decode_svg_bytes( bytes, size )
}

/// Build an `Element` from an embedded SVG. `size` is the requested
/// raster size in pixels and also the logical display size, so the
/// widget never gets stretched to fill its parent.
pub fn illustration_widget<Msg: Clone + 'static>( bytes: &[ u8 ], size: u32 ) -> Option<Element<Msg>>
{
	let ( rgba, w, h ) = decode_illustration( bytes, size )?;
	let max = w.max( h ) as f32;
	let dw  = w as f32 / max * size as f32;
	let dh  = h as f32 / max * size as f32;
	Some( img_widget( rgba, w, h ).size( dw, dh ).into() )
}

// ── Theme assets ─────────────────────────────────────────────────────────────

/// Resolve a theme icon by catalogue name and decode it to RGBA at the
/// given pixel size. Returns `None` if the icon is missing from the
/// active theme.
pub fn theme_icon<Msg: Clone + 'static>( name: &str, size: u32 ) -> Option<Element<Msg>>
{
	let ( rgba, w, h ) = ltk::theme_icon_rgba( name, size )?;
	Some( img_widget( rgba, w, h ).size( size as f32, size as f32 ).into() )
}

/// Square-format brand logo, decoded at `size` pixels. Falls back to
/// the generic `theme_logo()` PathBuf if the square variant is missing.
pub fn brand_logo<Msg: Clone + 'static>( size: u32 ) -> Option<Element<Msg>>
{
	let path = ltk::theme_logo_square().or_else( ltk::theme_logo )?;
	let bytes = std::fs::read( &path ).ok()?;
	build_logo( &bytes, size )
}

/// Plain isotype (`branding/{mode}/logo/logo.svg`) without the square
/// frame. Used by the Welcome screen where the figma calls for the
/// stand-alone mark.
pub fn brand_isotype<Msg: Clone + 'static>( size: u32 ) -> Option<Element<Msg>>
{
	let path = ltk::theme_logo()?;
	let bytes = std::fs::read( &path ).ok()?;
	build_logo( &bytes, size )
}

/// Splash variant: same square logo but with the "eyd" wordmark
/// recoloured white so it reads against the navy splash background.
/// Performs a textual replace on `fill="#0A1421"` (the dark navy
/// declared in `branding/light/logo/square.svg`) before rasterising.
pub fn splash_logo<Msg: Clone + 'static>( size: u32 ) -> Option<Element<Msg>>
{
	const NEEDLE:      &str = "fill=\"#0A1421\"";
	const REPLACEMENT: &str = "fill=\"#FFFFFF\"";

	let path = ltk::theme_logo_square().or_else( ltk::theme_logo )?;
	let raw  = std::fs::read_to_string( &path ).ok()?;
	if raw.contains( NEEDLE )
	{
		let recoloured = raw.replace( NEEDLE, REPLACEMENT );
		build_logo( recoloured.as_bytes(), size )
	} else {
		build_logo( raw.as_bytes(), size )
	}
}

fn build_logo<Msg: Clone + 'static>( bytes: &[ u8 ], size: u32 ) -> Option<Element<Msg>>
{
	let ( rgba, w, h ) = decode_svg_bytes( bytes, size )?;
	if w == 0 || h == 0 { return None; }
	let max = w.max( h ) as f32;
	let dw  = w as f32 / max * size as f32;
	let dh  = h as f32 / max * size as f32;
	Some( img_widget( rgba, w, h ).size( dw, dh ).into() )
}
