//! Conversion from FFI PdfObj to native pdf::object types.
//!
//! Bridges the MuPDF-compatible pdf_object FFI layer with the native
//! micropdf pdf::object types used by write, font, and image modules.

use crate::ffi::pdf_object::types::{PDF_OBJECTS, PdfObjHandle, PdfObjType};
use crate::pdf::object::{Name, ObjRef, Object, PdfString};
use std::collections::HashMap;

/// Convert a PdfObjHandle to native Object if the handle is valid.
/// Returns None if the handle is invalid or conversion fails.
pub fn pdf_obj_to_object(handle: PdfObjHandle) -> Option<Object> {
    PDF_OBJECTS.get(handle).and_then(|arc| {
        arc.lock()
            .ok()
            .and_then(|guard| pdf_obj_type_to_object(&guard.obj_type))
    })
}

fn pdf_obj_type_to_object(ty: &PdfObjType) -> Option<Object> {
    match ty {
        PdfObjType::Null => Some(Object::Null),
        PdfObjType::Bool(b) => Some(Object::Bool(*b)),
        PdfObjType::Int(i) => Some(Object::Int(*i)),
        PdfObjType::Real(f) => Some(Object::Real(*f)),
        PdfObjType::Name(s) => Some(Object::Name(Name::new(s))),
        PdfObjType::String(data) => Some(Object::String(PdfString::new(data.clone()))),
        PdfObjType::Array(arr) => {
            let mut out = Vec::with_capacity(arr.len());
            for item in arr {
                pdf_obj_type_to_object(&item.obj_type).map(|o| out.push(o))?;
            }
            Some(Object::Array(out))
        }
        PdfObjType::Dict(entries) => {
            let mut map: HashMap<Name, Object> = HashMap::new();
            for (k, v) in entries {
                let key = Name::new(k);
                let val = pdf_obj_type_to_object(&v.obj_type)?;
                map.insert(key, val);
            }
            Some(Object::Dict(map))
        }
        PdfObjType::Indirect { num, generation } => {
            Some(Object::Ref(ObjRef::new(*num, *generation)))
        }
        PdfObjType::Stream { dict, data } => {
            let dict_obj = pdf_obj_type_to_object(&dict.obj_type)?;
            let dict_map = dict_obj.as_dict()?.clone();
            Some(Object::Stream {
                dict: dict_map,
                data: data.clone(),
            })
        }
    }
}

/// Convert a PdfObjHandle to native Dict if it contains a dictionary.
/// Returns None if the handle is invalid or not a dict.
pub fn pdf_obj_to_dict(handle: PdfObjHandle) -> Option<HashMap<Name, Object>> {
    PDF_OBJECTS.get(handle).and_then(|arc| {
        arc.lock().ok().and_then(|guard| {
            if let PdfObjType::Dict(entries) = &guard.obj_type {
                let mut map: HashMap<Name, Object> = HashMap::new();
                for (k, v) in entries {
                    let key = Name::new(k);
                    if let Some(val) = pdf_obj_type_to_object(&v.obj_type) {
                        map.insert(key, val);
                    }
                }
                Some(map)
            } else {
                None
            }
        })
    })
}
