//! XDG-based path resolution.
//!
//! We separate "where state lives" from "where the daemon runs", so tests
//! can substitute a `Paths` value pointing at a tempdir.

use std::path::{ Path, PathBuf };

use anyhow::{ Context, Result, anyhow };
use directories::BaseDirs;

#[ derive( Debug, Clone ) ]
pub struct Paths
{
	/// `$XDG_DATA_HOME/liberux/contacts` — holds `contacts.db`.
	pub data_dir: PathBuf,

	/// `$XDG_CONFIG_HOME/liberux/contacts` — holds the auth token, opt-out
	/// flags, and any other persistent config.
	pub config_dir: PathBuf,

	/// `$XDG_RUNTIME_DIR/liberux` — `contacts.port` lives here. `None` on
	/// systems that don't expose a runtime dir (very rare on a session bus).
	pub runtime_dir: Option<PathBuf>,

	pub contacts_db: PathBuf,
	pub token_file: PathBuf,

	/// `$XDG_CONFIG_HOME/evolution/sources` — used by EDS. We never create
	/// this directory; its existence is also our "is EDS installed" signal.
	pub eds_sources_dir: PathBuf,

	/// Marker file the user creates to disable EDS auto-registration.
	pub no_eds_autoregister: PathBuf,

	/// `$XDG_RUNTIME_DIR/liberux/contacts.port` (when runtime_dir is set).
	pub port_file: Option<PathBuf>,
}

impl Paths
{
	pub fn resolve() -> Result<Self>
	{
		let base = BaseDirs::new().ok_or_else( || anyhow!( "no XDG base dirs available" ) )?;
		Ok( Self::from_base( &base ) )
	}

	pub fn from_base( base: &BaseDirs ) -> Self
	{
		let data_dir   = base.data_dir().join( "liberux/contacts" );
		let config_dir = base.config_dir().join( "liberux/contacts" );
		let runtime_dir = base.runtime_dir().map( |p| p.join( "liberux" ) );

		let contacts_db        = data_dir.join( "contacts.db" );
		let token_file         = config_dir.join( "token" );
		let no_eds_autoregister = config_dir.join( "no-eds-autoregister" );
		let eds_sources_dir    = base.config_dir().join( "evolution/sources" );
		let port_file          = runtime_dir.as_ref().map( |p| p.join( "contacts.port" ) );

		Self
		{
			data_dir, config_dir, runtime_dir,
			contacts_db, token_file, eds_sources_dir,
			no_eds_autoregister, port_file,
		}
	}

	/// Build a `Paths` rooted at `root`. Used by tests to keep state out of
	/// the user's real XDG dirs.
	pub fn under_root( root: &Path ) -> Self
	{
		let data_dir   = root.join( "data/liberux/contacts" );
		let config_dir = root.join( "config/liberux/contacts" );
		let runtime    = root.join( "runtime/liberux" );

		Self
		{
			contacts_db:         data_dir.join( "contacts.db" ),
			token_file:          config_dir.join( "token" ),
			no_eds_autoregister: config_dir.join( "no-eds-autoregister" ),
			eds_sources_dir:     root.join( "config/evolution/sources" ),
			port_file:           Some( runtime.join( "contacts.port" ) ),
			data_dir,
			config_dir,
			runtime_dir:         Some( runtime ),
		}
	}

	/// Create the directories we are responsible for (`data_dir`,
	/// `config_dir`, `runtime_dir`). We never create `eds_sources_dir`.
	pub fn ensure_dirs( &self ) -> Result<()>
	{
		std::fs::create_dir_all( &self.data_dir )
			.with_context( || format!( "creating {}", self.data_dir.display() ) )?;
		std::fs::create_dir_all( &self.config_dir )
			.with_context( || format!( "creating {}", self.config_dir.display() ) )?;
		if let Some( rt ) = &self.runtime_dir
		{
			std::fs::create_dir_all( rt )
				.with_context( || format!( "creating {}", rt.display() ) )?;
		}
		Ok( () )
	}
}
