//! Each parser produces a [`Part`] — the normalized cross-source representation
//! that [`crate::compare`] reasons over. Parsers MUST NOT do alias resolution or
//! tolerance fuzzing — that lives in compare.rs so it's one place.

pub mod altium;
pub mod ds2sf;
pub mod eagle;
pub mod kicad;

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Part {
    /// "ds2sf" | "kicad_sym+mod" | "eagle" | "altium" — used for hint phrasing.
    pub source: String,
    /// What identifier the source called this part. KiCad uses the first symbol
    /// name in the file; EAGLE uses the deviceset name; ds2sf uses symbolName.
    pub source_part_name: Option<String>,
    /// Pads from the footprint (mechanical pin numbers/letters: "1", "10", "A4").
    pub pads: Vec<Pad>,
    /// Symbol pins. For sources that link symbol→footprint (EAGLE deviceset),
    /// the pad field is populated. For sources where the symbol is numbered-only
    /// (KiCad UL stub bundles), name == number.
    pub pins: Vec<Pin>,
    /// Package metadata if discoverable from the source.
    pub package: Option<PackageInfo>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Pin {
    pub number: String,
    pub name: String,
    /// True when the source's pin "name" is just the pin number (UL stub case).
    /// Detected per-source so compare.rs can flag it without re-checking.
    pub is_stub_name: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Pad {
    pub number: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PackageInfo {
    /// As-found name. e.g. "VSSOP-10", "DGS0010A", "SOIC-8".
    pub raw_name: String,
    /// Body x in mm if discoverable.
    pub body_x_mm: Option<f64>,
    /// Body y in mm if discoverable.
    pub body_y_mm: Option<f64>,
}