//! Stage 4 — `RenderIR` (Chapter 7 §"RenderIR (Interface Only)").
//!
//! The renderer's input. Its full specification (page templates, draw calls,
//! rasterization) is delivered separately; this module defines only the
//! interface contract and the one obligation that crosses it: "every renderer
//! primitive MUST be traceable to its originating `ResolvedGlyph` (and therefore
//! to its score graph source)" (Chapter 7 §"RenderIR"). v0 implements that
//! interface — provenance and position flow through — and performs **no actual
//! rendering** (QUICKSTART, Agent E).

use crate::provenance::Provenance;
use crate::resolved::ResolvedLayoutIR;
use crate::spatial::{Point, ScaleContext};
use crate::{BoundingBox, GlyphReference, GlyphStyle, Stroke, Transform2D};

/// A single renderer primitive (Chapter 7 §"RenderIR"). Interface only — it
/// carries just enough to prove the provenance-preservation contract: every
/// primitive traces back to its `ResolvedGlyph`'s source.
#[derive(Clone, PartialEq, Debug)]
pub struct RenderPrimitive {
    pub provenance: Provenance,
    /// The SMuFL glyph to draw — what the renderer needs to know to produce
    /// output (Chapter 7 §"RenderIR": every primitive is traceable to its
    /// `ResolvedGlyph`, including its glyph reference).
    pub glyph: GlyphReference,
    pub position: Point,
    pub transform: Option<Transform2D>,
    pub bounding_box: BoundingBox,
    pub style: GlyphStyle,
    pub layer: i32,
}

/// The render IR interface output (Chapter 7 §"RenderIR").
#[derive(Clone, PartialEq, Debug)]
pub struct RenderIR {
    pub primitives: Vec<RenderPrimitive>,
    /// Non-glyph line primitives (staff lines, stems, barlines, …), traced like
    /// the glyph primitives so the round-trip recovers their sources too.
    pub strokes: Vec<Stroke>,
}

/// The render target (Chapter 7 §"RenderIR": `RenderConfiguration.target`).
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum RenderTarget {
    Pdf,
    Svg,
    Screen,
    Print,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ColorSpace {
    Srgb,
    DisplayP3,
    Cmyk,
    Grayscale,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct ColorConfiguration {
    pub color_space: ColorSpace,
    pub embed_profile: bool,
}

impl Default for ColorConfiguration {
    fn default() -> Self {
        ColorConfiguration {
            color_space: ColorSpace::Srgb,
            embed_profile: true,
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct RasterizationConfiguration {
    pub antialias: bool,
    pub dpi: u32,
}

impl Default for RasterizationConfiguration {
    fn default() -> Self {
        RasterizationConfiguration {
            antialias: true,
            dpi: 300,
        }
    }
}

/// Render configuration (Chapter 7 §"RenderIR": `RenderConfiguration`).
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct RenderConfiguration {
    pub target: RenderTarget,
    pub color: ColorConfiguration,
    pub rasterization: RasterizationConfiguration,
}

/// The render-projection interface (Chapter 7 §"RenderIR": `RenderIRProducer`).
/// The spec's `produce(resolved, scale, config)` signature is honored; v0
/// performs **no** rendering (the primitive vocabulary belongs to the
/// out-of-core renderer) but guarantees provenance and glyph identity flow
/// across the boundary.
pub trait RenderIRProducer {
    /// Converts resolved IR to renderer-bound primitives, preserving provenance.
    fn produce(
        &self,
        resolved: &ResolvedLayoutIR,
        scale: ScaleContext,
        config: RenderConfiguration,
    ) -> RenderIR;
}

/// The v0 render producer: one primitive per resolved glyph, provenance, glyph
/// identity, and position preserved, no rendering performed. The `scale` and
/// `config` are accepted (interface fidelity) but not consumed in v0.
pub struct PassthroughRenderProducer;

impl RenderIRProducer for PassthroughRenderProducer {
    fn produce(
        &self,
        resolved: &ResolvedLayoutIR,
        _scale: ScaleContext,
        _config: RenderConfiguration,
    ) -> RenderIR {
        to_render(resolved)
    }
}

/// The RenderIR interface call (Chapter 7 §"RenderIR"): one primitive per
/// resolved glyph, provenance and position preserved.
pub fn to_render(resolved: &ResolvedLayoutIR) -> RenderIR {
    RenderIR {
        primitives: resolved
            .glyphs
            .iter()
            .map(|g| RenderPrimitive {
                provenance: g.provenance.clone(),
                glyph: g.glyph.clone(),
                position: g.position,
                transform: g.transform,
                bounding_box: g.bounding_box,
                style: g.style,
                layer: g.layer,
            })
            .collect(),
        strokes: resolved.strokes.clone(),
    }
}
