//! Wallpaper on `Windows`: load, scale and bake the desktop background texture
//! for the primary screen (extend screens keep their own in `extra_wallpapers`).

use std::path::PathBuf;

use super::*;

impl Windows {
    /// Load wallpaper texture if not already loaded, or reload on scale change.
    pub(super) fn ensure_wallpaper(&mut self, renderer: &mut GlesRenderer) {
        let scale = self.canvas.scale();
        if self.wallpaper_loaded && (self.wallpaper_scale - scale).abs() < 0.01 {
            return;
        }
        self.wallpaper_loaded = true;
        self.wallpaper_scale = scale;
        self.wallpaper = Self::bake_wallpaper(renderer, scale, self.canvas.physical_size());
    }

    /// Rasterise the wallpaper file cover-cropped to one screen's physical
    /// size. `None` when there is no file, it fails to decode, or the size
    /// is degenerate.
    pub(super) fn bake_wallpaper(
        renderer: &mut GlesRenderer,
        scale: f64,
        phys_size: Size<i32, Physical>,
    ) -> Option<RenderTexture> {
        let path = Self::find_wallpaper()?;
        let img = image::open(&path).ok()?.into_rgba8();

        let (tw, th) = (phys_size.w as u32, phys_size.h as u32);
        if tw == 0 || th == 0 {
            return None;
        }

        let (iw, ih) = img.dimensions();
        // Scale to cover (crop excess)
        let sx = tw as f64 / iw as f64;
        let sy = th as f64 / ih as f64;
        let s = sx.max(sy);
        let sw = (iw as f64 * s) as u32;
        let sh = (ih as f64 * s) as u32;
        let ox = (sw.saturating_sub(tw)) / 2;
        let oy = (sh.saturating_sub(th)) / 2;

        let mut buf = vec![0u8; (tw * th * 4) as usize];
        for y in 0..th {
            for x in 0..tw {
                let src_x = ((x + ox) as f64 / s) as u32;
                let src_y = ((y + oy) as f64 / s) as u32;
                let src_x = src_x.min(iw - 1);
                let src_y = src_y.min(ih - 1);
                let src_off = ((src_y * iw + src_x) * 4) as usize;
                let dst_off = ((y * tw + x) * 4) as usize;
                buf[dst_off..dst_off + 4].copy_from_slice(&img.as_raw()[src_off..src_off + 4]);
            }
        }

        let tex = Texture::from_buffer(renderer, scale, &buf, tw as i32, th as i32, true);
        Some(RenderTexture::new(tex))
    }

    fn find_wallpaper() -> Option<PathBuf> {
        let config_dir = dirs::config_dir()?.join("forge");
        for name in &["wallpaper.png", "wallpaper.jpg", "wallpaper.jpeg"] {
            let p = config_dir.join(name);
            if p.exists() {
                return Some(p);
            }
        }
        None
    }
}
