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

//! Follow the desktop's accessibility text scale.
//!
//! Reads `org.gnome.desktop.interface text-scaling-factor` once at
//! startup and then follows external changes through `gsettings
//! monitor`, sending each value to the run loop, which applies it via
//! [`crate::set_text_scale`] and repaints. GTK apps track this key on
//! their own; this module gives every ltk app the same behaviour with
//! no app-side wiring. Degrades silently to a fixed 1.0 when
//! `gsettings` is not installed.

use std::io::{ BufRead, BufReader };
use std::process::{ Command, Stdio };

const SCHEMA: &str = "org.gnome.desktop.interface";
const KEY:    &str = "text-scaling-factor";

/// Spawn the watcher thread. `tx` delivers each observed factor to the
/// run loop; the initial `gsettings get` value is sent first.
pub( super ) fn spawn_watcher( tx: calloop::channel::Sender<f32> )
{
	let _ = std::thread::Builder::new()
		.name( "ltk-text-scale".into() )
		.spawn( move ||
		{
			if let Some( v ) = read_current()
			{
				let _ = tx.send( v );
			}

			let Ok( mut child ) = Command::new( "gsettings" )
				.args( [ "monitor", SCHEMA, KEY ] )
				.stdout( Stdio::piped() )
				.stderr( Stdio::null() )
				.spawn()
			else { return };
			let Some( stdout ) = child.stdout.take() else { return };

			// Each line has the shape `text-scaling-factor: 1.25`.
			for line in BufReader::new( stdout ).lines().map_while( Result::ok )
			{
				if let Some( v ) = parse_factor( &line )
				{
					if tx.send( v ).is_err() { break; }
				}
			}
			let _ = child.kill();
		} );
}

fn read_current() -> Option<f32>
{
	let out = Command::new( "gsettings" )
		.args( [ "get", SCHEMA, KEY ] )
		.stderr( Stdio::null() )
		.output()
		.ok()?;
	parse_factor( std::str::from_utf8( &out.stdout ).ok()? )
}

fn parse_factor( s: &str ) -> Option<f32>
{
	s.rsplit( [ ' ', ':' ] )
		.next()?
		.trim()
		.parse::<f32>()
		.ok()
		.filter( |v| *v > 0.0 )
}

#[ cfg( test ) ]
mod tests
{
	use super::parse_factor;

	#[ test ]
	fn parses_monitor_line_and_bare_value()
	{
		assert_eq!( parse_factor( "text-scaling-factor: 1.25" ), Some( 1.25 ) );
		assert_eq!( parse_factor( "1.0\n" ), Some( 1.0 ) );
		assert_eq!( parse_factor( "" ), None );
		assert_eq!( parse_factor( "text-scaling-factor: nope" ), None );
	}
}
