use crate::Alignment;
use crate::TruncationPolicy;

/// A field definition for a fixed-width writer.
///
/// Each field describes a column in the output: its width, padding byte,
/// alignment, and optional per-field truncation policy.
///
/// Constructed via [`FwWriterFieldBuilder`].
#[derive(Debug, Clone)]
pub struct FwWriterField {
    width: usize,
    padding: u8,
    alignment: Alignment,
    truncation: Option<TruncationPolicy>,
}

impl FwWriterField {
    /// Creates a new [`FwWriterFieldBuilder`] with the given width.
    #[inline]
    #[must_use]
    pub fn builder(width: usize) -> FwWriterFieldBuilder {
        FwWriterFieldBuilder::new(width)
    }

    /// Returns the width of this field in bytes.
    #[must_use]
    #[inline]
    pub fn width(&self) -> usize {
        self.width
    }

    /// Returns the padding byte used for this field.
    #[must_use]
    #[inline]
    pub fn padding(&self) -> u8 {
        self.padding
    }

    /// Returns the alignment of the value within this field.
    #[must_use]
    #[inline]
    pub fn alignment(&self) -> Alignment {
        self.alignment
    }

    /// Returns the per-field truncation policy override, if any.
    #[must_use]
    #[inline]
    pub fn truncation(&self) -> Option<TruncationPolicy> {
        self.truncation
    }
}

/// Builder for constructing a [`FwWriterField`].
#[derive(Debug)]
pub struct FwWriterFieldBuilder {
    width: usize,
    padding: u8,
    alignment: Alignment,
    truncation: Option<TruncationPolicy>,
}

impl FwWriterFieldBuilder {
    #[must_use]
    fn new(width: usize) -> Self {
        Self {
            width,
            padding: b' ',
            alignment: Alignment::default(),
            truncation: None,
        }
    }

    /// Sets the padding byte. Defaults to `b' '` (space).
    #[must_use]
    #[inline]
    pub fn padding(mut self, padding: u8) -> Self {
        self.padding = padding;
        self
    }

    /// Sets the field alignment. Defaults to [`Alignment::Left`].
    #[must_use]
    #[inline]
    pub fn alignment(mut self, alignment: Alignment) -> Self {
        self.alignment = alignment;
        self
    }

    /// Sets a per-field truncation policy override. Defaults to `None` (use global).
    #[must_use]
    #[inline]
    pub fn truncation(mut self, truncation: TruncationPolicy) -> Self {
        self.truncation = Some(truncation);
        self
    }

    /// Builds the [`FwWriterField`].
    #[must_use]
    #[inline]
    pub fn build(self) -> FwWriterField {
        FwWriterField {
            width: self.width,
            padding: self.padding,
            alignment: self.alignment,
            truncation: self.truncation,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn builder_defaults() {
        let field = FwWriterField::builder(10).build();
        assert_eq!(field.width(), 10);
        assert_eq!(field.padding(), b' ');
        assert_eq!(field.alignment(), Alignment::Left);
        assert_eq!(field.truncation(), None);
    }

    #[test]
    fn builder_all_custom() {
        let field = FwWriterField::builder(8)
            .padding(b'*')
            .alignment(Alignment::Right)
            .truncation(TruncationPolicy::Right)
            .build();
        assert_eq!(field.width(), 8);
        assert_eq!(field.padding(), b'*');
        assert_eq!(field.alignment(), Alignment::Right);
        assert_eq!(field.truncation(), Some(TruncationPolicy::Right));
    }
}
