use std::path::Path;

use crate::error::{PixstripError, Result};
use crate::types::{Dimensions, ImageFormat};

#[derive(Debug, Clone)]
pub struct ImageInfo {
    pub dimensions: Dimensions,
    pub format: Option<ImageFormat>,
    pub file_size: u64,
}

pub struct ImageLoader;

impl ImageLoader {
    pub fn new() -> Self {
        Self
    }

    pub fn load_info(&self, path: &Path) -> Result<ImageInfo> {
        let metadata = std::fs::metadata(path).map_err(|e| PixstripError::ImageLoad {
            path: path.to_path_buf(),
            reason: e.to_string(),
        })?;

        let reader =
            image::ImageReader::open(path).map_err(|e| PixstripError::ImageLoad {
                path: path.to_path_buf(),
                reason: e.to_string(),
            })?;

        let reader = reader.with_guessed_format().map_err(|e| PixstripError::ImageLoad {
            path: path.to_path_buf(),
            reason: e.to_string(),
        })?;

        // Read only the image header for dimensions (avoids full decode into RAM)
        let (width, height) = reader.into_dimensions().map_err(|e| PixstripError::ImageLoad {
            path: path.to_path_buf(),
            reason: e.to_string(),
        })?;

        let format = path
            .extension()
            .and_then(|ext| ext.to_str())
            .and_then(ImageFormat::from_extension);

        Ok(ImageInfo {
            dimensions: Dimensions { width, height },
            format,
            file_size: metadata.len(),
        })
    }

    pub fn load_pixels(&self, path: &Path) -> Result<image::DynamicImage> {
        image::open(path).map_err(|e| PixstripError::ImageLoad {
            path: path.to_path_buf(),
            reason: e.to_string(),
        })
    }
}

impl Default for ImageLoader {
    fn default() -> Self {
        Self::new()
    }
}
