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

//! Theming for ltk-based applications.
//!
//! A *theme* is a directory on disk holding a `theme.json` and any
//! supporting assets (wallpapers, fonts, …). The JSON declares `light`
//! and `dark` modes — each with its own slot table plus wallpaper,
//! lockscreen, launcher and window-controls blocks — plus a shared
//! `fonts` registry. The shell picks which mode is active via
//! [`ThemeMode`].
//!
//! # On-disk layout
//!
//! ```text
//! /usr/share/ltk/themes/<id>/             (system overlay, lower priority)
//! ~/.local/share/ltk/themes/<id>/         (user overlay,   higher priority)
//!     theme.json
//!     branding/{light,dark}/              wallpaper, lockscreen, logos
//!     icons/apps/                         per-application icons
//!     icons/catalogue/{filled,line}/      symbolic glyph catalogue
//!     cursors/ + cursor.theme             consumed by the compositor
//! ```
//!
//! Paths inside `theme.json` are interpreted relative to the theme's
//! directory and are eagerly resolved to absolute paths at load time.
//!
//! # Process-wide active state
//!
//! The active theme is published process-wide so widgets can consult their
//! colours without every caller threading the palette through their own
//! state. Use [`set_active_document`] / [`set_active_mode`] to change it,
//! and [`active_document`] / [`active_mode`] / [`active_theme_id`] to read
//! it back. Per-slot shorthand accessors ([`color`], [`paint()`], [`surface()`],
//! [`palette()`], …) cover the common patterns without going through the
//! full document.
//!
//! When `ensure_active` cannot locate the `default` theme in any search
//! path, an embedded B/W fallback document is installed instead and the
//! process keeps running: [`is_fallback_active`] flips on, the draw path
//! stamps a red warning banner, and stderr points at the
//! `ltk-theme-default` Debian package (it `Provides: ltk-theme`) or at
//! the `LTK_THEMES_DIR` environment variable for development
//! installations.

use std::sync::{ Arc, OnceLock };

// ─── Submodules ──────────────────────────────────────────────────────────────
//
// Paint / Shadow / Surface / TextStyle are the building blocks of the
// slot-typed theme schema; the SlotStore (`slots`) indexes them by id;
// the JSON loader (`schema`) parses the on-disk shape. `document` holds
// the top-level `ThemeDocument` and per-mode `Mode` types. `fonts` +
// `font_registry` cover the typed font references and their
// runtime-loaded counterparts. `gradient_lut` is the small CPU helper
// the GPU gradient shaders consume.

pub mod paint;
pub mod shadow;
pub mod surface;
pub mod text_style;

pub mod fonts;
pub mod font_registry;
pub mod gradient_lut;
pub mod slots;
pub mod document;
pub ( crate ) mod schema;
pub ( crate ) mod fallback;

pub mod accessors;
pub mod active;
pub mod assets;
pub mod error;
pub mod palette;
pub mod prefs;
pub mod search;
pub mod typography;

pub use paint::{ ColorStop, GradientSpace, LinearGradient, Paint, RadialGradient };
pub use shadow::{ BlendMode, InsetShadow, Shadow, ShadowsRef };
pub use surface::Surface;
pub use text_style::{ FontRef, FontStyle, LineHeight, TextDecoration, TextStyle, TextTransform };

pub use fonts::{ FontFamilyDef, FontSource };
pub use font_registry::{ FontKey, FontLoadError, FontRegistry };
pub use slots::{ Metadata, Slot, SlotStore };
pub use document::{ Mode, ThemeDocument };

pub use accessors::{ color, color_or, paint, palette, resolve_surface, shadows, surface, text_style, window_controls };
pub use active::{ active_document, active_mode, active_theme_id, is_fallback_active, set_active_document, set_active_mode };
pub use assets::{ app_default_icon, app_icon, branding_asset, branding_image, branding_raster, decode_svg_bytes, icon_path, icon_rgba, launcher_icon, lockscreen, logo, logo_horizontal, logo_square, tint_symbolic, wallpaper };
pub use error::ThemeError;
pub use palette::Palette;
pub use prefs::{ LauncherSpec, ThemeMode, ThemePreference, WallpaperFit, WallpaperSpec, WindowControlsSpec };
pub use search::{ build_font_registry, search_paths };

/// Shared `usvg` font database, lazily populated from the host's system
/// fonts. resvg's default `Options::fontdb` is empty, so SVGs containing
/// `<text>` would otherwise rasterise with no glyphs at all.
pub ( crate ) fn system_fontdb() -> Arc<resvg::usvg::fontdb::Database>
{
	static DB: OnceLock<Arc<resvg::usvg::fontdb::Database>> = OnceLock::new();
	DB.get_or_init( || {
		let mut db = resvg::usvg::fontdb::Database::new();
		db.load_system_fonts();
		Arc::new( db )
	} ).clone()
}
