//! Immutable frames, aligned plane storage, and typed plane views.

use std::alloc::{Layout, alloc_zeroed, dealloc, handle_alloc_error};
use std::marker::PhantomData;
use std::ptr::NonNull;
use std::sync::Arc;

use crate::{
    ErrorCategory, ErrorCode, FormatDescriptor, Metadata, MetadataSchema, PixelFlowError, Result,
    SampleType,
};

/// Sample marker trait for supported plane sample types.
pub trait Sample: sealed::Sealed + Copy + 'static {
    /// Matching storage sample type.
    const SAMPLE_TYPE: SampleType;
}

mod sealed {
    pub trait Sealed {}

    impl Sealed for u8 {}
    impl Sealed for u16 {}
    impl Sealed for f32 {}
}

impl Sample for u8 {
    const SAMPLE_TYPE: SampleType = SampleType::U8;
}

impl Sample for u16 {
    const SAMPLE_TYPE: SampleType = SampleType::U16;
}

impl Sample for f32 {
    const SAMPLE_TYPE: SampleType = SampleType::F32;
}

/// Runtime allocator configuration for frame plane buffers.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AllocatorConfig {
    alignment: usize,
}

impl AllocatorConfig {
    /// Creates allocator config with requested alignment.
    #[must_use]
    pub const fn new(alignment: usize) -> Self {
        Self { alignment }
    }

    /// Returns actual alignment used for allocations.
    #[must_use]
    pub const fn actual_alignment(self) -> usize {
        let requested = if self.alignment < 64 {
            64
        } else {
            self.alignment
        };

        if requested.is_power_of_two() {
            requested
        } else {
            requested.next_power_of_two()
        }
    }
}

impl Default for AllocatorConfig {
    fn default() -> Self {
        Self { alignment: 64 }
    }
}

#[derive(Debug)]
struct AlignedBuffer {
    ptr: NonNull<u8>,
    len: usize,
    alignment: usize,
}

// SAFETY: AlignedBuffer owns a heap allocation and exposes raw pointers only through APIs that
// preserve aliasing rules. Shared access is read-only unless unique ownership is proven with
// Arc::get_mut, so sending or sharing between threads is safe.
unsafe impl Send for AlignedBuffer {}
// SAFETY: Same reasoning as Send; no interior mutability and deallocation happens once in Drop.
unsafe impl Sync for AlignedBuffer {}

impl AlignedBuffer {
    fn new_zeroed(len: usize, config: AllocatorConfig) -> Self {
        let alignment = config.actual_alignment();
        let layout = Layout::from_size_align(len.max(1), alignment)
            .expect("alignment must be non-zero power of two");
        // SAFETY: `layout` has valid non-zero size and power-of-two alignment.
        let ptr = unsafe { alloc_zeroed(layout) };
        let ptr = NonNull::new(ptr).unwrap_or_else(|| handle_alloc_error(layout));

        Self {
            ptr,
            len,
            alignment,
        }
    }

    const fn as_ptr(&self) -> *const u8 {
        self.ptr.as_ptr()
    }

    const fn as_mut_ptr(&mut self) -> *mut u8 {
        // SAFETY: `NonNull<u8>` always points to live allocation owned by `self`, and method
        // requires `&mut self`, so returning mutable pointer does not create aliased mutable refs.
        unsafe { self.ptr.as_mut() }
    }
}

impl Drop for AlignedBuffer {
    fn drop(&mut self) {
        let layout = Layout::from_size_align(self.len.max(1), self.alignment)
            .expect("stored allocation layout must remain valid");
        // SAFETY: buffer was allocated with exact same layout in `new_zeroed`.
        unsafe {
            dealloc(self.ptr.as_ptr(), layout);
        }
    }
}

#[derive(Clone, Debug)]
struct PlaneStorage {
    buffer: Arc<AlignedBuffer>,
    sample_type: SampleType,
}

#[derive(Clone, Debug)]
struct PlaneView {
    storage: PlaneStorage,
    offset_bytes: usize,
    stride_bytes: usize,
    width: usize,
    height: usize,
}

/// Raw immutable plane view used by expert Rust and C ABI adapters.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RawPlane {
    /// Plane start pointer.
    pub ptr: *const u8,
    /// Stride in bytes.
    pub stride_bytes: usize,
    /// Visible width in samples.
    pub width: usize,
    /// Visible height in rows.
    pub height: usize,
    /// Plane storage sample type.
    pub sample_type: SampleType,
}

/// Raw mutable plane view used by expert builders and C ABI adapters.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RawPlaneMut {
    /// Plane start pointer.
    pub ptr: *mut u8,
    /// Stride in bytes.
    pub stride_bytes: usize,
    /// Visible width in samples.
    pub width: usize,
    /// Visible height in rows.
    pub height: usize,
    /// Plane storage sample type.
    pub sample_type: SampleType,
}

/// Immutable ref-counted frame handle.
#[derive(Clone)]
pub struct Frame {
    format: FormatDescriptor,
    width: usize,
    height: usize,
    planes: Vec<PlaneView>,
    metadata: Metadata,
    alignment: usize,
}

/// Builder used for explicit output allocation and writes.
pub struct FrameBuilder {
    format: FormatDescriptor,
    width: usize,
    height: usize,
    planes: Vec<PlaneView>,
    metadata: Metadata,
    alignment: usize,
}

/// Typed immutable plane view.
#[derive(Debug)]
pub struct Plane<T: Sample> {
    view: PlaneView,
    _sample: PhantomData<T>,
}

/// Typed mutable plane view available while building outputs.
#[derive(Debug)]
pub struct PlaneMut<'a, T: Sample> {
    view: &'a mut PlaneView,
    _sample: PhantomData<&'a mut T>,
}

/// Iterator over immutable typed plane rows.
pub struct PlaneRows<'a, T: Sample> {
    plane: &'a Plane<T>,
    next_row: usize,
}

impl FrameBuilder {
    /// Allocates explicit output buffers for a frame.
    pub fn new(
        format: FormatDescriptor,
        width: usize,
        height: usize,
        schema: &MetadataSchema,
        allocator: AllocatorConfig,
    ) -> Result<Self> {
        if width == 0 || height == 0 {
            return Err(PixelFlowError::new(
                ErrorCategory::Core,
                ErrorCode::new("frame.invalid_dimensions"),
                "frame dimensions must be non-zero",
            ));
        }

        let alignment = allocator.actual_alignment();
        let mut planes = Vec::with_capacity(format.planes().len());

        for descriptor in format.planes() {
            let plane_width = div_ceil(width, descriptor.width_divisor)?;
            let plane_height = div_ceil(height, descriptor.height_divisor)?;
            let row_bytes = plane_width
                .checked_mul(descriptor.sample_type.bytes_per_sample())
                .ok_or_else(|| {
                    PixelFlowError::new(
                        ErrorCategory::Core,
                        ErrorCode::new("frame.allocation_overflow"),
                        "row byte size overflowed",
                    )
                })?;
            let stride_bytes = align_up(row_bytes, alignment)?;
            let buffer_len = stride_bytes.checked_mul(plane_height).ok_or_else(|| {
                PixelFlowError::new(
                    ErrorCategory::Core,
                    ErrorCode::new("frame.allocation_overflow"),
                    "plane allocation size overflowed",
                )
            })?;

            let storage = PlaneStorage {
                buffer: Arc::new(AlignedBuffer::new_zeroed(buffer_len, allocator)),
                sample_type: descriptor.sample_type,
            };

            planes.push(PlaneView {
                storage,
                offset_bytes: 0,
                stride_bytes,
                width: plane_width,
                height: plane_height,
            });
        }

        Ok(Self {
            format,
            width,
            height,
            planes,
            metadata: Metadata::new(schema),
            alignment,
        })
    }

    /// Returns actual allocation alignment.
    #[must_use]
    pub const fn actual_alignment(&self) -> usize {
        self.alignment
    }

    /// Returns typed mutable plane view.
    pub fn plane_mut<T: Sample>(&mut self, index: usize) -> Result<PlaneMut<'_, T>> {
        let view = self
            .planes
            .get_mut(index)
            .ok_or_else(|| plane_index_error(index))?;

        if view.storage.sample_type != T::SAMPLE_TYPE {
            return Err(sample_mismatch_error(
                view.storage.sample_type,
                T::SAMPLE_TYPE,
            ));
        }

        Ok(PlaneMut {
            view,
            _sample: PhantomData,
        })
    }

    /// Finishes builder and returns immutable frame handle.
    #[must_use]
    pub fn finish(self) -> Frame {
        Frame {
            format: self.format,
            width: self.width,
            height: self.height,
            planes: self.planes,
            metadata: self.metadata,
            alignment: self.alignment,
        }
    }
}

impl Frame {
    /// Returns frame format descriptor.
    #[must_use]
    pub const fn format(&self) -> &FormatDescriptor {
        &self.format
    }

    /// Returns frame width.
    #[must_use]
    pub const fn width(&self) -> usize {
        self.width
    }

    /// Returns frame height.
    #[must_use]
    pub const fn height(&self) -> usize {
        self.height
    }

    /// Returns frame metadata.
    #[must_use]
    pub const fn metadata(&self) -> &Metadata {
        &self.metadata
    }

    /// Returns actual alignment used for this frame allocation.
    #[must_use]
    pub const fn actual_alignment(&self) -> usize {
        self.alignment
    }

    /// Returns typed immutable plane view.
    pub fn plane<T: Sample>(&self, index: usize) -> Result<Plane<T>> {
        let view = self
            .planes
            .get(index)
            .ok_or_else(|| plane_index_error(index))?;

        if view.storage.sample_type != T::SAMPLE_TYPE {
            return Err(sample_mismatch_error(
                view.storage.sample_type,
                T::SAMPLE_TYPE,
            ));
        }

        Ok(Plane {
            view: view.clone(),
            _sample: PhantomData,
        })
    }

    /// Creates frame clone that shares all plane buffers and replaces metadata.
    #[must_use]
    pub fn with_metadata(&self, metadata: Metadata) -> Self {
        Self {
            format: self.format.clone(),
            width: self.width,
            height: self.height,
            planes: self.planes.clone(),
            metadata,
            alignment: self.alignment,
        }
    }

    /// Returns true when both frames share same backing storage for a plane index.
    #[must_use]
    pub fn shares_plane_storage(&self, other: &Self, plane_index: usize) -> bool {
        self.shares_plane_storage_at(plane_index, other, plane_index)
    }

    /// Returns true when selected planes share the same backing storage.
    #[must_use]
    pub fn shares_plane_storage_at(
        &self,
        plane_index: usize,
        other: &Self,
        other_plane_index: usize,
    ) -> bool {
        match (
            self.planes.get(plane_index),
            other.planes.get(other_plane_index),
        ) {
            (Some(left), Some(right)) => Arc::ptr_eq(&left.storage.buffer, &right.storage.buffer),
            _ => false,
        }
    }

    /// Creates zero-copy crop-like view over parent plane storage.
    pub fn view(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
        if width == 0 || height == 0 {
            return Err(PixelFlowError::new(
                ErrorCategory::Core,
                ErrorCode::new("frame.invalid_view"),
                "view dimensions must be non-zero",
            ));
        }
        if left.checked_add(width).is_none_or(|r| r > self.width)
            || top.checked_add(height).is_none_or(|b| b > self.height)
        {
            return Err(PixelFlowError::new(
                ErrorCategory::Core,
                ErrorCode::new("frame.invalid_view"),
                "view rectangle is outside frame bounds",
            ));
        }

        let mut planes = Vec::with_capacity(self.planes.len());
        for (descriptor, source) in self.format.planes().iter().zip(&self.planes) {
            let plane_left = left / descriptor.width_divisor;
            let plane_top = top / descriptor.height_divisor;
            let plane_width = div_ceil(width, descriptor.width_divisor)?;
            let plane_height = div_ceil(height, descriptor.height_divisor)?;
            let sample_offset = plane_left
                .checked_mul(descriptor.sample_type.bytes_per_sample())
                .ok_or_else(|| {
                    PixelFlowError::new(
                        ErrorCategory::Core,
                        ErrorCode::new("frame.offset_overflow"),
                        "plane sample offset overflowed",
                    )
                })?;
            let row_offset = plane_top.checked_mul(source.stride_bytes).ok_or_else(|| {
                PixelFlowError::new(
                    ErrorCategory::Core,
                    ErrorCode::new("frame.offset_overflow"),
                    "plane row offset overflowed",
                )
            })?;
            let offset_bytes = source
                .offset_bytes
                .checked_add(row_offset)
                .and_then(|value| value.checked_add(sample_offset))
                .ok_or_else(|| {
                    PixelFlowError::new(
                        ErrorCategory::Core,
                        ErrorCode::new("frame.offset_overflow"),
                        "plane view offset overflowed",
                    )
                })?;

            planes.push(PlaneView {
                storage: source.storage.clone(),
                offset_bytes,
                stride_bytes: source.stride_bytes,
                width: plane_width,
                height: plane_height,
            });
        }

        Ok(Self {
            format: self.format.clone(),
            width,
            height,
            planes,
            metadata: self.metadata.clone(),
            alignment: self.alignment,
        })
    }

    /// Creates a zero-copy frame containing one source plane as plane 0 of `format`.
    pub fn single_plane_view(&self, plane_index: usize, format: FormatDescriptor) -> Result<Self> {
        let view = self.plane_view(plane_index)?;

        Self::from_plane_sources(
            format,
            view.width,
            view.height,
            &[(self, plane_index)],
            self.metadata.clone(),
        )
    }

    /// Creates a zero-copy frame from existing plane storage.
    pub fn from_plane_sources(
        format: FormatDescriptor,
        width: usize,
        height: usize,
        sources: &[(&Self, usize)],
        metadata: Metadata,
    ) -> Result<Self> {
        if width == 0 || height == 0 {
            return Err(PixelFlowError::new(
                ErrorCategory::Core,
                ErrorCode::new("frame.invalid_dimensions"),
                "frame dimensions must be non-zero",
            ));
        }
        if sources.len() != format.planes().len() {
            return Err(PixelFlowError::new(
                ErrorCategory::Core,
                ErrorCode::new("frame.plane_count_mismatch"),
                format!(
                    "format '{}' requires {} planes, got {}",
                    format.name(),
                    format.planes().len(),
                    sources.len()
                ),
            ));
        }

        let mut planes = Vec::with_capacity(sources.len());
        let mut alignment = usize::MAX;
        for (descriptor, (source, plane_index)) in format.planes().iter().zip(sources.iter()) {
            let source_view = source.plane_view(*plane_index)?.clone();
            let expected_width = div_ceil(width, descriptor.width_divisor)?;
            let expected_height = div_ceil(height, descriptor.height_divisor)?;
            if source_view.width != expected_width || source_view.height != expected_height {
                return Err(PixelFlowError::new(
                    ErrorCategory::Core,
                    ErrorCode::new("frame.plane_shape_mismatch"),
                    format!(
                        "plane role {:?} requires {}x{}, got {}x{}",
                        descriptor.role,
                        expected_width,
                        expected_height,
                        source_view.width,
                        source_view.height
                    ),
                ));
            }
            if source_view.storage.sample_type != descriptor.sample_type {
                return Err(sample_mismatch_error(
                    source_view.storage.sample_type,
                    descriptor.sample_type,
                ));
            }

            alignment = alignment.min(source.actual_alignment());
            planes.push(source_view);
        }

        Ok(Self {
            format,
            width,
            height,
            planes,
            metadata,
            alignment,
        })
    }

    fn plane_view(&self, index: usize) -> Result<&PlaneView> {
        self.planes
            .get(index)
            .ok_or_else(|| plane_index_error(index))
    }

    /// Returns raw pointer and stride view for expert Rust and ABI adapters.
    ///
    /// # Safety
    /// Caller must honor plane bounds from `height` and `stride_bytes`, and must interpret sample
    /// values using returned `sample_type`. Pointer remains valid only while frame storage remains
    /// alive through this frame or another shared owner.
    pub unsafe fn raw_plane(&self, index: usize) -> Result<RawPlane> {
        let view = self
            .planes
            .get(index)
            .ok_or_else(|| plane_index_error(index))?;

        Ok(RawPlane {
            ptr: view
                .storage
                .buffer
                .as_ptr()
                .wrapping_add(view.offset_bytes)
                .cast::<u8>(),
            stride_bytes: view.stride_bytes,
            width: view.width,
            height: view.height,
            sample_type: view.storage.sample_type,
        })
    }
}

impl<T: Sample> Plane<T> {
    /// Returns visible plane width in samples.
    #[must_use]
    pub const fn width(&self) -> usize {
        self.view.width
    }

    /// Returns visible plane height in rows.
    #[must_use]
    pub const fn height(&self) -> usize {
        self.view.height
    }

    /// Returns immutable row slice by row index.
    #[must_use]
    pub fn row(&self, row: usize) -> Option<&[T]> {
        if row >= self.view.height {
            return None;
        }

        Some(typed_row(&self.view, row))
    }

    /// Iterates over visible row slices.
    #[must_use]
    pub const fn rows(&self) -> PlaneRows<'_, T> {
        PlaneRows {
            plane: self,
            next_row: 0,
        }
    }
}

impl<'a, T: Sample> PlaneMut<'a, T> {
    /// Returns visible plane width in samples.
    #[must_use]
    pub const fn width(&self) -> usize {
        self.view.width
    }

    /// Returns visible plane height in rows.
    #[must_use]
    pub const fn height(&self) -> usize {
        self.view.height
    }

    /// Returns mutable row slice by row index.
    #[must_use]
    pub fn row_mut(&mut self, row: usize) -> Option<&mut [T]> {
        if row >= self.view.height {
            return None;
        }

        Some(typed_row_mut(self.view, row))
    }

    /// Returns raw mutable pointer and plane shape for expert code.
    #[must_use]
    pub fn raw_parts(&mut self) -> RawPlaneMut {
        RawPlaneMut {
            ptr: self.view.storage_mut_ptr(),
            stride_bytes: self.view.stride_bytes,
            width: self.view.width,
            height: self.view.height,
            sample_type: self.view.storage.sample_type,
        }
    }
}

impl<'a, T: Sample> Iterator for PlaneRows<'a, T> {
    type Item = &'a [T];

    fn next(&mut self) -> Option<Self::Item> {
        let row = self.plane.row(self.next_row)?;
        self.next_row += 1;
        Some(row)
    }
}

fn div_ceil(value: usize, divisor: usize) -> Result<usize> {
    if divisor == 0 {
        return Err(PixelFlowError::new(
            ErrorCategory::Core,
            ErrorCode::new("frame.invalid_divisor"),
            "plane divisor must be non-zero",
        ));
    }

    Ok(value.div_ceil(divisor))
}

fn align_up(value: usize, alignment: usize) -> Result<usize> {
    let mask = alignment.checked_sub(1).ok_or_else(|| {
        PixelFlowError::new(
            ErrorCategory::Core,
            ErrorCode::new("frame.invalid_alignment"),
            "alignment underflowed",
        )
    })?;

    value
        .checked_add(mask)
        .map(|sum| sum & !mask)
        .ok_or_else(|| {
            PixelFlowError::new(
                ErrorCategory::Core,
                ErrorCode::new("frame.allocation_overflow"),
                "aligned row size overflowed",
            )
        })
}

fn plane_index_error(index: usize) -> PixelFlowError {
    PixelFlowError::new(
        ErrorCategory::Core,
        ErrorCode::new("frame.plane_index"),
        format!("plane index {index} is out of range"),
    )
}

fn sample_mismatch_error(actual: SampleType, requested: SampleType) -> PixelFlowError {
    PixelFlowError::new(
        ErrorCategory::Format,
        ErrorCode::new("format.sample_type_mismatch"),
        format!(
            "plane sample type is {:?}, requested {:?}",
            actual, requested
        ),
    )
}

fn typed_row<T: Sample>(view: &PlaneView, row: usize) -> &[T] {
    let byte_offset = view.offset_bytes + row * view.stride_bytes;
    // SAFETY: offsets and strides are calculated from buffer bounds at build/view time; pointer
    // alignment is at least allocator alignment and storage sample type matches T in caller checks.
    unsafe {
        std::slice::from_raw_parts(
            view.storage.buffer.as_ptr().add(byte_offset).cast::<T>(),
            view.width,
        )
    }
}

fn typed_row_mut<T: Sample>(view: &mut PlaneView, row: usize) -> &mut [T] {
    let byte_offset = view.offset_bytes + row * view.stride_bytes;
    let buffer = Arc::get_mut(&mut view.storage.buffer)
        .expect("builder must uniquely own plane storage before finish");
    // SAFETY: mutable row access only exists on FrameBuilder where storage is uniquely owned.
    unsafe {
        std::slice::from_raw_parts_mut(buffer.as_mut_ptr().add(byte_offset).cast::<T>(), view.width)
    }
}

impl PlaneView {
    fn storage_mut_ptr(&mut self) -> *mut u8 {
        let buffer = Arc::get_mut(&mut self.storage.buffer)
            .expect("builder must uniquely own plane storage before finish");
        buffer.as_mut_ptr().wrapping_add(self.offset_bytes)
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        ErrorCategory, ErrorCode, MetadataKind, MetadataSchema, MetadataValue, SampleType,
        resolve_format_alias,
    };

    use super::{AllocatorConfig, Frame, FrameBuilder};

    #[test]
    fn frame_builder_allocates_aligned_plane_buffers() {
        let format = resolve_format_alias("gray8").expect("format should resolve");
        let schema = MetadataSchema::core();
        let mut builder = FrameBuilder::new(format, 4, 3, &schema, AllocatorConfig::default())
            .expect("builder should allocate");

        assert!(builder.actual_alignment() >= 64);
        let mut plane = builder.plane_mut::<u8>(0).expect("u8 plane should match");
        let raw = plane.raw_parts();

        assert_eq!(raw.width, 4);
        assert_eq!(raw.height, 3);
        assert_eq!(raw.sample_type, SampleType::U8);
        assert_eq!((raw.ptr as usize) % builder.actual_alignment(), 0);
    }

    #[test]
    fn builder_writes_rows_and_finish_returns_immutable_frame() {
        let format = resolve_format_alias("gray8").expect("format should resolve");
        let schema = MetadataSchema::core();
        let mut builder = FrameBuilder::new(format, 3, 2, &schema, AllocatorConfig::default())
            .expect("builder should allocate");

        {
            let mut plane = builder.plane_mut::<u8>(0).expect("u8 plane should match");
            plane
                .row_mut(0)
                .expect("row 0 should exist")
                .copy_from_slice(&[1, 2, 3]);
            plane
                .row_mut(1)
                .expect("row 1 should exist")
                .copy_from_slice(&[4, 5, 6]);
        }

        let frame = builder.finish();
        let plane = frame.plane::<u8>(0).expect("u8 plane should match");

        assert_eq!(plane.row(0).expect("row 0 should exist"), &[1, 2, 3]);
        assert_eq!(plane.row(1).expect("row 1 should exist"), &[4, 5, 6]);
        assert_eq!(
            frame.metadata().get("core:matrix"),
            Some(&MetadataValue::None)
        );
    }

    #[test]
    fn prop_only_clone_shares_plane_storage_but_replaces_metadata() {
        let format = resolve_format_alias("gray8").expect("format should resolve");
        let mut schema = MetadataSchema::core();
        schema
            .register_plugin_key("acme/filter:enabled", MetadataKind::Bool)
            .expect("plugin key should register");

        let mut builder = FrameBuilder::new(format, 2, 2, &schema, AllocatorConfig::default())
            .expect("builder should allocate");
        builder
            .plane_mut::<u8>(0)
            .expect("u8 plane should match")
            .row_mut(0)
            .expect("row should exist")
            .copy_from_slice(&[7, 8]);
        let frame = builder.finish();

        let mut metadata = frame.metadata().clone();
        metadata
            .set(&schema, "acme/filter:enabled", MetadataValue::Bool(true))
            .expect("metadata write should pass");

        let cloned = frame.with_metadata(metadata);

        assert!(frame.shares_plane_storage(&cloned, 0));
        assert_eq!(
            cloned.metadata().get("acme/filter:enabled"),
            Some(&MetadataValue::Bool(true))
        );
        assert_eq!(
            cloned.plane::<u8>(0).expect("u8 plane").row(0),
            Some(&[7, 8][..])
        );
    }

    #[test]
    fn crop_like_view_shares_storage_and_adjusts_visible_rows() {
        let format = resolve_format_alias("gray8").expect("format should resolve");
        let schema = MetadataSchema::core();
        let mut builder = FrameBuilder::new(format, 4, 4, &schema, AllocatorConfig::default())
            .expect("builder should allocate");

        {
            let mut plane = builder.plane_mut::<u8>(0).expect("u8 plane should match");
            plane
                .row_mut(0)
                .expect("row")
                .copy_from_slice(&[1, 2, 3, 4]);
            plane
                .row_mut(1)
                .expect("row")
                .copy_from_slice(&[5, 6, 7, 8]);
            plane
                .row_mut(2)
                .expect("row")
                .copy_from_slice(&[9, 10, 11, 12]);
            plane
                .row_mut(3)
                .expect("row")
                .copy_from_slice(&[13, 14, 15, 16]);
        }

        let frame = builder.finish();
        let cropped = frame
            .view(1, 1, 2, 2)
            .expect("crop-like view should succeed");

        assert!(frame.shares_plane_storage(&cropped, 0));
        assert_eq!(cropped.width(), 2);
        assert_eq!(cropped.height(), 2);

        let plane = cropped.plane::<u8>(0).expect("u8 plane should match");
        assert_eq!(plane.row(0), Some(&[6, 7][..]));
        assert_eq!(plane.row(1), Some(&[10, 11][..]));
    }

    #[test]
    fn frame_single_plane_view_shares_storage_and_preserves_metadata() {
        let source_format = resolve_format_alias("yuv420p8").expect("format should resolve");
        let gray_format = resolve_format_alias("gray8").expect("format should resolve");
        let schema = MetadataSchema::core();
        let mut builder =
            FrameBuilder::new(source_format, 4, 4, &schema, AllocatorConfig::default())
                .expect("builder should allocate");
        {
            let mut u = builder.plane_mut::<u8>(1).expect("u plane should match");
            let row = u.row_mut(0).expect("row should exist");
            *row.first_mut().expect("plane row should be non-empty") = 77;
        }
        let source = builder.finish();
        let mut metadata = source.metadata().clone();
        metadata
            .set(&schema, "core:frame_number", MetadataValue::Int(9))
            .expect("metadata should set");
        let source = source.with_metadata(metadata);

        let output = source
            .single_plane_view(1, gray_format)
            .expect("single plane view should build");

        assert_eq!(output.width(), 2);
        assert_eq!(output.height(), 2);
        assert_eq!(
            output.metadata().get("core:frame_number"),
            Some(&MetadataValue::Int(9))
        );
        assert!(source.shares_plane_storage_at(1, &output, 0));
        assert_eq!(
            output.plane::<u8>(0).expect("u8 plane").row(0),
            Some(&[77, 0][..])
        );
    }

    #[test]
    fn frame_from_plane_sources_combines_compatible_planes_without_copying() {
        let schema = MetadataSchema::core();
        let gray_format = resolve_format_alias("gray8").expect("format should resolve");
        let target_format = resolve_format_alias("yuv420p8").expect("format should resolve");
        let y = FrameBuilder::new(
            gray_format.clone(),
            4,
            4,
            &schema,
            AllocatorConfig::default(),
        )
        .expect("y builder should allocate")
        .finish();
        let u = FrameBuilder::new(
            gray_format.clone(),
            2,
            2,
            &schema,
            AllocatorConfig::default(),
        )
        .expect("u builder should allocate")
        .finish();
        let v = FrameBuilder::new(gray_format, 2, 2, &schema, AllocatorConfig::default())
            .expect("v builder should allocate")
            .finish();

        let output = Frame::from_plane_sources(
            target_format,
            4,
            4,
            &[(&y, 0), (&u, 0), (&v, 0)],
            y.metadata().clone(),
        )
        .expect("compatible planes should compose");

        assert_eq!(output.width(), 4);
        assert_eq!(output.height(), 4);
        assert!(y.shares_plane_storage_at(0, &output, 0));
        assert!(u.shares_plane_storage_at(0, &output, 1));
        assert!(v.shares_plane_storage_at(0, &output, 2));
    }

    #[test]
    fn frame_from_plane_sources_rejects_incompatible_shape_and_sample_type() {
        let schema = MetadataSchema::core();
        let gray8 = resolve_format_alias("gray8").expect("format should resolve");
        let gray10 = resolve_format_alias("gray10").expect("format should resolve");
        let target = resolve_format_alias("yuv420p8").expect("format should resolve");
        let y = FrameBuilder::new(gray8.clone(), 4, 4, &schema, AllocatorConfig::default())
            .expect("builder should allocate")
            .finish();
        let wrong_shape = FrameBuilder::new(gray8, 3, 2, &schema, AllocatorConfig::default())
            .expect("builder should allocate")
            .finish();
        let wrong_sample = FrameBuilder::new(gray10, 2, 2, &schema, AllocatorConfig::default())
            .expect("builder should allocate")
            .finish();

        let Err(shape_error) = Frame::from_plane_sources(
            target.clone(),
            4,
            4,
            &[(&y, 0), (&wrong_shape, 0), (&wrong_shape, 0)],
            y.metadata().clone(),
        ) else {
            panic!("wrong chroma shape should fail");
        };
        assert_eq!(shape_error.category(), ErrorCategory::Core);
        assert_eq!(
            shape_error.code(),
            ErrorCode::new("frame.plane_shape_mismatch")
        );

        let Err(sample_error) = Frame::from_plane_sources(
            target,
            4,
            4,
            &[(&y, 0), (&wrong_sample, 0), (&wrong_sample, 0)],
            y.metadata().clone(),
        ) else {
            panic!("wrong sample type should fail");
        };
        assert_eq!(sample_error.category(), ErrorCategory::Format);
        assert_eq!(
            sample_error.code(),
            ErrorCode::new("format.sample_type_mismatch")
        );
    }

    #[test]
    fn typed_plane_mismatch_returns_error_not_panic() {
        let format = resolve_format_alias("gray10").expect("format should resolve");
        let schema = MetadataSchema::core();
        let frame = FrameBuilder::new(format, 2, 2, &schema, AllocatorConfig::default())
            .expect("builder should allocate")
            .finish();

        let error = frame
            .plane::<u8>(0)
            .expect_err("wrong typed access should fail");

        assert_eq!(error.category(), ErrorCategory::Format);
        assert_eq!(error.code(), ErrorCode::new("format.sample_type_mismatch"));
    }

    #[test]
    fn unsafe_raw_plane_access_exposes_pointer_stride_and_contract_shape() {
        let format = resolve_format_alias("gray8").expect("format should resolve");
        let schema = MetadataSchema::core();
        let frame = FrameBuilder::new(format, 5, 2, &schema, AllocatorConfig::default())
            .expect("builder should allocate")
            .finish();

        // SAFETY: test inspects metadata only and does not dereference raw pointer.
        let raw = unsafe { frame.raw_plane(0) }.expect("raw plane should exist");

        assert!(!raw.ptr.is_null());
        assert!(raw.stride_bytes >= 5);
        assert_eq!(raw.width, 5);
        assert_eq!(raw.height, 2);
        assert_eq!(raw.sample_type, SampleType::U8);
    }

    #[test]
    fn typed_plane_rows_iterate_visible_slices() {
        let format = resolve_format_alias("gray8").expect("format should resolve");
        let schema = MetadataSchema::core();
        let mut builder = FrameBuilder::new(format, 2, 2, &schema, AllocatorConfig::default())
            .expect("builder should allocate");

        {
            let mut plane = builder.plane_mut::<u8>(0).expect("u8 plane should match");
            plane.row_mut(0).expect("row").copy_from_slice(&[1, 2]);
            plane.row_mut(1).expect("row").copy_from_slice(&[3, 4]);
        }

        let frame = builder.finish();
        let plane = frame.plane::<u8>(0).expect("u8 plane should match");
        let rows: Vec<&[u8]> = plane.rows().collect();

        assert_eq!(rows, vec![&[1, 2][..], &[3, 4][..]]);
    }
}
