use crate::{error::{PdfMakeError, Result}, model::Alignment};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct DarkModule {
    pub x: usize,
    pub y: usize,
}

#[derive(Debug, Clone, PartialEq)]
pub struct QrMatrix {
    pub modules: usize,
    pub dark_modules: Vec<DarkModule>,
}

pub fn encode_qr(text: &str, ecc_level: Option<&str>, _mode: Option<&str>, version: Option<u32>, _mask: Option<u8>) -> Result<QrMatrix> {
    if text.is_empty() {
        return Err(PdfMakeError::InvalidQrContent);
    }
    let ecc = match ecc_level.unwrap_or("M") {
        "L" => qrcode::EcLevel::L,
        "M" => qrcode::EcLevel::M,
        "Q" => qrcode::EcLevel::Q,
        "H" => qrcode::EcLevel::H,
        _ => qrcode::EcLevel::M,
    };

    let code = if let Some(ver) = version {
        let qr_version = qrcode::Version::Normal(ver as i16);
        qrcode::QrCode::with_version(text.as_bytes(), qr_version, ecc)
            .map_err(|_| PdfMakeError::QrEncode)?
    } else {
        qrcode::QrCode::with_error_correction_level(text.as_bytes(), ecc)
            .map_err(|_| PdfMakeError::QrEncode)?
    };

    let width = code.width();
    let mut dark_modules = Vec::new();
    for y in 0..width {
        for x in 0..width {
            if code[(x, y)] == qrcode::Color::Dark {
                dark_modules.push(DarkModule { x, y });
            }
        }
    }
    Ok(QrMatrix { modules: width, dark_modules })
}

pub fn resolve_qr_size(fit: Option<f32>) -> Result<f32> {
    let size = fit.unwrap_or(96.0);
    if size <= 0.0 { return Err(PdfMakeError::InvalidImageDimensions); }
    Ok(size)
}

pub fn align_x(left: f32, available_width: f32, width: f32, alignment: Alignment) -> f32 {
    match alignment {
        Alignment::Left | Alignment::Justify => left,
        Alignment::Center => left + (available_width - width) / 2.0,
        Alignment::Right => left + available_width - width,
    }
}