use pyo3::prelude::*;

#[derive(Debug, Default, Clone)]
#[pyclass]
enum ExportTyp {
    #[default]
    Regular,
    Reexport,
    Stub,
}

#[pymethods]
impl ExportTyp {
    fn __str__(&self) -> &'static str {
        match self {
            ExportTyp::Regular => "regular",
            ExportTyp::Reexport => "reexport",
            ExportTyp::Stub => "stub",
        }
    }
}

#[derive(Debug, Default, Clone)]
#[pyclass]
struct ExportInfo {
    #[pyo3(get)]
    typ: ExportTyp,
    #[pyo3(get)]
    address: u64,
    #[pyo3(get)]
    flags: u64,
    #[pyo3(get)]
    lib: Option<String>,
    #[pyo3(get)]
    lib_symbol_name: Option<String>,
}

impl From<goblin::mach::exports::ExportInfo<'_>> for ExportInfo {
    fn from(info: goblin::mach::exports::ExportInfo) -> Self {
        use goblin::mach::exports::ExportInfo::*;
        match info {
            Regular { address, flags } => Self {
                typ: ExportTyp::Regular,
                address,
                flags,
                ..Default::default()
            },
            Reexport {
                lib,
                lib_symbol_name,
                flags,
            } => Self {
                typ: ExportTyp::Reexport,
                lib: Some(lib.to_string()),
                lib_symbol_name: lib_symbol_name.map(|s| s.to_string()),
                flags,
                ..Default::default()
            },
            Stub { flags, .. } => Self {
                typ: ExportTyp::Stub,
                flags,
                ..Default::default()
            },
        }
    }
}

#[derive(Debug)]
#[pyclass]
pub struct Export {
    #[pyo3(get)]
    name: String,
    #[pyo3(get)]
    info: ExportInfo,
    #[pyo3(get)]
    size: usize,
    #[pyo3(get)]
    offset: u64,
}

#[pymethods]
impl Export {
    fn __repr__(&self) -> String {
        format!("{:?}", self)
    }
}

impl From<goblin::mach::exports::Export<'_>> for Export {
    fn from(export: goblin::mach::exports::Export) -> Self {
        Self {
            name: export.name,
            info: export.info.into(),
            size: export.size,
            offset: export.offset,
        }
    }
}