//! Binary entry point for the Print Platform Pro Browser Linux UI app.
//!
//! Wires three things together:
//!
//!  1. The GResource bundle (UI XML + icons + CSS), embedded via a
//!     `gresources!` link at compile time and registered with GIO
//!     at startup so `ui/window.ui` etc. resolve.
//!
//!  2. The D-Bus client to the Go agent (`AgentClient`). One
//!     instance shared by the application + every page.
//!
//!  3. The system-tray (SNI) on a background thread, sending
//!     `TrayCommand`s back over an `mpsc::channel` that we drain on
//!     the GTK main loop.

mod about;
mod application;
mod dbus;
mod dbus_signals;
mod demos;
mod dims;
mod logs;
mod origins;
mod printers;
mod settings;
mod test_prints;
mod window;

use anyhow::{Context, Result};
use application::ZbplApplication;
use dbus::AgentClient;
use gtk::gio;
use gtk::prelude::*;
use std::rc::Rc;

// The UI's GtkApplication ID. Distinct from the agent's D-Bus bus
// name (also "com.printplatformpro.BrowserAgent") because they
// share the session bus and would collide otherwise — GtkApplication
// fails to register actions when a non-Gtk peer already owns the
// name. The `.UI` suffix gives us our own slot.
const APP_ID: &str = "com.printplatformpro.BrowserAgent.UI";
const GETTEXT_PACKAGE: &str = "pppro-browser-linux-ui";

fn main() -> Result<()> {
    tracing_subscriber::fmt()
        .with_env_filter(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
        )
        .init();

    // Wire gettext so the `gettext()` calls in the page modules and
    // the `_("…")` markers in the compiled .ui resources resolve to
    // the user's locale at runtime. Locale files live under
    // $prefix/share/locale by default; ZBPL_LOCALE_DIR overrides
    // for dev builds where translations sit beside the source tree.
    let locale_dir = std::env::var("ZBPL_LOCALE_DIR")
        .unwrap_or_else(|_| "/usr/share/locale".to_string());
    gettextrs::setlocale(gettextrs::LocaleCategory::LcAll, "");
    gettextrs::bindtextdomain(GETTEXT_PACKAGE, locale_dir).ok();
    gettextrs::bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8").ok();
    gettextrs::textdomain(GETTEXT_PACKAGE).ok();

    // Register the embedded GResource bundle. The build system
    // (meson) compiles `data/resources.gresource.xml` into a
    // `.gresource` blob and `include_bytes!` slurps it into the
    // binary at compile time.
    let resource_bytes = include_bytes!(concat!(env!("OUT_DIR"), "/resources.gresource"));
    let bytes = glib::Bytes::from_static(resource_bytes);
    let resource = gio::Resource::from_data(&bytes).context("load resource bundle")?;
    gio::resources_register(&resource);

    adw::init().context("adw::init")?;

    // Tell GTK which icon to use for every window we create. Looks
    // up `com.printplatformpro.BrowserAgent` in the hicolor theme
    // (installed by the .rpm/.deb under /usr/share/icons/hicolor/
    // scalable/apps/). Without this the WM falls back to a generic
    // "preferences-system" cog because GtkApplication's app-id
    // includes a `.UI` suffix the icon files don't match exactly.
    gtk::Window::set_default_icon_name("com.printplatformpro.BrowserAgent");

    // Connect to the agent's D-Bus interface eagerly — failing
    // early is fine, the user gets a clear error message rather
    // than a half-rendered window with empty fields.
    let agent = AgentClient::connect()
        .context("connect to Print Platform Pro Browser agent on session D-Bus")?;
    // Auto-start the agent if it isn't running — covers the case
    // where the user quit it from the tray and re-opens Settings
    // expecting it to come back. No-op when the agent is already up.
    agent.ensure_running();
    let agent = Rc::new(agent);

    let app = ZbplApplication::new(APP_ID, agent);

    // No in-UI tray any more (v0.3.3). The agent has its own tray
    // icon (libayatana-appindicator) which can re-open this UI on
    // demand; running two trays for one product was confusing.

    // Spawn the D-Bus signal subscriber so OriginPendingApproval
    // events from the agent can pop a native AdwAlertDialog.
    // Failure to subscribe is non-fatal — agent might not be
    // running yet at app startup; the UI's Connected/Disconnected
    // status banner already covers that case.
    match dbus_signals::spawn() {
        Ok(rx) => app.install_signal_drain(rx),
        Err(e) => tracing::warn!("dbus signal subscription failed (will retry on next launch): {e:?}"),
    }

    // GTK takes the args itself (e.g. --gtk-debug); pass through
    // raw env::args.
    let exit = app.run();
    if exit != glib::ExitCode::SUCCESS {
        std::process::exit(exit.value());
    }
    Ok(())
}

use gtk::glib;
