//! MPRIS media state, split by concern:
//! - `service`: the playerctl poller and the D-Bus player controls.
//! - `view`: the media-widget rendering and hit-testing.
//! - this module: the model (current `MediaInfo`) and its wiring.

use calloop::LoopHandle;

use crate::drawing::{RenderTexture, Texture};
use crate::forge::Forge;

mod service;
mod view;

const MEDIA_BG_RGBA: [u8; 4] = [35, 35, 35, 230];

#[derive(Debug, Clone)]
pub struct MediaInfo {
    pub title: String,
    pub artist: String,
    pub playing: bool,
    pub available: bool,
    /// Cover art URL from MPRIS metadata (mpris:artUrl).
    pub art_url: Option<String>,
}

impl Default for MediaInfo {
    fn default() -> Self {
        Self {
            title: String::new(),
            artist: String::new(),
            playing: false,
            available: false,
            art_url: None,
        }
    }
}

pub struct MprisState {
    pub media: MediaInfo,
    dirty: bool,
    last_scale: f64,

    bg_texture: RenderTexture,
    title_texture: Option<RenderTexture>,
    artist_texture: Option<RenderTexture>,
    controls_texture: Option<RenderTexture>,
    /// Cached cover art texture.
    cover_texture: Option<RenderTexture>,
    /// URL of the cover art that was last loaded (to avoid reloading).
    cover_loaded_url: Option<String>,
}

impl MprisState {
    pub fn new() -> Self {
        Self {
            media: MediaInfo::default(),
            dirty: true,
            last_scale: 0.0,
            bg_texture: RenderTexture::new(Texture::from_color(MEDIA_BG_RGBA, true)),
            title_texture: None,
            artist_texture: None,
            controls_texture: None,
            cover_texture: None,
            cover_loaded_url: None,
        }
    }

    /// Start MPRIS D-Bus listener in a background thread.
    pub fn start_listener(event_loop: &LoopHandle<'static, Forge>) {
        crate::services::dbus_worker::spawn_adapter(
            event_loop,
            "forge-mpris",
            service::run_mpris_listener,
            |info, forge| {
                forge.shell.mpris.media = info;
                forge.shell.mpris.dirty = true;
                forge.windows.set_dirty();
                forge.unstall();
            },
        );
    }

    /// Send play/pause command to the active MPRIS player.
    pub fn play_pause() {
        service::mpris_player_call("PlayPause");
    }

    /// Send next track command.
    pub fn next() {
        service::mpris_player_call("Next");
    }

    /// Send previous track command.
    pub fn previous() {
        service::mpris_player_call("Previous");
    }

    pub fn invalidate(&mut self) {
        self.dirty = true;
    }
}
