//! Watch `org.gnome.desktop.interface color-scheme` for external changes.
//!
//! When the user flips dark mode from outside the shell — gnome-control-
//! center, a `gsettings set` from a terminal, a future settings app — neither
//! crustace nor forge would notice, because forge no longer polls gsettings
//! for the theme (that 30 s poll was clobbering the IPC value we just
//! pushed). This module closes that gap by spawning a thread around
//! `gsettings monitor`, parsing each stdout line, and pumping a
//! `Message::ExternalColorScheme` back into ltk's event loop so the
//! shell-wide handler can run `ltk::set_active_mode` + `ForgeIpc::set_theme`
//! in the usual way.

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

use ltk::ChannelSender;

use crate::message::Message;

/// Spawn the watcher thread. Returns silently if `gsettings` is missing —
/// the rest of the shell keeps working, we just lose the external-change
/// propagation path.
pub fn start( sender: ChannelSender<Message> )
{
	let _ = thread::Builder::new()
		.name( "color-scheme-watcher".into() )
		.spawn( move || run( sender ) );
}

fn run( sender: ChannelSender<Message> )
{
	let mut child = match Command::new( "gsettings" )
		.args( ["monitor", "org.gnome.desktop.interface", "color-scheme"] )
		.stdout( Stdio::piped() )
		.stderr( Stdio::null() )
		.spawn()
	{
		Ok( c )  => c,
		Err( e ) =>
		{
			tracing::warn!( "color-scheme watcher: could not spawn gsettings monitor: {}", e );
			return;
		}
	};

	let stdout = match child.stdout.take()
	{
		Some( s ) => s,
		None      => return,
	};

	// Each line `gsettings monitor` prints has the shape
	//   color-scheme: 'prefer-dark'
	// or
	//   color-scheme: 'default'
	// We only need to distinguish "prefer-dark" from everything else.
	for line in BufReader::new( stdout ).lines().flatten()
	{
		let mode = if line.contains( "prefer-dark" )
		{
			ltk::ThemeMode::Dark
		}
		else
		{
			ltk::ThemeMode::Light
		};

		if sender.send( Message::ExternalColorScheme( mode ) ).is_err()
		{
			// Receiver gone — shell is shutting down.
			break;
		}
	}

	// If `gsettings monitor` exits (rare), let it go; there's no value in
	// spinning up a restart loop against a tool that, if it died once,
	// will probably die again for the same reason.
	let _ = child.wait();
}
